Pressure Transducer Calibration

This is my first attempt at logging pressure. I bought a 3-wire "100 PSI" pressure transducer from Amazon. I think it's actually a 0.5Mpa transducer because I'm using a >>highly accurate<< :rofl: :rofl: :rofl: bicycle pump to test it and an external gauge from an old air compressor. I trust the air compressor gauge far more than the bicycle pump gauge. I never threw the air compressor in the back of my truck. It matters not, 0.5Mpa will work just fine for my purposes. There's a blow off valve set at 75 PSI so it should never see 0.5Mpa and typical operating range is 30-something to mid-50s PSI.
I digress. When the transducer is at ambient pressure, it returns a value between 163 and 168 instead of the expected low 100s. I'm guessing it's easier to adjust the calculation to work on a scale from 165-??? than it is to write a calibration adjustment, but I want to keep this intuitive for future changes without having to spend so much time to calibrate my code.

What is a better way to do this that still puts a variable in the calculation to adjust both the zero and still have full sweep of the range?

Note: there's values in comments that I used when I thought I had a 0-100PSI transducer.

int transducer_signal;
long last_output;
float scale = 0.5; //72PSI 0.689; //100PSI //the maximum resolution on the transducer in Mpa. Mine is 100PSI or 0.689
float calibration_offset = -0.0403; //-0.0535; //inverse of whatever the transducer reads at ambient pressure. This one reads 0.05 (guessing on the 0.055 part) at ambient pressure
float calibration_magnifyer = 1; //0.51; //if transducer is perfectly accurate, this is 1; If it reads high, it's less than 1; Reads low, more than 1; Never zero!

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  long now = millis()/1000;
  transducer_signal = analogRead(A0);
  if(now % 5 == 0 && last_output != now){
    Serial.print("input: ");
    Serial.println(transducer_signal);
    float outputMpa = (((transducer_signal - 102) * scale / 819) + calibration_offset) * calibration_magnifyer; //math works like this: minimum is 0.5V max is 4.5V. So you must subtract 10% off each end of the meter. 102=1024/10, 819=1024-102 "scale" is what ever the full resolution of the transducer is.
    Serial.print("calculated value: ");
    Serial.print(outputMpa);
    Serial.print(" Mpa, ");
    Serial.print(outputMpa * 1000);
    Serial.print(" pa, PSI: ");
    Serial.println(outputMpa * 145);
    last_output = now;
  }
}

Last, the reason I think I have a 0.5Mpa transducer is I got this output a few times when pumping it up. The "input" is the raw value from the Arduino.
input: 1024
calculated value: 0.52 Mpa, 522.58 pa, PSI: 75.77

I'm a big guy. I like to pick stuff up and put stuff down. It really didn't feel like I was pumping 100PSI through a bicycle pump which 1024 on a 100PSI transducer should be well above 100PSI.

Please post a link to the sensor, and a wiring diagram.

Wiring knock-off Wemos D1:
5V - red wire
GND- black wire
A0 - green wire

Best attempt at a data sheet on the transducer: https://www.dataq.com/resources/pdfs/datasheets/pressure-sensor-ds.pdf
While it doesn't say the same company name, the fonts, colors and general feel of the PDF tells me this is the company somebody in China ripped off to make the sensor I bought.
Again, this is the 100PSI version. I think mine is mis-marked, it doesn't matter if I can make it easy to adjust in the future.

The best way I've found to troubleshoot is such a situation is to print out the raw counts.

  1. Test with the analog input grounded (s/b 0) . And at Vcc (s/b 1023)
  2. With the transducer at ambient pressure watch the counts for a few minutes (or more) is it stable? Most pressure transducers are more likely to drift at 0 pressure that have changes in gain.

So plug the red wire into the power supply?

Just letting it alone the monitor shows very little variation. Something like 163, 165 (for a while) with a 168 thrown in just to make me scratch my head. But it sticks really close to 165. This is within the tolerance show in the specs.

I think the transducer is fine other than being mis-marked.

Connect the sensor red wire to the Arduino 5V pin, the black wire to GND and blue to A0.

