MS4525DO pressure sensor sensitivity issue

Hey there,

I am trying to measure air speed with this differential pressure sensor connected to a pitot tube: http://www.holybro.com/product/digital-air-speed-sensor/
And here is the datasheet of the sensor: http://www.holybro.com/manual/Air_Speed_Sensor_Datasheet_MS4525DO.pdf

The sensor communicates over i2c and I receive data, but have an issue with the sensitivity. The sensor only sends output data in steps of seven, so I get data like 8094, 8101, 8108. I suspected the problem was due to too short time between sensor polling and reading, but couldn't fix it with a delay after requesting data.

I think the calculation is not quite right, but the issue is also in the raw data, so first I need to get it right there.

Did somebody have the same issue and knows what to do?

#include <Wire.h>   //I2C library 0x28H 
#include <stdint.h> //Standard C, allows explicit data type decleration.

byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type

//MS4525D sensor characteristic
const uint8_t MS4525DAddress = 0x28;
const int16_t MS4525FullScaleRange = 1; //1 psi
//const int16_t MS4525MinScaleCounts = 1638;
//const int16_t MS4525FullScaleCounts = 14746;
const int16_t MS4525MinScaleCounts = 1617;  //Voff
const int16_t MS4525FullScaleCounts = 14569.2;  //Vfso
const int16_t MS4525Span = MS4525FullScaleCounts - MS4525MinScaleCounts;  //span
const int16_t MS4525ZeroCounts = (MS4525MinScaleCounts + MS4525FullScaleCounts)/2;  //?

byte _status; // A two bit field indicating the status of the I2C read
uint16_t P_dat, T_dat; // 14 bit pressure data and 11 bit temperature data
float psi, Vms, Vkmh, psioff;

byte fetch_pressure(uint16_t &P_dat, uint16_t &T_dat)
{
  byte _status, Press_H, Press_L, Temp_H, Temp_L;
  Wire.beginTransmission(MS4525DAddress);  
  // Wire.endTransmission();      // Stop transmitting
  delay(100);
  Wire.requestFrom(MS4525DAddress, static_cast<uint8_t>(4), static_cast<uint8_t>(false)); // Request 4 bytes, 2 pressure/status and 2 temprature.
  delay(100);
  Press_H = Wire.read();
  Press_L = Wire.read();
  Temp_H = Wire.read();
  Temp_L = Wire.read();
  Wire.endTransmission();

  _status = (Press_H >> 6) & 0x03;
  Press_H = Press_H & 0x3f;
  P_dat = (((uint16_t)Press_H) << 8 ) | Press_L;

  Temp_L = (Temp_L >> 5);
  T_dat = (((uint16_t)Temp_H) << 3) | Temp_L;

  return _status;
}

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  while(! Serial)
  {
    delay(1);
  }
  Serial.println("MS4525D0 test");
  _status = fetch_pressure(P_dat,T_dat);
  Serial.print("P_raw Offset: ");
  Serial.print(P_dat);
  psioff = abs((static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange));
  Serial.print("\t");
  Serial.print("Psi Offset: ");
  Serial.println(psioff,6);
}

void loop()
{
  _status = fetch_pressure(P_dat,T_dat);
  switch (_status)
  {
    case 0: //Serial.println("Ok ");
     break;
    case 1: Serial.println("Busy");
      break;
    case 2: Serial.println("Slate");
      break;
    default: Serial.println("Error");
      break;
  }

//Berechnung Druck
  psi =(static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange)-psioff;
  psi = abs(psi);

//Berechnung Geschwindigkeit
  Vms = sqrt((psi*13789.5144)/1.225);
  Vkmh = Vms*3.6;
     
//Ausgabe im seriellen Monitor
  Serial.print("psioff: ");Serial.print(psioff,6);
  Serial.print(" , ");
  Serial.print("raw Pressure: ");Serial.print(P_dat);
  Serial.print(" , ");
  Serial.print("pressure psi: ");Serial.print(psi,6);
  Serial.print(" , ");
  Serial.print("speed m/s: ");Serial.print(Vms,2);
  Serial.print(" , ");
  Serial.print("speed km/h: ");Serial.println(Vkmh,2);
  
  delay(1000);
}


Hi, @onrcnoz
Welcome to the forum.
Thanks for using code tags on your program. :+1:

What units are those figures supposed to be?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Hi Tom,

thanks for your fast response. The output of the sensor don't have units, but one number unit has to be equal to 0.84 Pascal or 0.000122 psi. The sensor has a 14 bit output for a range from -1 psi to 1 psi. We have 8192 units for 0 to 1 psi, so 1 unit equals 0.000122 psi. At the moment I get output data which counts in numbers of 7. The sensitivity is 0.00085 psi which is not enough for air speed measuring.

The transducer is not sensitive enough for your application .
You can expect to get sensible readings below 0.01 psi.
Work out your maximum pressure and pick a transducer with a range as near as possible to that .
The spec sheet gives accuracy as +- .25% of span , which is +- 0.0025 psi. Total error band is +- 0.01 psi - you are working down in the noise .

Pitot pressure =1/2* density * (velocity )^2

