Maker.io main logo

CLUE Altimeter

2024-01-23 | By Adafruit Industries

License: See Original Project Displays

Courtesy of Adafruit

Guide by Carter Nelson

Overview

Knowing one's altitude, height above sea level, is useful for many ‎applications. Airplane pilots use it, so they don't run into the ground ‎or each other. Hikers and mountain climbers use it to know where ‎they are and how far to the summit. Etc.‎

climb_1

There are various ways to determine altitude. Pressure based ‎altitude computation is a common method and Adafruit sells ‎numerous pressure sensors that can report an altitude. But to get an ‎accurate value for altitude from pressure, there are a few important ‎details to consider. In this guide we will go over the specifics of how ‎pressure is used to compute altitude and learn about those ‎important details.‎

To help illustrate things in a real world application, we will use ‎an Adafruit CLUE board and CircuitPython to create a simple little ‎altimeter and take it into the mountains.‎

Put your yodelin' hat on and let's get started!‎

Parts

The Atmosphere

atmosphere_2

Image courtesy of the Earth Science and Remote Sensing Unit, NASA Johnson Space Center ‎‎(Photo ID ISS045-E-27869)‎

Ah, the atmosphere. It's the lovely air that's all around us. We are all ‎generally familiar with several properties of this atmosphere, like ‎temperature, humidity, etc. You can just walk outside and feel those ‎right away.‎

There is also pressure. You don't quite sense that the same way, but ‎it's there. If you've ever had your ears pop while going up in an ‎elevator, that's due to the change in pressure.‎

In the above image, note how thin the atmosphere appears in ‎relation to the scale of the Earth. It's often compared to the outer ‎skin of an onion. But that's where we all hang out :)‎

The Standard Atmosphere

As we will see, pressure and temperature change with altitude. In ‎reality, they also change with time (ex: midnight vs. high noon) and ‎location (ex: equator vs. poles). To provide atmospheric values an ‎engineer can use in design calculations, the idea of a "standard ‎atmosphere" is used. Just think of this as the atmospheric values ‎averaged over all locations and times. The results are then made ‎available via publications, like this:‎

An example atmosphere reference publication. Get your copy here.‎

reference_3

That example is the 1962 version of the U.S. Standard Atmosphere. It ‎was updated several times, with the most recent being the 1976 ‎version:‎

The 1976 U.S. Standard Atmosphere. Get your copy here.‎

copy_4

There is also an International Standard Atmosphere.‎

These publications are nothing more than page after page of tables ‎that provide atmospheric values for any given altitude. The tables ‎come from various equations which the publications also discuss. In ‎‎1976, computers were expensive, so these books of tables were a ‎cheaper solution than putting those equations into a computer. ‎Luckily, that is no longer the case and nowadays one would simply ‎use any number of available computer-based options, like this ‎Python library:‎

Python Ambiance Standard Atmosphere Library.‎

How Things Change with Altitude

OK, so let's look at how pressure and temperature change with ‎altitude in this standard atmosphere model. Here are some plots ‎that show this. These were created using the Python module ‎ambiance linked above.‎

change_5