Keep in mind that the transducer outputs 0.5V for 0 PSI relative pressure (this is a gauge, not absolute pressure sensor), which is an ADC reading of about 102. Full scale (4.5V) is about 920.

That is how I have it connected to the Arduino. Except it's a green wire, not blue. 0PSI returns 165-ish. Hence the need to calibrate it. I've pumped it up to 1024 once or twice by mistake. But I thought it was a 100PSI, not a 72 PSI transducer when I did it.

This may be a pain to do but.... my local costco has what appears to be a very accurate tire pressure control. Could you gin up a pressure sensor to tire stem adapter?

Or if you have a spare tire. Verify that at costco or other reliable air filling station. Then check it when you get home with your sensor. You should be able to find a tire fill head in the compressor section of Home Depot.

I suggest spare tire because the tires on the vehicle change temperature when you drive.

Then that is one calibration point. Replace the "102" in the code you posted with 165.

If you use PSI units, apply X PSI to the sensor and record the raw ADC reading (Xadc).

Replace the term "scale/819" with ((float)X) / (Xadc-165) and remove the last two terms.

The new line looks like this:

    if (transducer_signal > 165) float outputPSI = (transducer_signal - 165) * ((float) X)/(Xadc-165);

Great tutorial and overview on sensor calibration: Why Calibrate? | Calibrating Sensors | Adafruit Learning System

That's not a bad idea. I could certainly take the PC and my test rig to a tire filling station, inflate it to near the limit of 0.5Mpa and see what the reading is.
It only takes one fast pump to get to 1024 or two slower ones. I intentionally didn't use teflon tape on one side so it leaks since there needs to be variation and I don't want to continuously bleed the shrader valve.

Would

 if (transducer_signal > 102  + calibration_offset) float outputPSI = (transducer_signal - (102 + calibration_offset)) * ((float) X)/(Xadc-(102 + calibration_offset));

Serve the same purpose, where calibration_offset = +63? I'm trying to make it easy when I get the properly functioning transducer (if I ever get one ).

If that seems easier to you, great!

If you have a Nano and power from USB, AREF will be around 4.7V NOT 5V. May not matter, but...

If you have a "small" spare I believe they require a much higher pressure than a standard tire.

Or if you have a bicycle you could take the front tire which also requires a higher pressure that your vehicle tire (assuming its not a commercial vehicle).

Easier initially, no. Easier than looking for a literal in my code and remembering I need to adjust that literal in three different places after I've forgotten how the code works? Yes.

Thanks all.

My approach would be to declare and define three variables, right up at the top of the code, like the following. Then there is no need for anyone to guess or delve deeply into the code, later on.

int zero_pressure_adc_offset = (Zero_adc_value); //example 165
float calibration_pressure = X; //psi, example 100
int calibration_pressure_adc_value = X_adc; //example 888

This is the working copy. I'm fairly satisfied with the results, again, assuming that I have a mis-marked transducer that's actually 0.5Mpa. But strangely enough the ceiling seems lower than 72psi, around 62psi is where I get a maximum reading. The only way I can really confirm would be to find another trustworthy transducer and run the numbers at the lowest maximum pressure among the two at varying pressures, record the voltages and do the math. It was $18, I'm not expecting NASA accuracy.

float scale = 5.0; //72PSI the maximum resolution on the transducer, currently in BAR.
float calibration_offset = 66; //whatever the transducer reads at ambient pressure less 102(.4) because it is supposed to be 0.5V at 0psi
float calibration_gain = 0.85; //if transducer is perfectly accurate, this is 1; If it reads high, it's less than 1; Reads low, more than 1; Never zero!

//these lines are run in a function or loop()...
int transducer_signal = analogRead(A0);
float current_pressure = (((transducer_signal - (102 + calibration_offset)) * scale / 819)) * calibration_gain; //math works like this: minimum is 0.5V max is 4.5V. So you must subtract 10% off each end of the meter. 102=1024/10, 819=1024-102-102; "scale" is what ever the full resolution of the transducer is.

