Categories
Aircraft Projects

DIY Altimeter for Aircraft

This is a DIY altimeter for aircraft project guide that uses inches of mercury. You can adjust it for pressure changes just like the real thing. You can order a ready to go package from us, coming soon!

The power supply can be either the battery that I’ve installed 4.2v lipo or equivalent. You can also plug it into any usb power bank and skip the battery.

Very Important to Know

For aircraft use, this altimeter uses the internal cabin pressure to get its readings. The inside of an aircraft has a slightly lower pressure and therefore will cause your handheld altimeter to read a higher altitude than your aircraft’s main altimeter. Thankfully with some programming and mental aptitude we can adjust the handheld altimeter once we’re in flight and at speed.

The general rule of thumb so far is that you’ll see about 100 feet higher altitude on the handheld project than you will see on the aircraft’s main altimeter. The only absolute fix for this is to create a pitot static port for the DIY altimeter. Or when you’re on the ground you can simply start the DIY altimeter at 100 feet lower than airport altitude depending on the speed you travel on average but lots more to come on testing and calibrating.

If you’re not using this handheld altimeter project in an airplane, the accuracy works just fine. Open cockpit aircraft will not have to worry about this either. Hang gliding, parachuting, hiking and anything else of that sort will be accurate as well.

For Use as a Backup Altimeter:

Set your aircrafts altimeter as normal. Then once you’re at speed and out of the circuit, adjust your backup altimeter to match your aircraft’s altimeter. It will remain accurate at that point but any change in the cabin pressure will change the altimeter reading such as opening a window.

Each aircraft is different in regards to cabin pressure differentials so keep that in mind.

Let’s go over the numbers on the screen first and teach you how this works.

The Numbers on the Screen

Temp:19.74 *C
P:30.30 | 30.33
Humid: 45.9%
Alt:28.7 ft

The first line is pretty straight forward, it’s 19.74 degrees in my office.
P:30.30 – This number shows your pressure.
30.33 – This number is the altimeter’s pressure setting.
Humid: 45.9% is the humidity reading and yes it will have true altitude as a feature one day.
Alt: 28.7 ft – This is your altitude.

What are the two buttons for?

The button circled with red will lower your pressure setting.
The button circled in green will raise your pressure setting.

You can use this to set the altimeter just like the main altimeter on your airplane. When you power up the altimeter it will read what you had your pressure set to last time, but today there’s a new pressure setting. It’s currently set to say, 30.05 but when you’re getting your airport pressure numbers the pressure setting is supposed to be 29.99 so we simply adjust with our buttons until the second pressure number reads 29.99.

You’ll also see your altitude reading move at the same time. So if like me your airport always stays at 252 feet elevation (haha of course it stays at that elevation) you can simply power up the altimeter and adjust to the airport altitude, exactly as you do with your pre flight checklist when you get to altimeter setting.

A really fun test I did with this project. I drove to the beach and put the altimeter right on the ground where the ocean meets the beach and set the altitude to zero. I then walked to my car (with the altimeter in hand) and drove to my airport.

What a great moment it was when I looked at the altimeter and saw that it was 4 feet off from the airport elevation showing 256 feet. I got a little mad that it wasn’t exactly bang on… until I realized I was holding the altimeter in my hand at stomach height. I gave my head a shake and then put the altimeter on the ground at which point it read almost exactly 252 feet.

Ok enough story time.

With this altimeter you will need to know either your starting elevation or your pressure setting. As an example, you’re going hiking with it and you drive to the start of the trail to head up a mountain. You turn on the altimeter and it gives you a reading. This will NOT be your actual altitude. The altimeter MUST be set to you starting altitude. If you want to know how many feet you’ve climbed from the start of the trail that’s easy. Just move the current altitude to zero with your up and down buttons and start hiking.

Parts List:

Wemos D1 mini or pro
BME280
LCD screen
Two momentary push buttons
Power supply – can be USB power like in the photos above
or at 5v power supply wired into the board.

The Code:

#include <Wire.h>
#include <EEPROM.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <U8g2lib.h>
#define SEALEVELPRESSURE_HPA 1019.0 // STD 1013.25 hPa (29.92 inHg)
Adafruit_BME280 bme;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
const char *WEBSITE_URL = "StarAirVision.com";
const int URL_DISPLAY_DELAY   = 5000; // ms
const uint32_t DISPLAY_DELAY  = 1000;  // ms
const char EEPROM_C           = 'c';  // Change this to restore the default value
const char EEPROM_ADDR  = 100;
// Constants
const float FEET_PER_METER  = 3.28084;
const float HPA_PER_INHG    = 33.8639;
const float PRESSURE_STEP   = 0.01;
const float PRESSURE_UPPER  = 32.03;
const float PRESSURE_LOWER  = 25.69;
// NB: Pressure inHg
// Variables
float levelPressure = (SEALEVELPRESSURE_HPA / HPA_PER_INHG);
float temperature;
float pressure;
float altitude;
float humidity;
class Button {
  public:
    Button(uint8_t _pin) {
      pin = _pin;
    }
    void init() {
      pinMode(pin, INPUT_PULLUP);
    }
    bool pressed() {
      bool reading = digitalRead(pin);
  
      if(reading != lastState) {
        lastState = reading;
        lastDebounce = millis();
      }
    
      if( (millis() - lastDebounce) > debounceDelay) {
        if (reading != state) {
          state = reading;
    
          if(state == LOW) {
            return true;
          }
        }
      }
  
      return false;
    }
    