The vertical axis is height, with the bottom being sea level and the ‎top being 80km (that's very high). Pressure decreases with altitude ‎in a bendy curve sort of way. Temperature is wacky, it sometimes ‎decreases, sometimes stays the same, sometimes increases.‎

Even though the Earth's atmosphere is thin relative to the overall ‎size of the Earth (see image at top of this page), it is pretty tall when ‎compared with the highest point on Earth - Mt. Everest. In this guide, ‎we are mainly interested in altitudes on the Earth's surface, like ‎places where we could actually stand. So, we don't need to worry ‎about anything above the summit of Everest. Let's zoom in.‎

change_6

There! These two plots show the variation in pressure and ‎temperature for the altitudes we are interested in - anywhere your ‎feet are touching the ground. Now things look much simpler, just ‎two happy little lines.‎

Note how pressure changes with altitude. Specifically - pressure ‎decreases as altitude increases. We will use that fact to create our ‎pressure-based altimeter. First, we need a way to measure pressure, ‎so let's look at how pressure sensors work.‎

Pressure Sensors

It's a little difficult to appreciate how significant the changes in ‎pressure within the atmosphere can be. The following experiment is ‎a fun way to get a good general idea.‎

Go to a high altitude, like a mountain summit. Take an empty plastic ‎water bottle and remove the cap so it fills with air with a pressure at ‎that altitude. Now put the cap on tightly so it seals in that air. Then ‎go down in altitude. The air inside stays at the lower pressure of the ‎higher altitude. The outside air pressure will increase as you descend. ‎If you can change altitude enough, the bottle will get crushed!‎

The difference in air pressure over 13,000 feet is enough to crush a ‎plastic bottle!‎

pressure_7

Most pressure sensors work in a similar way. They have a sensing ‎membrane which is like the plastic bottle. Here is what the inside of ‎a sensor similar to the BMP280 on the Adafruit CLUE looks like:‎

The blue surface is just like the plastic bottle.‎

blue_8

Think of the inside of the plastic bottle being like what is underneath ‎that blue surface - a small pocket of trapped air. The upper side of ‎the blue surface is like the outside of the bottle. It will see whatever ‎air pressure it is surrounded by. So as the air pressure above the blue ‎surface changes, it deflects, like the water bottle being crushed. This ‎deflection is then sensed by the other electronics on the sensor. ‎Turning that into pressure is just a matter of math.‎

Computing Altitude

Warning! This page contains ugly math. Sorry.‎

OK, so we have some understanding of how the atmosphere (in ‎particular pressure) changes with altitude. And we've learned a bit ‎about how pressure sensors work. So how can we use a pressure ‎sensor to determine altitude?‎

Well, buried in that lovely U.S. Standard Atmosphere document, on ‎page 12, is this sweet little equation 33a:‎

equation_9

Bleh! That's a mess. But don't worry, we can simplify this greatly. This ‎is a full form general purpose equation, so includes all the bells and ‎whistles.‎

To make it a little clearer, here are the pressure (P) and altitude (H) ‎that we are interested in:‎

equation_10

Everything else in the equation is a constant - known values that we ‎simply go look up. Here's a rundown:‎

We get R*, g0', and TM,b from Table 2. For our case, TM,b is T0.‎

table_11

We get Hb and LM,b from Table 4.‎

We are staying within the lowest region of the atmosphere, so b=0.‎

table_12

After a little hunting, we track down M0 in the text.‎

text_13

So, we simply plug in all those values and all that is left is pressure (P) ‎and altitude (H).‎

But then, one more step. This equation computes pressure for a ‎given altitude, but we want to go the other way - we want to ‎compute altitude for a given pressure. So, we need to rearrange the ‎equation.‎

Here's the end result after plugging in all those constants and ‎rearranging:‎

equation_14

Just plug in pressure P from our pressure sensor and out comes ‎altitude H in meters. Neat!‎

Someone working at NWS/NOAA probably got tired of answering ‎this one also and put together this little handy cheat sheet:‎

Pressure Altitude

Yeah! Our answers agree.‎

Hey, Wait - There's Still a Variable

Oops. We still got a variable named Pb in the equation. What is that? ‎Lead? Peanut butter? Princess Bubblegum? Nope. It's another ‎pressure. And that's the crux of the problem when it comes to ‎pressure-based altimeters. So, let's go into some detail about ‎what Pb is and how to deal with it...‎

Dealing With Changes

The term Pb in our altitude equation is the pressure at the bottom of ‎the atmospheric zone we are in. Since we are focusing on the lowest ‎zone in the atmosphere, the bottom is zero altitude, aka sea level. So, ‎we have:‎

equation_15

The sea level pressure, SLP, is just what it says. If you went down to ‎the ocean and measured the pressure right at the water, that would ‎be sea level pressure. The problem is this:‎

Sea level pressure is not constant and changes with time and ‎location.‎

Ugh! So how do we deal with SLP so we can compute altitude? ‎There are two general approaches.‎

Calibrating Using Sea Level Pressure

This is super easy. If you know the current value for sea level ‎pressure, SLP, then just plug it in. Then your pressure sensor ‎measures your local pressure, P, and you can compute altitude, H, ‎using:‎

calibrate_16

Done!‎

The value for SLP needs to be for your current location, not the value ‎from some other location miles away.‎

This is what airplane pilots do. Before takeoff, they listen over the ‎radio to a local report that provides SLP at the airport's location. They ‎then turn a dial on the airplane's altimeter to set that value. Then off ‎they go!‎

A pilot turns the knob (arrow) until the reading in the Kollsman ‎window (square) matches the reported local SLP.‎

altimeter_17

OK, but what if you are standing out in the middle of the mountains? ‎Maybe you could use a radio or smartphone to get a value for SLP. ‎But it won't be for your specific location. Also, being in the ‎mountains is typically an off-grid affair. So even getting SLP from the ‎outside world is often not possible. In these situations, you rely on ‎knowing your current altitude and using this next approach.‎

Calibrating Using Current Altitude

In this case, you are standing at a known altitude, H. The pressure ‎sensor itself gives the current local pressure, P. We can then ‎rearrange our altitude equation to back compute what sea level ‎pressure, SLP, would be:‎

calibrate_18

You specify H, the pressure sensor provides P, and from that we ‎compute SLP. We store that value for SLP and use it from then on in ‎our main altitude equation - the same one used in previous section.‎

But how do you know your current altitude H? If you knew it, why ‎would you even need an altimeter? With this approach you typically ‎use certain geographical features which have known altitudes. Here ‎are some examples:‎

If you were standing at the outflow to Azure Lake, then your actual ‎altitude is going to be very close to 4055 feet, same as the lake's ‎altitude.‎

altitude_19

If you were standing on the summit of SE Twin Spire, aka Hard Mox, ‎then your altitude is 8504 feet.‎

altitude_20

If you are on the trail at Park Creek Pass, then your altitude is ‎between 6040 and 6080 feet - the closest contours. Using ‎something like 6070 feet would be good.‎

altitude_21

When you reach one of these locations, you stop for a bit, have a ‎snack, and calibrate your altimeter. Then off you go!‎

Altimeter Code

Let's use an Adafruit CLUE to bring this all together and ‎demonstrate how a pressure-based altimeter works, and also why ‎calibration is important.‎

Prepare the CLUE

Follow this guide for setting up CircuitPython on the CLUE:‎

CircuitPython on CLUE

Download the Project Bundle

Your project will use a specific set of CircuitPython libraries and ‎the code.py file. To get everything you need, click on the Download ‎Project Bundle link below, and uncompress the .zip file.‎

Hook your CLUE to your computer via a known good USB ‎data+power cable. It should show up as a thumb drive ‎named CIRCUITPY.‎

Using File Explorer/Finder (depending on your Operating System), ‎drag the contents of the uncompressed bundle directory onto your ‎board's CIRCUITPY drive, replacing any existing files or directories ‎with the same names, and adding any new ones that are necessary.‎

Once the code restarts, the altimeter should start and show up on ‎the CLUE screen. Head on to the next pages for instructions on how ‎to use the altimeter code.‎

‎Download Project Bundle

Copy Code
# SPDX-FileCopyrightText: 2020 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import struct
import displayio
import terminalio
from microcontroller import nvm
from adafruit_display_text import label
import adafruit_imageload
from adafruit_clue import clue

# ==| USER CONFIG |=====================
USE_METRIC = False
DISPLAY_UPDATE = 1
HOLD_TO_SET = 1
FONT = terminalio.FONT
BLUE = 0x53E4FF
ORANGE = 0xFCDF03
RED = 0xFA0000
DEBOUNCE = 0.05
SAMPLES = 10
DELAY = 0.05
STD_SLP = 1013.25
# ==| USER CONFIG |=====================

# configure pressure sensor (see Table 15 in datasheet)
clue._pressure.mode = 0x03 # normal
clue._pressure.overscan_pressure = 0x05 # x16
clue._pressure.overscan_temperature = 0x02 # x2
clue._pressure.iir_filter = 0x02 # 4
clue._pressure.standby_period = 0x01 # 62.5 ms

# restore saved sea level pressure from NVM
slp = struct.unpack("f", nvm[0:4])[0]
clue.sea_level_pressure = slp if 0 < slp < 2000 else STD_SLP

# --------------------------------------------------------------------
# D I S P L A Y S E T U P
# --------------------------------------------------------------------

# create main display group
splash = displayio.Group()
clue.display.root_group = splash

# background
bg_bmp, bg_pal = adafruit_imageload.load(
"images/network23.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette
)
for i, color in enumerate(bg_pal):
if color == 0xFF0000:
bg_pal.make_transparent(i)
break
background = displayio.TileGrid(bg_bmp, pixel_shader=bg_pal)

# a group for both altitude readouts
alti_readouts = displayio.Group(scale=6)

# altitude (corrected)
alti_disp = label.Label(FONT, text="12345", color=ORANGE)
alti_disp.anchor_point = (0, 0)
alti_disp.anchored_position = (7, 2)

# altitude (uncorrected)
alt2_disp = label.Label(FONT, text="12345", color=ORANGE)
alt2_disp.anchor_point = (0, 0)
alt2_disp.anchored_position = (7, 15)

# add both alti's to group
alti_readouts.append(alti_disp)
alti_readouts.append(alt2_disp)

# barometric pressure and temperature
aux_data = label.Label(FONT, text="P: 1234.56 T: 123.4", color=BLUE)
aux_data.anchor_point = (0, 0)
aux_data.anchored_position = (16, 212)

# calibration mode indicator
cal_mode = label.Label(FONT, text=" ", color=RED, scale=4, x=150, y=200)

# add everything to splash
splash.append(background)
splash.append(alti_readouts)
splash.append(aux_data)
splash.append(cal_mode)

# --------------------------------------------------------------------
# H E L P E R F U N C T I O N S
# --------------------------------------------------------------------
def compute_altitude(barometric_pressure, sea_level_pressure):
"""Compute altitude (m) from barometric pressure (hPa) and sea level pressure (hPa)."""
# https://www.weather.gov/media/epz/wxcalc/pressureAltitude.pdf
return 44307.69396 * (1 - pow((barometric_pressure / sea_level_pressure), 0.190284))


def compute_sea_level_pressure(barometric_pressure, altitude):
"""Compute sea level pressure (hPa) from barometric pressure (hPa) and altitude (m)."""
return barometric_pressure * pow((1 - (altitude / 44307.69396)), -5.2553)


def average_readings(samples=10, delay=0.05):
"""Return averaged readings for pressure and temperature."""
pressure = 0
temperature = 0
for _ in range(samples):
pressure += clue.pressure
temperature += clue.temperature
time.sleep(delay)
return pressure / samples, temperature / samples


def recalibrate(current_sea_level_pressure=None):
"""Enter current altitude."""
cal_mode.text = "CAL"
alt2_disp.text = "-----"
# wait for release if still being held
while clue.button_a and clue.button_b:
pass
# get current value
altitude = int(alti_disp.text)
done = False
while not done:
now = time.monotonic()
# increase
if clue.button_a and not clue.button_b:
altitude -= 1
time.sleep(DEBOUNCE)
# decrease
elif clue.button_b and not clue.button_a:
altitude += 1
time.sleep(DEBOUNCE)
# hold both to set
elif clue.button_a and clue.button_b:
while clue.button_a and clue.button_b:
if time.monotonic() - now > HOLD_TO_SET:
print("done")
done = True
break
alti_disp.text = "{:5d}".format(altitude)
cal_mode.text = " "
# change clue settings
if not USE_METRIC:
altitude *= 0.3048
# get current local pressure
barometric_pressure, _ = average_readings(SAMPLES, DELAY)
# compute sea level pressure and set
clue.sea_level_pressure = compute_sea_level_pressure(barometric_pressure, altitude)
# store in NVM for later use
nvm[0:4] = struct.pack("f", clue.sea_level_pressure)


def update_display():
"""Update the display with latest info."""
barometric_pressure, temperature = average_readings(SAMPLES, DELAY)
altitude = compute_altitude(barometric_pressure, clue.sea_level_pressure)
alt2tude = compute_altitude(barometric_pressure, STD_SLP)
if not USE_METRIC:
altitude *= 3.28084 # ft
alt2tude *= 3.28084
# barometric_pressure *= 0.0145038 # psi
temperature = 32 + 1.8 * temperature # deg F
alti_disp.text = "{:5d}".format(int(altitude))
alt2_disp.text = "{:5d}".format(int(alt2tude))
aux_data.text = "P: {:7.2f} T: {:5.1f}".format(barometric_pressure, temperature)


# --------------------------------------------------------------------
# M A I N L O O P
# --------------------------------------------------------------------
last_update = time.monotonic()

while True:

now = time.monotonic()

# update display with latest info
if now - last_update > DISPLAY_UPDATE:
update_display()
last_update = now

# hold both to recalibrate
if clue.button_a and clue.button_b:
# accumulate hold time
while clue.button_a and clue.button_b:
if time.monotonic() - now > HOLD_TO_SET:
print("set")
recalibrate(clue.sea_level_pressure)
break
# wait for release if still being held
while clue.button_a and clue.button_b:
pass

View on GitHub

Using the CLUE Altimeter

Here's a rundown on how to use to CLUE altimeter.‎

Normal Mode

When the program starts up, it enters normal mode. The pressure ‎sensor is constantly read, and the altitude is computed and reported. ‎Here is a summary of what is shown:‎

  • A: The corrected altitude readout.‎
  • B: Altitude based on standard day sea level pressure.‎
  • C: Current barometric pressure and sensor temperature.‎

normal_22

The idea with the two altitudes values is to provide a comparison ‎between a "calibrated" or corrected (COR) value with one that is ‎uncorrected. For the uncorrected value, the sea level pressure value ‎used in the altitude calculation is that for a standard day (STD) of ‎‎1013.25 hPa.‎

The COR value is the one that will show your actual altitude based ‎on the current calibration. If the calibration is wrong, then the ‎reading will be wrong. Here's how to calibrate:‎

Calibration Mode

This is the mode you enter to calibrate the altimeter. The calibration ‎is based on knowing your current altitude - so you will need that ‎value.‎

To enter calibration mode, hold both buttons.‎

mode_23

CAL appears in lower right corner. The STD readout changes to ‎dashes.‎

Now use buttons to increase (INC) or decrease (DEC) the value ‎in A to match the current altitude.‎

current_24

Once the value in A is set, hold both buttons again to save the ‎calibration and exit CAL mode.‎

value_25

CAL disappears and the altitude values continue to update again.

update_26

And now you are back to Normal Mode.‎

Field Test Example

Let's take our CLUE altimeter for a hike and see how it does. Here's a ‎map of the hike with several locations of known altitude indicated.‎ ‎

  1. Snow Lake, 4016 ft.
  2. Gem Lake, 4857 ft.‎
  3. Wright Mountain, 5430 ft.‎

map_27

We will use point 1, Snow Lake, as our calibration point. When we get ‎there, we'll stop and set the altimeter to the known altitude at that ‎location (4016 ft). Then, we'll check the altitude again at points 2 and ‎‎3 and see how it compares.‎

Here we go:‎

At Snow Lake the altimeter was set to 4019 ft. The lake surface is ‎‎4016 ft, but we are standing with the altimeter several feet above ‎that. :)‎

