Altitude measurement question

Hi, I'm trying to display relative altitude (is relative the right term?? :~ ) in serial terminal, as in, if I stand halfway-up the mountain, and press reset, my altitude will display zero. If I climb the mountain, the altitude will increase. If I descend, the altitude will become a negative value (-).

I'm using the bmp180 sensor, but I'm having difficulty making this happen. I can find my local barometric pressure value from the internet, and use it to calculate the local altitude (then increase the value or decrease the value as I walk around). My local altitude is about 285m above sea level, so this is the value Arduino starts at in serial terminal.

What I'm trying to do is have it start from zero whenever I reset Arduino, wherever in the world I might be. (I'm not too picky about pressure accuracy).

Can anyone help? Sorry if I'm being a dumbass.

I'm using this tutorial: http://www.loveelectronics.co.uk/Tutorials/20/bmp180-arduino-library-tutorial

Can anyone help? Sorry if I'm being a dumbass.

OK, dumbass, post your code. Hey, you said it, not me.

Lol sorry

?
// Include the Wire library for I2C access.
#include <Wire.h>
// Include the Love Electronics BMP180 library.
#include <BMP180.h>

// Store an instance of the BMP180 sensor.
BMP180 barometer;
// We are going to use the on board LED for an indicator.
int indicatorLed = 13; 

// Store the current sea level pressure at your location in Pascals.
float seaLevelPressure = 102085;

void setup()
{
  // We start the serial library to output our messages.
  Serial.begin(9600);
  // We start the I2C on the Arduino for communication with the BMP180 sensor.
  Wire.begin();
  // Set up the Indicator LED.
  pinMode(indicatorLed, OUTPUT);
  // We create an instance of our BMP180 sensor.
  barometer = BMP180();
  // We check to see if we can connect to the sensor.
  if(barometer.EnsureConnected())
  {
    Serial.println("Connected to BMP180."); // Output we are connected to the computer.
    digitalWrite(indicatorLed, HIGH); // Set our LED.
    
     // When we have connected, we reset the device to ensure a clean start.
    barometer.SoftReset();
    // Now we initialize the sensor and pull the calibration data.
    barometer.Initialize();
  }
  else
  { 
    Serial.println("Could not connect to BMP180.");
    digitalWrite(indicatorLed, LOW); // Set our LED.
  }
}

void loop()
{
  if(barometer.IsConnected)
  {
    // Retrive the current pressure in Pascals.
    long currentPressure = barometer.GetPressure();
    
    // Print out the Pressure.
    Serial.print("Pressure: ");
    Serial.print(currentPressure);
    Serial.print(" Pa");
    
    // Retrive the current altitude (in meters). Current Sea Level Pressure is required for this.
    float altitude = barometer.GetAltitude(seaLevelPressure);
    
    // Print out the Altitude.
    Serial.print("\tAltitude: ");
    Serial.print(altitude);
    Serial.print(" m");
    
    // Retrive the current temperature in degrees celcius.
    float currentTemperature = barometer.GetTemperature();
    
    // Print out the Temperature
    Serial.print("\tTemperature: ");
    Serial.print(currentTemperature);
    Serial.write(176);
    Serial.print("C");
    
    Serial.println(); // Start a new line.
    delay(500); // Show new results every half second.
  }
}

My logic is assuming that, if you take the first altitude reading after pressing Arduino reset, and subtract this from every further reading, this would presumably give the altitude I want (relative altitude ??? :~ ) :

current altitude - Initial altitude = relative altitude (the jackpot!)

But how to code this?

  // We create an instance of our BMP180 sensor.
  barometer = BMP180();

You already had an instance of the BMP180 class.

serial altitude - Initial altitude = relative altitude

"serial altitude"? Is that the altitude of the serial port?

    long currentPressure = barometer.GetPressure();
    float altitude = barometer.GetAltitude(seaLevelPressure);

Make these same calls in setup(), but store the results in global variables. Perhaps ones called, oh I don't know, maybe initialPressure and initialAltitude.

Why aren't you getting the altitude based on the measured pressure? The altitude you get from this call should be sea level.

    delay(500); // Show new results every second.

Useless comments should at least be correct.

PaulS:

  // We create an instance of our BMP180 sensor.

barometer = BMP180();





> You already had an instance of the BMP180 class.


Corrected



