# Arduino Altimeter

This is a revisit to the CanSat project to share some tips on how to use a simple MPX4115A pressure sensor as an altimeter.  In a previous post I shared how to set up the sensor to detect ambient pressure, so now that we have that data, how do we estimate our altitude?

## The First Attempt

A somewhat simplistic equation for relating height to pressure is given as:

P=101325(1-2.25577 x 10-5h)5.25588

Here, pressure (P) is given in Pascals, while height (h) is given in meters.  We can calculate P from our pressure sensor. We need to rearrange this equation to isolate h.

For simplicity sake, lets replace the coefficients:
Let A = 101325
Let B = 2.25577 x 10-5
Let C = 5.25588

Our equation then becomes:
$P=A\left(1-Bh\right)^{C}$
Dividing both sides by A gives:
$\frac{P}{A}=\left(1-Bh\right)^{C}$
Raising both sides by 1/C gives:
$\left(\frac{P}{A}\right)^{\frac{1}{C}}=\left(\left(1-Bh\right)^{C}\right)^{\frac{1}{C}}$
This can be simplified to:
$\left(\frac{P}{A}\right)^{\frac{1}{C}}=\left(1-Bh\right)$
Subtract 1 from both sides:
$\left(\frac{P}{A}\right)^{\frac{1}{C}}-1=-Bh$
Finally divide by -B to reveal:
$\frac{\left(\frac{P}{A}\right)^{\frac{1}{C}}-1}{-B}=h$

Now that we’ve isolated ‘h’ we can implement a the function in code to calculate it from the sensor pressure reading, and the constant coefficients:

// Read Pressure in Pascals
float pressure=((pressureValue/1024.0)+0.095)/0.000009;

// Calculate Height using formula above
float height = 0.0;
float A = 101325.0;
float B = 2.25577E-05;
float C = 5.25588;

height = (((pow((pressure/A),1/C))-1)/-B);


### Testing

Testing this code on an Arduino with pressure sensor gave readings of 987.72 hPa ( 98771.71 Pa) and an estimated height of 214.74 meters.  This was compared to the local weather station, which gave pressure as 991.4 hPa.  Using the GPS feature of my smart phone, it estimated height at between 76 and 84 meters.

As our results show, there are wide discrepancies. These are due to the natural air pressure variation due to weather systems. The first formula doesn’t take atmospheric pressure into account, so even at the same height we could miscalculate our altitude due to high or low pressure weather systems. Although this first attempt is simplistic, it may not be of sufficient accuracy to be useful.

## Using the Barometric Function.

The barometric formula is a more sophisticated model of how pressure relates to height.  It also takes into account the launch temperature and pressure, so we can calculate a relativistic height (height above/below launch), rather than an absolute one.

The barometric formula is given as:
$h=\left(\frac{T_{1}}{a}\right)\left(\left(\frac{p}{p_{1}}\right)^{\frac{-aR}{g}}-1\right)+h_{1}$

Where:

• h: height in meters

• h1: height in meters at launch

• T1: Temperature at launch in Kelvin

• a: temperature gradient. Constant of -0.0065 Kelvin per meter.

• p: Pressure in Pascals

• p1: Pressure at launch in Pascals

• R: Gas Constant of 287.06 J/kg*K

• g: Acceleration due to gravity. Constant of 9.81 m/s2.

This gives us an estimate of altitude based on existing pressure and temperature conditions at launch. To get an accurate measure of altitude we will need to set h1 to our height at launch. Otherwise we can assume h1 to be zero and we would then be calculating a relative height, with reference to the launch height.

### Coding

Assuming we can read the ambient temperature, we can calculate the height relative to launch height, using this Arduino sketch:


float launchTemp;
float launchPressure;
float launchHeight;

// Constants
float G = 9.81;
float R = 287.06;
float A = -0.0065;

void setup() {
Serial.begin(9600);

Serial.print("Launch temperature: ");
Serial.print(launchTemp);
Serial.println(" Kelvin");

Serial.print("Launch Pressure: ");
Serial.print(launchPressure/100.0);
Serial.println(" hPa");

launchHeight = 0.0;
}

void loop(){
float height = getHeight(pressure);
float millibars = pressure/100;

Serial.println();
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" K");
Serial.print("Pressure = ");
Serial.print(pressure);
Serial.println(" pascals");
Serial.print("Pressure = ");
Serial.print(millibars);
Serial.println(" millibars");
Serial.print("Height = ");
Serial.print(height);
Serial.println(" meters");
delay(1000);
}

/* Reads pressure from the given pin.
* Returns a value in Pascals
*/
// Serial.print("Vp: ");
// Serial.println(pressureValue);
float pressure=(((pressureValue/1024.0)+0.095)/0.000009);
return pressure;
}

/* Translates pressure (in Pascals) to height (in meters)
*/
float getHeight(float pressure){
float height = 0.0;
float arg = (A*R)/G;
height = (launchTemp/A)*(pow(pressure/launchPressure, -arg)-1) + launchHeight;
return height;
}

/*
* Reads the temperature of a thermister, at the given pin.
* Return the temperature as Kelvin
*/
int Vo; // Integer value of voltage reading
float Rf = 9830.0; // Fixed resistance in the voltage divider
/*
* Steinhart-Hart Equation coefficients.
* Calculated from datasheet reference temps/resistances.
*/
float c1 = 1.3084634E-03;
float c2 = 2.344772E-04;
float c3 = 1.04177209450756E-07;
float logRt,Rt,T;

Rt = Rf*( 1023.0 / (float)Vo - 1.0 ); // Calculate thermister resistance
logRt = log(Rt);

// Apply Steinhart-Hart equation.
T = ( 1.0 / (c1 + c2*logRt + c3*logRt*logRt*logRt ) );
return T;
}

float kelvinToCelcius(float temp){
return temp - 273.15;
}



### Testing

On testing, we receive output similar to:

Launch temperature: 295.46 Kelvin
Launch Pressure: 986.63 hPa
Pressure = 98663.20 pascals
Pressure = 986.63 millibars
Height = 0.00 meters
Pressure = 98771.71 pascals
Pressure = 987.72 millibars
Height = -9.50 meters 

As we can see, the signal from the pressure sensor seems noisy. Our rate of error is frequent, and puts us out by close to 10 meters, which is significant. Further approaches to calibration, and reducing the errors will have to be considered to improve sensor resolution.