Note how the STD altitude is off by a couple hundred feet.‎

altitude_28

The trail at Gem Lake is 10's of feet above the actual lake surface of ‎‎4857 ft. So, the altimeter reading here of 4872 ft. seems OK.‎

That's the summit of Wright Mountain in the background - our next ‎stop.‎

stop_29

Standing on the summit of Wright Mountain we get a reading ‎of 5436 ft. That's excellent agreement.‎

Oh, but we're holding the altimeter above the summit. OK...let's put ‎it down on the actual summit.‎

down_30

Even better. The CLUE based altimeter is agreeing within a few ‎feet! 5432 ft.‎

Note again how the STD based altitude is off by hundreds of feet.‎

off_31

And there you go. That's a perfect example of how a pressure-based ‎altimeter can be used to provide surprisingly accurate results. It also ‎hopefully illustrates how far off the altitude reading can be if proper ‎calibration is not done.‎

FAQ

How often do I need to calibrate?‎

It all depends on the weather. With calm stable weather, you might ‎be good for days. But if a weather system is moving in, your ‎calibration may only be good for hours, maybe even less.‎

How much accuracy should I expect?

With a good recent calibration, you should be able to get altitude to ‎within 10's of feet, or better, from a pressure-based altimeter. That ‎can easily degrade to 100's of feet due to atmospheric changes ‎throwing off the current calibration.‎