> serial altitude - Initial altitude = relative altitude




> "serial altitude"? Is that the altitude of the serial port?


Yarp. I guess, aka "current altitude"



long currentPressure = barometer.GetPressure();
   float altitude = barometer.GetAltitude(seaLevelPressure);





> Make these same calls in setup(), but store the results in global variables. Perhaps ones called, oh I don't know, maybe initialPressure and initialAltitude.



How to store as a global variable? Like this?:
initialPressure = (long currentPressure = barometer.GetPressure());
initialAltitude = (float altitude = barometer.GetAltitude(seaLevelPressure));

confused




> Why aren't you getting the altitude based on the measured pressure? The altitude you get from this call should be sea level.
> 
> 
> 
> ```
>     delay(500); // Show new results every second.
> ```
> 
> 
> 
> 
> > Useless comments should at least be correct.


Corrected.

Updated code:

// Include the Wire library for I2C access.
#include <Wire.h>
// Include the Love Electronics BMP180 library.
#include <BMP180.h>

// Store an instance of the BMP180 sensor.
BMP180 barometer;
// We are going to use the on board LED for an indicator.
int indicatorLed = 13; 


// Store the current sea level pressure at your location in Pascals.
float seaLevelPressure = 102085;

void setup()
{
  long currentPressure = barometer.GetPressure();
  float altitude = barometer.GetAltitude(seaLevelPressure);
  // We start the serial library to output our messages.
  Serial.begin(9600);
  // We start the I2C on the Arduino for communication with the BMP180 sensor.
  Wire.begin();
  // Set up the Indicator LED.
  pinMode(indicatorLed, OUTPUT);
  // We check to see if we can connect to the sensor.
  if(barometer.EnsureConnected())
  {
    Serial.println("Connected to BMP180."); // Output we are connected to the computer.
    digitalWrite(indicatorLed, HIGH); // Set our LED.
    
     // When we have connected, we reset the device to ensure a clean start.
    barometer.SoftReset();
    // Now we initialize the sensor and pull the calibration data.
    barometer.Initialize();
  }
  else
  { 
    Serial.println("Could not connect to BMP180.");
    digitalWrite(indicatorLed, LOW); // Set our LED.
  }
}

void loop()
{
  if(barometer.IsConnected)
  {
    // Retrive the current pressure in Pascals.
    long currentPressure = barometer.GetPressure();
    
    // Retrive the current altitude (in meters). Current Sea Level Pressure is required for this.
    float altitude = barometer.GetAltitude(seaLevelPressure);
    
    // Print out the Altitude.
    Serial.print("\tAltitude: ");
    Serial.print(altitude);
    Serial.print(" m");
    
    // Retrive the current temperature in degrees celcius.
    float currentTemperature = barometer.GetTemperature();
    
    Serial.println(); // Start a new line.
    delay(500); // Show new results every second.
  }
}

How to store as a global variable? Like this?:
initialPressure = (long currentPressure = barometer.GetPressure());
initialAltitude = (float altitude = barometer.GetAltitude(seaLevelPressure));

confused

You need to define initialPressure and initialAltitude as global variables. Do you know what that means? Global variables are declared outside of any function - typically before setup().

Then, just use:

initialPressure =  barometer.GetPressure();
initialAltitude = barometer.GetAltitude(initialPressure);

in setup().

Frankly, you should get rid of the seaLevelPressure variable. You don't give a rats ass about sea level. You want the pressure nw, and the altitude that corresponds to that pressure, not the altitude that corresponds to some other pressure.

Don't discount "sea level pressure" so quickly!

Because the relationship between altitude, temperature and air pressure is highly nonlinear, most algorithms that determine altitude from the current air pressure use a fairly simple functional model for the Earth's atmosphere. The model includes determination of a reference value for the air pressure at sea level, at some assumed temperature, which is then used as the basis for a lookup table or functional derivation of the current altitude/pressure relationship. The reference sea level value has to be updated frequently.

Furthermore, the "sea level pressure" (not the absolute pressure) is what is reported in your local newspaper, at the local airport and on customized weather reports. So, if you want to calibrate your altimeter/barometer, you have to know what the correction is from your altitude to sea level.