@onrcnoz I used your code for my course project (at the university). And I looked up help from my instructor and he figure out that the code it self has no issue, but it might caused by the initial pressure value being somehow wrong after upload the code to the board.
we modified the delay time for the loop, and press the reset button on the board.

Here is the modified code based on yours, but added some other component for my automatic flaps by airspeed project.

#include <Wire.h>   //I2C library 0x28H 
#include <stdint.h> //Standard C, allows explicit data type decleration.
#include <Servo.h>
#include <LiquidCrystal_I2C.h>


Servo myservo;  // create servo object to control a servo
int pos1 = 180;
int pos2 = 90;

LiquidCrystal_I2C lcd(0x27,20,4);

byte fetch_pressure(unsigned int *p_Pressure); //convert value to byte data type

//MS4525D sensor characteristic
const uint8_t MS4525DAddress = 0x28;
const int16_t MS4525FullScaleRange = 1; //1 psi
//const int16_t MS4525MinScaleCounts = 1638;
//const int16_t MS4525FullScaleCounts = 14746;
const int16_t MS4525MinScaleCounts = 1617;  //Voff
const int16_t MS4525FullScaleCounts = 14569.2;  //Vfso
const int16_t MS4525Span = MS4525FullScaleCounts - MS4525MinScaleCounts;  //span
const int16_t MS4525ZeroCounts = (MS4525MinScaleCounts + MS4525FullScaleCounts)/2;  //?

byte _status; // A two bit field indicating the status of the I2C read
uint16_t P_dat, T_dat; // 14 bit pressure data and 11 bit temperature data
float psi, Vms, Vkmh, psioff;

byte fetch_pressure(uint16_t &P_dat, uint16_t &T_dat)
{
  byte _status, Press_H, Press_L, Temp_H, Temp_L;
  Wire.beginTransmission(MS4525DAddress);  
  // Wire.endTransmission();      // Stop transmitting
  delay(100);
  Wire.requestFrom(MS4525DAddress, static_cast<uint8_t>(4), static_cast<uint8_t>(false)); // Request 4 bytes, 2 pressure/status and 2 temprature.
  delay(100);
  Press_H = Wire.read();
  Press_L = Wire.read();
  Temp_H = Wire.read();
  Temp_L = Wire.read();
  Wire.endTransmission();

  _status = (Press_H >> 6) & 0x03;
  Press_H = Press_H & 0x3f;
  P_dat = (((uint16_t)Press_H) << 8 ) | Press_L;

  Temp_L = (Temp_L >> 5);
  T_dat = (((uint16_t)Temp_H) << 3) | Temp_L;

  return _status;
}

void setup()
{myservo.attach(9);  // attaches the servo on pin 9 to the servo object

  lcd.init();                      // initialize the lcd 
  lcd.init();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Airspeed kph");

  Serial.begin(9600);
  Wire.begin();
  while(! Serial)
  {
    delay(1);
  }
  Serial.println("MS4525D0 test");
  _status = fetch_pressure(P_dat,T_dat); //flush any existing data
  delay(250);
  _status = fetch_pressure(P_dat,T_dat);
  Serial.print("P_raw Offset: ");
  Serial.print(P_dat);
  psioff = abs((static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange));
  Serial.print("\t");
  Serial.print("Psi Offset: ");
  Serial.println(psioff,6);
}

void loop()
{
  _status = fetch_pressure(P_dat,T_dat);
  switch (_status)
  {
    case 0: //Serial.println("Ok ");
     break;
    case 1: Serial.println("Busy");
      break;
    case 2: Serial.println("Stale");
      break;
    default: Serial.println("Error");
      break;
  }

//calculate pressure
  psi =(static_cast<float>(static_cast<int16_t>(P_dat)-MS4525ZeroCounts))/static_cast<float>(MS4525Span)*static_cast<float>(MS4525FullScaleRange)-psioff;
  psi = abs(psi);

//calculate speed
  Vms = sqrt((psi*13789.5144)/1.225);
  Vkmh = Vms*3.6;
     
//output to serial monitor
  Serial.print("psioff: ");Serial.print(psioff,6);
  Serial.print(" , ");
  Serial.print("raw Pressure: ");Serial.print(P_dat);
  Serial.print(" , ");
  Serial.print("pressure psi: ");Serial.print(psi,6);
  Serial.print(" , ");
  Serial.print("speed m/s: ");Serial.print(Vms,2);
  Serial.print(" , ");
  Serial.print("speed km/h: ");Serial.println(Vkmh,2);
    if(Vkmh>45){myservo.write(pos1);} 
    else{myservo.write(pos2);} 
  
  lcd.setCursor(1,1);
  lcd.print(Vkmh);
  
  delay(250);
}

Hello @onrcnoz

Your code is Ok, except one thing:

"const int16_t MS4525ZeroCounts = (MS4525MinScaleCounts + MS4525FullScaleCounts)/2;" Not OK

"const int16_t MS4525ZeroCounts = (MS4525FullScaleCounts - MS4525MinScaleCounts)/2;" OK

The Span is the result of (MAX - MIN).....

It´s working over here ;) !

Best Regards

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