Why does the pressure sensor also provide temperature?

Pressure sensors are also sensitive to temperature. But all we want is ‎pressure. Therefore, the effects of temperature must be taken into ‎account and corrected. Thus, a separate temperature sensor is ‎typically located near the pressure sensing element. That ‎temperature is then used to compute a corrected pressure value. ‎This correction can be quite complex.‎‎ ‎

Typically, the value from that temperature sensor is made available. ‎But keep in mind that what it is providing is the temperature of the ‎sensor itself.‎

Can I use that temperature to measure the air temperature?‎

Not reliably. Since the pressure sensor is relatively small (small ‎thermal mass), it will change with air temperature and thus give a ‎general indication. But it is, by necessity, buried down in the sensing ‎element itself. So due to local self-heating and other effects, it can be ‎off by many degrees.‎

What's better - GPS altitude or pressure-based altitude?‎

A decent and properly calibrated pressure altimeter will easily beat a ‎GPS based altitude. Here we are only considering the GPS altitude ‎derived directly from a 3D lock on multiple satellites, which is what a ‎basic handheld GPS unit, or smartphone, will provide.

制造商零件编号 4500
CLUE NRF52840 EXPRESS
Adafruit Industries LLC
制造商零件编号 592
CABLE A PLUG TO MCR B PLUG 3'
Adafruit Industries LLC
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum