Reading altimeter data into the Arduino

Greg Wilson
4 min readJan 13, 2018

--

This article, part of the Arduino Radio Control Model Plane Altitude Hold series, describes the technique that will be used to read altimeter data via the I2C bus into the Arduino.

Having a way to read the altimeter is essential to the altitude hold project.

Connecting the devices

It is simple to connect the devices (see an earlier article in the series for details about the devices themselves). The altimeter needs a power source, so connect it to +5V and GROUND. The altimeter needs two data connections to allow I2C communications: SDA (pin A4 on my nano) and SCL (pin A5).

Program

You’ll need to know the address for the altimeter device. Mine is `0xE8`.

We use the Wire library to communicate with the device.

Here’s the program that we’ll use to communicate with the altimeter.

/* Demonstrates one way to read altitude data from an an I2C 
* device, specifically using:
* - Arduino Nano
* - Wire library
* - Eagletree Altimeter Microsensor v3
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
* OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
// We'll use the Wire library for I2C operations
#include <Wire.h>
// This value is from the online documentation for the
// altimeter device
byte i2c_altimeter_address = 0xE8;
// This item toggles debugging behaviour on or off.
// Comment the item out to disable debugging messages.
#define debug
// Set up debugging behaviours
#ifdef debug
#define debug_print(x) Serial.print (x)
#define debug_println(x) Serial.println (x)
#else
#define debug_print(x)
#define debug_println(x)
#endif
/**
* Prepares for altimeter reading using the Wire library.
*/
void setup() {
// Join I2C bus (address optional for master)
Wire.begin();
// The Wire library only needs seven-bit device addresses
i2c_altimeter_address = i2c_altimeter_address >> 1;

#ifdef debug
// Start serial communication so we can see the results
Serial.begin(57600);
#endif
}
/**
* Reads the altimeter many times, then
* shows some summary data if debug mode is enabled.
*/
void loop() {
long start_time, end_time, mean_time;
int iterations = 2000;
int lowest = 5000; // Start with an unreasonably high value
int highest = -1; // Start with an unreasonably low value
int altitude;
int error_count = 0;
start_time = micros();
for (int i=0; i<iterations; i++) {
altitude = i2c_read_altimeter();
if (altitude < 0) {
error_count++;
} else {
highest = max(altitude, highest);
lowest = min(altitude, lowest);
}
}
end_time = micros();
mean_time = (end_time - start_time) / iterations;
debug_print("Cycles completed:");
debug_print(iterations);
debug_print("\tMean time (micro-seconds):");
debug_print(mean_time);
debug_print("\tHighest: ");
debug_print(highest);
debug_print("\tLowest: ");
debug_print(lowest);
debug_print("\tErrors: ");
debug_println(error_count);
}
/**
* Read the altimeter and return the result.
* The EagleTree Altimeter Microsensor v3 returns
* a value using the measurement units that are set
* on the device itself, and can be feet or metres.
* My device is set to metres.
* The measurement will be between 0 and 3048 metres,
* so an integer return value is suitable.
* A return value of -100 indicates an error.
*/
int i2c_read_altimeter() {
int altitude = -100;
byte first_byte, second_byte;

// Send the read command to the device
Wire.beginTransmission(i2c_altimeter_address);
Wire.write(byte(0x07));
Wire.endTransmission(false);
// Request a 2-byte response from the device
Wire.requestFrom(i2c_altimeter_address, (byte) 2);
if (Wire.available() >= 2) {
// Calculate and return the altitude
first_byte = Wire.read();
second_byte = Wire.read();
altitude = second_byte * 256 + first_byte;
}
return altitude;
}

Typical output

I ran the program while I walked with my laptop and connected device up a little hill. The reported altitudes steadily climbed from 0 to 16 metres. Here are some selected lines from the output:

Cycles completed:2000 Mean time (micro-seconds):592 Highest: 0 Lowest: 0 Errors: 0
...
Cycles completed:2000 Mean time (micro-seconds):592 Highest: 1 Lowest: 0 Errors: 0
...
Cycles completed:2000 Mean time (micro-seconds):592 Highest: 9 Lowest: 9 Errors: 0
...
Cycles completed:2000 Mean time (micro-seconds):592 Highest: 16 Lowest: 16 Errors: 0

Output jitter

For the most part, the output was steady and believable, with little or no difference between the highest and lowest altitude values returned in a short period.

Some of the lines showed an unreasonably large range between the highest and lowest values recorded in a short period. Here are some examples:

Cycles completed:2000 Mean time (micro-seconds):592 Highest: 4 Lowest: 1 Errors: 0Cycles completed:2000 Mean time (micro-seconds):592 Highest: 9 Lowest: 4 Errors: 0Cycles completed:2000 Mean time (micro-seconds):592 Highest: 14 Lowest: 7 Errors: 0

We ought to include some kind of filtering or smoothing in the project, so that spurious results don’t cause problems.

Read time

It takes only ~0.6 milliseconds (~600 microseconds) to read the altimeter. That’s fast enough for our purpose.

Conclusion

We can use a technique based on this demonstration in the altitude-hold project. The altimeter data is mostly reliable, but some filtering or smoothing would be a good idea.

--

--

Greg Wilson

Hopeless at orienteering, rubbish at flying radio controlled planes, but enjoys both activities anyway.