How a 4-20mA Pressure Sensor Transducer Works

The core sensing element inside an industrial pressure sensor transducer is typically a piezoresistive Wheatstone bridge etched into a stainless steel diaphragm. As fluid or gas pressure deflects the diaphragm, the strain gauges stretch or compress, changing their electrical resistance and creating a millivolt-level differential signal proportional to the applied force.

Unlike a raw sensor that outputs a fragile millivolt signal, a transducer includes onboard signal conditioning. It amplifies the bridge output, applies temperature compensation, and drives a constant current loop (4-20mA). At 0 PSI, it outputs 4mA (a "live zero" that allows your controller to detect a broken wire, which would read 0mA); at full scale (e.g., 100 PSI), it outputs 20mA. This current-based output makes the signal highly immune to voltage drop over long cable runs, which is why it remains the undisputed standard in industrial automation.

Wiring the Transducer to an ESP32

The ESP32 cannot read current directly, and its 3.3V logic cannot interface with the 12-24V typically required to power the transducer. We must convert the current to a voltage using a precision shunt resistor. Crucial bench note: Many tutorials recommend a 250-ohm shunt, which yields 1-5V. That 5V maximum will fry the ESP32's internal ADC and exceed the default range of a 3.3V-powered ADS1115. We use a 150-ohm shunt to safely map the 4-20mA loop to a 0.6V - 3.0V window.

Component Pin/Terminal Connects To Notes & Supply Range
Pressure Transducer Brown (V+) 24VDC PSU (+) Transducer supply range: 10-30VDC
Pressure Transducer Black (Signal) 150Ω Shunt (Side A) Outputs 4-20mA current
150Ω Shunt (0.1%) Side B GND (PSU & ESP32) Creates 0.6V to 3.0V drop
150Ω Shunt (Side A) ADS1115 A0 Analog Input 150Ω yields max 3.0V at 20mA
ADS1115 Breakout VDD ESP32 3V3 Power for external ADC
ADS1115 Breakout GND ESP32 GND Common ground required
ADS1115 Breakout SDA / SCL ESP32 GPIO 21 / 22 I2C Bus (add 4.7k pull-ups if needed)
Safety & Grounding Callout: The 24VDC power supply ground must be tied to the ESP32 ground at the shunt resistor. If you are measuring pressure in a conductive metal pipe system powered by a different AC mains circuit, you risk a ground loop. In those cases, insert a galvanic isolator (like the ISO124) between the shunt and the ADC.

The Math: Converting Raw ADC Reads to PSI

The output of this sensor transducer is strictly a current source. The voltage only exists because we forced the current through our 150-ohm shunt. To get a physical unit (PSI), we must reverse this chain: Raw ADC Bits → Voltage → Current (mA) → Pressure (PSI).

Assuming a 100 PSI full-scale transducer and an ADS1115 configured with a ±4.096V Programmable Gain Amplifier (PGA):

  • ADS1115 Resolution: 16-bit signed (0 to 32767 for positive reads). 1 LSB = 4.096V / 32768 = 0.125 mV (0.000125 V).
  • Raw to Voltage: Voltage = raw_adc * 0.000125
  • Voltage to Current: Current_mA = (Voltage / 150.0) * 1000
  • Current to PSI: The span is 16mA (20mA - 4mA). PSI = ((Current_mA - 4.0) / 16.0) * 100.0

Here is the complete, copy-pasteable C++ implementation using the Adafruit_ADS1X15 library:

#include <Wire.h>
#include <Adafruit_ADS1X15.h>

Adafruit_ADS1115 ads;

// Constants for a 100 PSI transducer with a 150-ohm shunt
const float SHUNT_OHMS = 150.0;
const float ADC_LSB_VOLTS = 0.000125; // For PGA = ±4.096V
const float ZERO_OFFSET_MA = 4.0;
const float SPAN_MA = 16.0;
const float FULL_SCALE_PSI = 100.0;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22); // ESP32 default I2C pins
  
  if (!ads.begin(0x48)) {
    Serial.println("Failed to initialize ADS1115. Check wiring.");
    while (1);
  }
  ads.setGain(GAIN_ONE); // ±4.096V range (1 LSB = 0.125mV)
}

void loop() {
  int16_t raw_adc = ads.readADC_SingleEnded(0);
  
  if (raw_adc < 0) raw_adc = 0; // Prevent negative wrap-around
  
  float voltage = raw_adc * ADC_LSB_VOLTS;
  float current_ma = (voltage / SHUNT_OHMS) * 1000.0;
  
  float psi = 0;
  if (current_ma >= ZERO_OFFSET_MA) {
    psi = ((current_ma - ZERO_OFFSET_MA) / SPAN_MA) * FULL_SCALE_PSI;
  }
  
  Serial.printf("Raw: %d | V: %.3f | mA: %.2f | PSI: %.2f\n", raw_adc, voltage, current_ma, psi);
  delay(250);
}

Calibration, Scaling, and Interference

Even with a 0.1% tolerance shunt resistor, your raw readings will likely be off by 1-3% out of the box. You must perform a two-point calibration.

  1. Zero Trim: Cap the pressure port so it reads atmospheric pressure (0 PSI gauge). Record the current_ma value. If it reads 4.12mA instead of 4.00mA, subtract 0.12 from your ZERO_OFFSET_MA constant in code.
  2. Span Trim: Apply a known, trusted pressure (e.g., 50 PSI from a calibrated hand pump). Record the calculated PSI. If it reads 48.5 PSI, your scaling factor is slightly off. Multiply your FULL_SCALE_PSI constant by (50 / 48.5) to correct the slope.

Common Interference Sources

While 4-20mA loops are robust, they are not magic. The most common interference source in embedded setups is Variable Frequency Drives (VFDs) on nearby pump motors. VFDs generate massive high-frequency common-mode noise. If your transducer cable runs parallel to VFD motor leads, the noise will capacitively couple into your loop. Fix: Use shielded twisted pair (STP) cable for the transducer, and ground the drain wire at the PSU end only to prevent ground loops. Additionally, switching noise from the ESP32's internal DC-DC converter can inject ripple into the 3.3V rail, which powers the ADS1115. Place a 10µF tantalum and a 0.1µF ceramic capacitor directly across the ADS1115 VDD and GND pins to filter this out.

Decision Tree: Choosing Your ADC Interface

When architecting your data acquisition chain for a sensor transducer, you have a few paths. Use this decision matrix to select your hardware:

If your constraint is... Then choose... Why?
Budget is strictly < $3 and > 5% error is acceptable ESP32 Internal ADC + 150Ω Shunt Free, but the ESP32 ADC is notoriously non-linear and noisy near 0V and 3.3V.
You need to read 4+ transducers simultaneously Adafruit 4-20mA Current Loop Receiver (ADA3486) Handles the shunt and op-amp buffering on-board, but costs ~$15 per channel.
You need < 0.5% accuracy and high stability ADS1115 16-bit External ADC Excellent PGA, stable voltage reference, and standard I2C interface.

The Default Pick: Buy the ADS1115 breakout board (Texas Instruments ADS1115). It costs roughly $4 to $8 depending on the supplier. It entirely eliminates the headache of the ESP32's internal ADC non-linearity (documented in detail in the Espressif ADC calibration guidelines), and its 16-bit resolution gives you over 24,000 discrete steps across your 0.6V to 3.0V window. That translates to a theoretical resolution of 0.004 PSI on a 100 PSI transducer, which is more than enough to absorb mechanical noise and provide rock-solid industrial readings in a DIY or prototyping environment.