I've used the now retired SCP1000 absolute pressure sensor for a variety of applications, partly because it was the first, cheap and accurate module available (you could easily detect a 20 cm difference in altitude). It came with a user manual that describes the basic equations very clearly, so I wrote an driver and barometer/altimeter function for the AVR Butterfly (ATmega169) on the basis of it. That project is simple C code and is posted on AVRFreaks at http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=2362

The coded equations for determining the sea level pressure and altitude may be useful and some of the code could be readily imported into a sketch. If you want to set your current altitude to zero, that is fine. The code will then calculate a nonsensical value for the sea level pressure, but the atmosphere model still works correctly.

I've posted the atmosphere model that I used here http://molbio.uoregon.edu/~remington/scp1000_barometer.pdf as it no longer seems to be available on the web. Of course, any pressure sensor can be used with these equations.

Finally, I did experiment with temperature corrections using the adiabatic model for a dry atmosphere, but they are second order and not useful in practice.

Simple code to calculate altitude in feet or meters from local temperature in Kelvin and pressure in Pa. Calibration function included

//globals
volatile unsigned long int pressure;	//pressure reading in Pa from SCP1000
volatile signed int temperature;		//temperature in degrees C*10 from SCP1000
char buffer[13];						//temporary formatting buffer

	signed long P0=101325;	  	//standard atmosphere in Pa, updated when altitude is set
	float alt_m, dTdH=0.0065, T0=288.15;		//Assume 15 degrees Celcius; 0 C = 273.15 K
	signed long tav,pav,t,p; 	//temp variables, temperature and pressure
	signed long alt_f=0,new_alt;	//altitude in feet
	uint8_t i,key;				//loop variables
	double fact;

//  main loop
	while(1) {

	tav=0; pav=0; key=0;

// loop to average pressure and temperature data

		for(i=0; i<SAMPLES; i++) {
			scp_read();				//read pressure and temperature from SCP1000
			tav+=temperature;
			pav+=pressure;
			}

//
// user input to change altitude?  ...key pressed?
// Note that GetNum returns only integer values
//
		if(key && (p>0)) {  //but only if we already have t & p

			new_alt = alt_f; //save old altitude
			new_alt = GetNum(new_alt);  //display current altitude and input new altitude from user

// calculate P0 from new altitude
// dTdH and T0 are kept as variables, in case user implements temperature correction

			alt_m= new_alt/METERS_TO_FEET;	//back to meters, if necessary 
			fact = 1.0 - alt_m*dTdH/T0;
			fact = pow(fact,5.256);
			P0 = ((double) p)/fact + 0.5;
			}
		else {  //display measured altitude

			t=(tav+SAMPLES/2)/SAMPLES;	//round and average temperature measurements
			p=(pav+SAMPLES/2)/SAMPLES;	//round and average pressure measurements
			print_decimal(t, 1, 2);		//display temperature
			LCD_puts(buffer); //on LCD
//
// calculate current altitude from standard atmosphere model (see application 
// note #33 from VTI): "SCP1000 Pressure Sensor as Barometer and Altimeter"
// dTdH and T0 are kept as variables, in case user implements temperature correction
//
			fact= 1.0 - pow(((double) p)/((double) P0),0.19026);
			alt_m = (T0/dTdH)*fact;
			alt_f = alt_m*METERS_TO_FEET + 0.5;  //convert units
			print_decimal(alt_f, 0,1);
			LCD_puts(buffer); //print derived altitude

			} //end if else
	
	} //end while (1)

jremington:
Simple code to calculate altitude in feet or meters from local temperature in Kelvin and pressure in Pa. Calibration function included

//globals

volatile unsigned long int pressure; //pressure reading in Pa from SCP1000
volatile signed int temperature; //temperature in degrees C*10 from SCP1000
char buffer[13]; //temporary formatting buffer

signed long P0=101325;	  	//standard atmosphere in Pa, updated when altitude is set
float alt_m, dTdH=0.0065, T0=288.15;		//Assume 15 degrees Celcius; 0 C = 273.15 K
signed long tav,pav,t,p; 	//temp variables, temperature and pressure
signed long alt_f=0,new_alt;	//altitude in feet
uint8_t i,key;				//loop variables
double fact;