Bonus: you can see I've switched from Mpa to Bar, but it's still the same formula because the scale is what actually matters. I think, without running the numbers, you could use PSI as the scale and as long as the calibration offset is in 0-1024 value from Arduino, it won't make a difference.

It's accurate according to two independent air pressure tank gauges (I've now broken the bicycle pump and am using compressed air with a regulator) with respect to the 2% fluctuation as noted in the Amazon.com ad.

For anyone reading who may find this useful, my theory is first, set the zero. It was "off" by 66 out of 1024 or 0.04Mpa or 5.8 psi at ambient pressure. That's 8%. "Typical Chinese Quality, Am I Right?"
Now that it's zeroed by subtracting the ambient reading, it's not really that great across the board either, so the maximum reading was showing about 15% higher than any other gauge. Hence the 0.85 gain. (thank you to JohnRob for refreshing my memory on terminology) Whatever result after adjusting the zero setting is multiplied by 0.85 in order to produce the most accurate result.

This isn't perfect, but I'm not a rocket scientist and I'm working with recording a well pump pressure over time to determine if I really need to replace a well pump or not. The $50 I spent to put this rig together could save me $4,000 or confirm I really do need to spend the $4,000.

It reports to a server and via PHP inserts data into a MySQL table. (yeah, I have been out of web development for a long time, kickin' it old school!) It could have been PERL...

If I needed 100% precision with high accuracy, I could have spent $700 on a 99.9999% accurate transducer. And probably hooked it up backwards and let out the magic smoke.

When it's all said and done, I've got a neat little IoT pressure meter that monitors not only pressure, but time the pump runs too.

I will add a "zero = off" line, so if future me decides to monkey with the code and sticks a zero in the gain, it multiplies by one since zero will mean the pressure is always zero on every scale.
I probably could have found the true scale on this one for the same amount of work using a voltmeter and a quality tire pressure gauge, but I'd still need to account for zeroing the result at ambient pressure.

I think I learned something in the process too. That alone is worth $50.

UPDATE: So don't tell my ex-wife this, but I am an idiot.
It's a 5V sensor, but that doesn't mean I should be plugging it into the 5V slot on the Arduino.
I realized this when I transferred the project to a WeMos D1 mini that the D1 R2 is also a 3.3V Analog.
Because I was pumping in 5V, my maximum reading would be 3.3/5 or 66 PSI. If you remember, it seemed like it was peaking at 62PSI using the 0-200 air compressor gauges.

Once on the 3.3V input to the red wire, I now could get readings of 103 (should be 102 per documentation) and after zeroing it maxed out near 95PSI. It never does quite make it to 100 PSI, the output never goes to 1024, but high 900s are possible.
The scale is now 6.98 (BAR) instead of 0.5 (Mpa) or 5 (BAR) - no need to adjust the equations in the code.
When it was all said and done, I settled on a -4.6% gain (multiplying by .954) in order to have reasonably accurate readings in the pressure range I was looking for.
The ad says 2% accuracy, but I think it's probably 3-4% based on some anomalies I've noticed that I can't attribute to things like the water heater expanding water and thus increasing pressure or that same water cooling down over time. Again, you get what you pay for.
I have it recording changes greater than 5% so it's not sending updates a few times per second during water use.

And now that I've built this toy, it's happily monitoring the water pressure and reporting it to a MySQL db.
I've ruled out some sort of restriction in my house plumbing and I am going to replace the mechanical switch that turns the well pump on. It triggers on as low as 14PSI and as high as 28PSI, so it's clearly failing.
I could never catch it happening with the mechanical gauge that was in place before - even after replacing the gauge.
Hopefully, that's the end of my issue.
FWIW, I replaced the check valve several weeks ago again, hoping to solve my problem. I could easily confirm that was bad since I could blow through both ends after removing it. It was a copper body, so it probably was new when the house was new in 1961.

Next up will be a TFT display to show pressure in PSI and change the background to blue if the pump is on, green for WiFi communication and red for errors. The LED blinking patterns I programmed in are OK, but not great. Solid for on, very slow short blinks for off vs. medium cadence short blinks for communiation vs. slightly faster long blinks for errors just aren't as intuitive as I thought they'd be.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.