  private:
    uint8_t pin;
    bool state; 
    bool lastState = LOW; 
    uint32_t lastDebounce = 0;
    uint32_t debounceDelay = 50;
};
Button upBtn(D3);
Button downBtn(D4);
void initBME() {
  Serial.println(F("BME280 test"));
  
  if( !bme.begin() ) {
      Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
      Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
      while (1) delay(10);
  }
}
void displayUrl() {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_4x6_tr);
  u8g2.drawStr(1, 15, WEBSITE_URL);
  u8g2.sendBuffer();
  delay(URL_DISPLAY_DELAY);
}
void measure() {
  temperature = bme.readTemperature();
  pressure = bme.readPressure() / 100.0F;
  humidity = bme.readHumidity();
  altitude = bme.readAltitude( (HPA_PER_INHG * levelPressure) );
  
  Serial.print("Temperature = ");
  Serial.print(temperature, 2);
  Serial.println(" *C");
  Serial.print("Pressure = ");
  Serial.print(pressure/HPA_PER_INHG, 2);
  Serial.print(" (at sea-level = ");
  Serial.print(levelPressure, 2);
  Serial.println(") inHg");
  Serial.print("Approx. Altitude = ");
  Serial.print(altitude, 2);
  Serial.print(" m ");
  Serial.print( (FEET_PER_METER * altitude), 2 );
  Serial.println(" feet");
  Serial.print("Humidity = ");
  Serial.print(humidity);
  Serial.println(" %");
  Serial.println();
}
void displayValues() {
  // Measure sensor data
  measure();
  
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_fub11_tr);
  char buf[64];
  sprintf(buf, "Temp:%.2f *C", temperature);
  u8g2.drawStr(0, 16, buf);
  sprintf(buf, "P:%.2f|%.2f", (pressure / HPA_PER_INHG), levelPressure);
  u8g2.drawStr(0, 32, buf);
  sprintf(buf, "Humid:%.1f %%", humidity);
  u8g2.drawStr(0, 48, buf);
  sprintf(buf, "Alt:%.1f ft", (FEET_PER_METER * altitude) );
  u8g2.drawStr(0, 64, buf);
  
  u8g2.sendBuffer();
}
void savePresetPressure() {
  EEPROM.put(EEPROM_ADDR, levelPressure);
  EEPROM.commit();  
}
void loadPresetPressure() {
  if(EEPROM.read( (EEPROM_ADDR-1) ) != EEPROM_C) {
    // Initialize location
    Serial.println("Init EEPROM.");
    EEPROM.write((EEPROM_ADDR-1), EEPROM_C);
    
     savePresetPressure();
  }
  else {
    EEPROM.get(EEPROM_ADDR, levelPressure);
  } 
}
void runControl() {
  static uint32_t lastSave;
  if( upBtn.pressed() ) {
    Serial.println("UP pressed");
    levelPressure += PRESSURE_STEP;
    levelPressure  = min(PRESSURE_UPPER, levelPressure);
    displayValues();
  }
  if( downBtn.pressed() ) {
    Serial.println("DOWN pressed");
    levelPressure -= PRESSURE_STEP;
    levelPressure  = max(PRESSURE_LOWER, levelPressure);
    displayValues();
  }
  
  // Only attemp to save after 5 seconds
  if( (uint32_t)(millis() - lastSave) > 5000 ) {
    savePresetPressure();
    lastSave = millis();
  }
}
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  EEPROM.begin(512);
  // Configure buttons
  upBtn.init();
  downBtn.init();
  // Load preset level pressure from EEPROM
  loadPresetPressure();
  
  initBME();
  u8g2.begin();
  // Display website url
  displayUrl();
}
uint32_t lastDisplay;
void loop() {
  // put your main code here, to run repeatedly:
  runControl();
  
  if( (uint32_t)(millis() - lastDisplay) > DISPLAY_DELAY) {
    displayValues();
    lastDisplay = millis();
  }
}

Wiring the Board

Both the BME280 and LCD screen use the same pins for SCL and SDA.
SCL for both will go to D1 on the board.
SDA for both will go to D2 on the board.
Both BME280 and the screen will use 3.3v out from the board.
All grounds go to the ground pin next to 5v on the board.

Buttons:
The UP button needs a wire going from D3 to one side of the button, then the other side of the button goes to ground. When the button is pushed you’re causing a ground on pin D3 telling the board to move once.
The DOWN button needs a wire going from D4 to one side of the button, then the other side of the button goes to ground.

The BME280 sensor is the red one on the image above but that’s not what they look like in real life, it was just the best representation that I could find in the list.

If you have questions please feel free to email ryan@starairvision.com