//  main loop
while(1) {

tav=0; pav=0; key=0;

// loop to average pressure and temperature data

	for(i=0; i<SAMPLES; i++) {
		scp_read();				//read pressure and temperature from SCP1000
		tav+=temperature;
		pav+=pressure;
		}

//
// user input to change altitude?  ...key pressed?
// Note that GetNum returns only integer values
//
if(key && (p>0)) {  //but only if we already have t & p

		new_alt = alt_f; //save old altitude
		new_alt = GetNum(new_alt);  //display current altitude and input new altitude from user

// calculate P0 from new altitude
// dTdH and T0 are kept as variables, in case user implements temperature correction

		alt_m= new_alt/METERS_TO_FEET;	//back to meters, if necessary 
		fact = 1.0 - alt_m*dTdH/T0;
		fact = pow(fact,5.256);
		P0 = ((double) p)/fact + 0.5;
		}
	else {  //display measured altitude

		t=(tav+SAMPLES/2)/SAMPLES;	//round and average temperature measurements
		p=(pav+SAMPLES/2)/SAMPLES;	//round and average pressure measurements
		print_decimal(t, 1, 2);		//display temperature
		LCD_puts(buffer); //on LCD

//
// calculate current altitude from standard atmosphere model (see application
// note #33 from VTI): "SCP1000 Pressure Sensor as Barometer and Altimeter"
// dTdH and T0 are kept as variables, in case user implements temperature correction
//
fact= 1.0 - pow(((double) p)/((double) P0),0.19026);
alt_m = (T0/dTdH)fact;
alt_f = alt_m
METERS_TO_FEET + 0.5;  //convert units
print_decimal(alt_f, 0,1);
LCD_puts(buffer); //print derived altitude

		} //end if else

} //end while (1)

This is for the SCP1000 not the BMP180 sensor, so this makes it....

PaulS:

How to store as a global variable? Like this?:
initialPressure = (long currentPressure = barometer.GetPressure());
initialAltitude = (float altitude = barometer.GetAltitude(seaLevelPressure));

confused

You need to define initialPressure and initialAltitude as global variables. Do you know what that means? Global variables are declared outside of any function - typically before setup().

Then, just use:

initialPressure =  barometer.GetPressure();

initialAltitude = barometer.GetAltitude(initialPressure);



in setup().

Frankly, you should get rid of the seaLevelPressure variable. You don't give a rats ass about sea level. You want the pressure nw, and the altitude that corresponds to that pressure, not the altitude that corresponds to some other pressure.

I think in this situation removing the seaLevelPressure variable is a good idea. I'm not really using it.

now to practice defining global variables

I think the code works. Anyone seem to agree? :slight_smile: How do I share on Arduino Playground? I made an Arduino Playground page: Google Code Archive - Long-term storage for Google Code Project Hosting.

//----------BMP180 pressure sensor example sketch 2: Display zero altitude from current location------------//
Code:

//---Example BMP180 sketch by Benbojangles 2013----//
//---This sketch will make your altitude zero when you press the reset button---//
//---Allowing you to know increases and decreases in altitude based on your initial location---//
//---Altitude is in Meters---//

// Include the Wire library for I2C access.
#include <Wire.h>
// Include the BMP180 library.
#include <BMP180.h>

//------------ Store an instance of the BMP180 sensor. ----------------//
BMP180 barometer;
//------------ Use the on board LED for an indicator. -----------------//
int indicatorLed = 13; 


//--- Set current pressure & altitude, in this example it will be zero when we press reset button. ---//
int initialPressure = 0;
int initialAltitude = 0;

void setup()
{
  initialPressure =  barometer.GetPressure();
  initialAltitude = barometer.GetAltitude(initialPressure);
  
  long currentPressure = barometer.GetPressure();
  float altitude = barometer.GetAltitude(initialPressure);
  // Start the serial library to output our messages.
  Serial.begin(9600);
  // Start the I2C on the Arduino for communication with the BMP180 sensor.
  Wire.begin();
  // Set up the Indicator LED.
  pinMode(indicatorLed, OUTPUT);
  // Check to see if connected to the sensor.
  if(barometer.EnsureConnected())
  {
    Serial.println("Connected to BMP180."); // Output - connected to the computer.
    digitalWrite(indicatorLed, HIGH); // Set our LED.
    
     // When connected, reset the device to ensure a clean start.
    barometer.SoftReset();
    // Initialize the sensor and pull the calibration data.
    barometer.Initialize();
  }
  else
  { 
    Serial.println("Not connected to BMP180.");
    digitalWrite(indicatorLed, LOW); // Set our LED.
  }
}

