Pressure transducer code

How to interpret pressure transducer signals:

  • Calibration is key (temperature and atmosphere). If you're going to use the sensor for fluid level detection, leave the sensor in a bucket of water to bring it down to a normalized temperature before sampling your zero pressure reading.

  • The readings from transducers fluctuate. Using a circular filtering buffer is a most accurate way, but
    if memory is limited, use a high low median approach or both (smaller buffer). i.e. if reading is > p-high (store), if reading is lower than p-low (store), then divide by 2. Do this in some interval like every 250ms, then feed these results into a small circular buffer (like 20 samples), then perform median calculation. This also works well with ammeters and AC voltage detection. My example only uses a circular buffer of 200 samples but produces amazingly accurate and consistent results.

  • Size the transducer as small as possible for highest resolution, though 12-bit ADCs will be accurate even if massively oversized. For example, a 174Psi transducer on an Arduino Due has 2cm resolution when measuring water head (up to 80 meters); whereas an Uno has only 12cm of resolution (up to 122 meters depth). A 100psi transducer on a Due is accurate to 1.3cm or about 7.4cm on an Uno.

  • As far as I know, pressure transducers are the most accurate and reliable way of measuring fluid level in a well or tank of any depth. I cut around the base of the female connector of the transducer (to expose the pins better) and solder 23AWG direct burial Ethernet cable directly to the pins, bend the pins away from eachother for easier soldering. Then encase the connections in contact cement like "Amazing Goop" or silicone. This will never leak if you do it right and its good in a well over 150ft deep. The supplied connector is not even drip proof despite the seal, its complete rubbish and it has a flaky connection %80 of the time. I've thrown away perfectly good transducers by accident. Don't reverse the polarity or it's toast. The single vertical is the analog output and the two lower horizontal pins are positive 5v (left) and ground (right), confirm this by testing the connector before you solder.

  • If there is long distance between the Arduino and the transducer, make sure to use multiple conductors of the Ethernet cable but make sure that the ground wires(s) and signal return wire(s) are twisted together (to cut down on EMI). Use Green and Blue for ground and Green Strip and Blue Stripe for signal, blue/green pairs have more twists per foot and therefore are more resistant to EMI. If your motors have VFDs then you may need shielded/loomed cable.

  • Normally I use a Due or Arduino Zero - I apply 5v to the transducer. Since limited to 3.3v, the transducer will only be good for %66 of its pressure rating (to prevent over-voltage). Normally this is not an issue, just de-rate by %33 accordingly. So a 100psi transducer will have 1.34cm accuracy up to 46 meters in water or handle up to 66psi with .02psi accuracy.

Use this example to determine transducer resolution and max depth. The lower the pressure rating of transducer, the more accurate it will be.

short pressZero = 112;        //put the highest raw reading you see here at atmospheric pressure
short pressMax = 30;         //reduce pressure rating by %66 if 3.3v logic but still use 5v input
float resolution = 921.6;      //3686.4 for Due/Zero and add analogReadResolution(12) to void setup
byte analogPin = 0;           //transducer pin number
boolean autoCalibrate = true; //will automatically select highest raw reading in 10sec period

///////////////////////////////////////////////////////////////////////////////////////////////////////
byte pressStep;
short rawRead[201];
unsigned long timer;
byte calibrate;
boolean autoCalibrateComplete = false;
short pressZeroTemp;
String buf;

void setup()
{
  buf.reserve(40);
  Serial.begin(115200);
  transProp();
  delay(6000);
}

void loop()
{
  if (millis() - timer >= 1000)
  {
    float pressPsi;
    unsigned long rawTemp = 0;
    short raw;
    for (byte x = 0; x < 200; x++) rawTemp += rawRead[x];
    raw = rawTemp / 200;
    unsigned short calc1 = raw - pressZero;
    unsigned long calc2 = calc1 * pressMax;
    float calc3 = resolution - float(pressZero);
    if (raw <= pressZero) pressPsi = 0.0;
    else pressPsi = float(calc2) / float(calc3);
    float pressMeter = pressPsi * .7030695782; // psi to meters of water head
    buf = F("Raw: ");
    buf += raw;
    buf += F(" psi: ");
    buf += pressPsi;
    buf += F(" meters: ");
    buf += pressMeter;
    Serial.println(buf);
    if (autoCalibrate == true && calibrate >= 10)
    {
      if (autoCalibrateComplete == false)
      {
        pressZero = pressZeroTemp;
        buf = F("\n\nsensor re-calibrated to : ");
        buf += pressZero;
        buf += F(" (raw)\n");
        Serial.println(buf);
        transProp();
        delay(6000);
        autoCalibrateComplete = true;
      }
    }
    else
    {
      if (raw > pressZeroTemp) pressZeroTemp = raw;
      calibrate++;
    }
    timer = millis();
  }
  if (pressStep < 200) pressStep++;
  else pressStep = 0;
  rawRead[pressStep] = analogRead(analogPin);
}

void transProp() {
  buf = (F("max depth: "));
  float tDepth = pressMax;
  buf += (round(tDepth * .7030695782));
  buf += (F(" meters\n"));
  buf += (F("max resolution: "));
  float tRes = (tDepth / (resolution - float(pressZero)));
  buf += (tRes * 70.30695782);
  buf += (F("cm  or  "));
  buf += (tRes);
  buf += (F(" psi\n\n"));
  Serial.println(buf);
}