void loop()
{
  if(barometer.IsConnected)
  {
    // Retrive the current pressure in Pascals.
    long currentPressure = barometer.GetPressure();
    
    // Retrive the current altitude (in meters).
    float altitude = barometer.GetAltitude(currentPressure);
    
    // Print out the Altitude.
    Serial.print("\tAltitude: ");
    Serial.print(altitude);
    Serial.print(" m");
    
    // Retrive the current temperature in degrees celcius.
    float currentTemperature = barometer.GetTemperature();
    
    Serial.println(); // Start a new line.
    delay(500); // Show new results every half second.
  }
}

Also, here is the library, with included example:

BMP180.zip (7.01 KB)

benbojangles1:
I think the code works. Anyone seem to agree? :slight_smile: How do I share on Arduino Playground? I made an Arduino Playground page: Google Code Archive - Long-term storage for Google Code Project Hosting.

//----------BMP180 pressure sensor example sketch 2: Display zero altitude from current location------------//
Code:

//---Example BMP180 sketch by Benbojangles 2013----//

//---This sketch will make your altitude zero when you press the reset button---//
//---Allowing you to know increases and decreases in altitude based on your initial location---//
//---Altitude is in Meters---//

// Include the Wire library for I2C access.
#include <Wire.h>
// Include the BMP180 library.
#include <BMP180.h>

//------------ Store an instance of the BMP180 sensor. ----------------//
BMP180 barometer;
//------------ Use the on board LED for an indicator. -----------------//
int indicatorLed = 13;

//--- Set current pressure & altitude, in this example it will be zero when we press reset button. ---//
int initialPressure = 0;
int initialAltitude = 0;

void setup()
{
 initialPressure =  barometer.GetPressure();
 initialAltitude = barometer.GetAltitude(initialPressure);
 
 long currentPressure = barometer.GetPressure();
 float altitude = barometer.GetAltitude(initialPressure);
 // Start the serial library to output our messages.
 Serial.begin(9600);
 // Start the I2C on the Arduino for communication with the BMP180 sensor.
 Wire.begin();
 // Set up the Indicator LED.
 pinMode(indicatorLed, OUTPUT);
 // Check to see if connected to the sensor.
 if(barometer.EnsureConnected())
 {
   Serial.println("Connected to BMP180."); // Output - connected to the computer.
   digitalWrite(indicatorLed, HIGH); // Set our LED.
   
    // When connected, reset the device to ensure a clean start.
   barometer.SoftReset();
   // Initialize the sensor and pull the calibration data.
   barometer.Initialize();
 }
 else
 {
   Serial.println("Not connected to BMP180.");
   digitalWrite(indicatorLed, LOW); // Set our LED.
 }
}

void loop()
{
 if(barometer.IsConnected)
 {
   // Retrive the current pressure in Pascals.
   long currentPressure = barometer.GetPressure();
   
   // Retrive the current altitude (in meters).
   float altitude = barometer.GetAltitude(currentPressure);
   
   // Print out the Altitude.
   Serial.print("\tAltitude: ");
   Serial.print(altitude);
   Serial.print(" m");
   
   // Retrive the current temperature in degrees celcius.
   float currentTemperature = barometer.GetTemperature();
   
   Serial.println(); // Start a new line.
   delay(500); // Show new results every half second.
 }
}




Also, here is the library, with included example:

Hello,
Your code is very nice, this is typically what I'm looking for. I have the project to add an OSD on my Quadcopter with an arduino and a MAX7456 for the video part.
The code works properly but isn't realy smooth in altitude reading.
So I would like to make an average reading of the measurement (+/- 10/second) and print it every 1 second.
I'm very new with arduino and coding... If someone have an idee to do this posible it would be great :slight_smile:
Thanks
Arnaud

docspool:
So I would like to make an average reading of the measurement (+/- 10/second) and print it every 1 second.

You can maintain a rolling average just using an exponential decaying average. Conceptually, it's this:

average = (average * weight) + (newValue * (1 - weight))

The 'blink without delay' example demonstrates how to do things at regular intervals, such as displaying the average once per second.

Thanks for your reply Peter,
I'm a real neewbie with programing and your equation does not inspire me a lot of code :sweat_smile: