Built-in project · Arduino Uno R3

Height meter on an Arduino Uno

A VL53L1X laser ranger measures the height above the floor and a DPS310 barometer the height climbed, the two halves of a drone’s altimeter. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate About 25 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $42. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Sharing two sensors on one I2C bus
  • Measuring distance with a laser time of flight sensor
  • Estimating height change from air pressure
  • Using a start reading as a zero point
  • Difficulty: Intermediate
  • Time: About 25 minutes
  • Board: Arduino Uno R3
  • Parts: 4

How it works

Two sensors share the I2C bus on A4 and A5. A VL53L1X laser points down and measures the distance to the floor in millimeters. A DPS310 barometer measures air pressure.

Air pressure falls as you climb. At startup the sketch stores the first pressure reading. Then it multiplies the drop by 8.3 meters per hectopascal to estimate how far you have climbed. Every 400 ms it prints the floor distance and the climb. The laser is precise but short range, and the barometer works at any height.

Parts list

4 parts, plus the jumper wires. They retail for about $42; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Laser distance, VL53L1X pin SCLArduino Uno R3 pin SCL
Laser distance, VL53L1X pin SDAArduino Uno R3 pin SDA
Laser distance, VL53L1X pin GNDArduino Uno R3 pin GND
Barometric pressure, DPS310 pin VINArduino Uno R3 pin 5V
Barometric pressure, DPS310 pin GNDArduino Uno R3 pin GND
Barometric pressure, DPS310 pin SDAArduino Uno R3 pin A4
Barometric pressure, DPS310 pin SCLArduino Uno R3 pin A5
Laser distance, VL53L1X pin VIN5 V

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Height meter: a VL53L1X laser ranger looks straight down for the height
// above the floor, and a DPS310 barometer works out how far it has climbed
// from the change in air pressure, the way a drone keeps its height.
//
//   VL53L1X, DPS310   SDA -> A4   SCL -> A5   VIN -> 5 V   GND -> GND
//
// The laser is exact to a few millimeters but only reaches 4 m. The
// barometer reaches any height, but air pressure only falls about 12 Pa a
// meter near the ground, so it needs the DPS310's precision. Together they
// cover both.
//
// Things to try. Drag the distance slider on the VL53L1X. Then drag the
// pressure slider on the DPS310 down by 12 hPa: that is about 100 m of climb.

#include <Wire.h>
#include <VL53L1X.h>
#include <Adafruit_DPS310.h>

VL53L1X ranger;
Adafruit_DPS310 baro;
float startPressure = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ranger.setTimeout(500);
  if (!ranger.init()) {
    Serial.println("No VL53L1X");
  }
  ranger.setDistanceMode(VL53L1X::Long);
  ranger.setMeasurementTimingBudget(50000);
  ranger.startContinuous(100);
  if (!baro.begin_I2C(0x76)) {
    Serial.println("No DPS310");
  }
  baro.configurePressure(DPS310_16HZ, DPS310_16SAMPLES);
  baro.configureTemperature(DPS310_16HZ, DPS310_16SAMPLES);
  // Throw away the reading taken at the old settings, then wait for the
  // first at the new ones.
  sensors_event_t temp, pressure;
  baro.getEvents(&temp, &pressure);
  while (!baro.temperatureAvailable() || !baro.pressureAvailable()) {
    delay(10);
  }
  baro.getEvents(&temp, &pressure);
  startPressure = pressure.pressure;
  Serial.println("Height meter ready");
}

void loop() {
  uint16_t mm = ranger.read();
  sensors_event_t temp, pressure;
  baro.getEvents(&temp, &pressure);
  // About 8.3 m of height for each hectopascal near sea level.
  float climbed = (startPressure - pressure.pressure) * 8.3;

  Serial.print("floor ");
  if (ranger.ranging_data.range_status == VL53L1X::RangeValid) {
    Serial.print(mm);
    Serial.print(" mm");
  } else {
    Serial.print("out of range");
  }
  Serial.print("  climbed ");
  Serial.print(climbed, 1);
  Serial.println(" m");
  delay(400);
}

Code walkthrough

The key functions of the sketch, and what each one does.

setup sketch.ino

Starts I2C and the laser ranger in long distance mode with continuous readings every 100 ms. Then it starts the DPS310 at address 0x76, sets its sampling, waits for a fresh reading, and saves that pressure as startPressure, the zero for climbing.

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ranger.setTimeout(500);
  if (!ranger.init()) {
    Serial.println("No VL53L1X");
  }
  ranger.setDistanceMode(VL53L1X::Long);
  ranger.setMeasurementTimingBudget(50000);
  ranger.startContinuous(100);
  if (!baro.begin_I2C(0x76)) {
    Serial.println("No DPS310");
  }
  baro.configurePressure(DPS310_16HZ, DPS310_16SAMPLES);
  baro.configureTemperature(DPS310_16HZ, DPS310_16SAMPLES);
  // Throw away the reading taken at the old settings, then wait for the
  // first at the new ones.
  sensors_event_t temp, pressure;
  baro.getEvents(&temp, &pressure);
  while (!baro.temperatureAvailable() || !baro.pressureAvailable()) {
    delay(10);
  }
  baro.getEvents(&temp, &pressure);
  startPressure = pressure.pressure;
  Serial.println("Height meter ready");
}

loop sketch.ino

Reads the laser and the barometer. Climb is the drop in pressure from the start times 8.3. It prints the floor distance in mm, or out of range when the reading is not valid, along with the climb in meters to one decimal. Then it waits 400 ms.

void loop() {
  uint16_t mm = ranger.read();
  sensors_event_t temp, pressure;
  baro.getEvents(&temp, &pressure);
  // About 8.3 m of height for each hectopascal near sea level.
  float climbed = (startPressure - pressure.pressure) * 8.3;

  Serial.print("floor ");
  if (ranger.ranging_data.range_status == VL53L1X::RangeValid) {
    Serial.print(mm);
    Serial.print(" mm");
  } else {
    Serial.print("out of range");
  }
  Serial.print("  climbed ");
  Serial.print(climbed, 1);
  Serial.println(" m");
  delay(400);
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • Serial says No VL53L1X or No DPS310 This project
    Check SDA and SCL wiring and power. The DPS310 is read at address 0x76.
  • The floor reading says out of range This project
    The laser only reaches about 4 m, and the range must be valid. Point it at a surface within reach.
  • The climb reads zero at the start This project
    That is by design. It measures change from the pressure taken at startup.
  • The sensor is not found, or the library cannot start. Laser distance
    The I2C address is 0x29. Wire SDA and SCL with pull-ups, and power it with 2.6 V to 3.5 V (3.3 V is best). Many modules have a regulator, but check yours. Tie XSHUT HIGH to run it.
  • The distance reading jumps or reads maximum. Laser distance
    It measures to a surface in its cone, up to about 4 m in the dark and less in bright light. Pick the distance mode (short or long) and timing budget. Dark or shiny surfaces return less light.
  • The sensor is not found on I2C. Barometric pressure
    The address is 0x77, or 0x76 when the SDO pin is pulled low. Check SDA, SCL, 3.3 V power and ground. Run an I2C scanner to confirm.
  • The readings are noisy or drift. Barometric pressure
    Set oversampling and a measurement rate that suit your task. Higher oversampling lowers the noise but slows each reading. Keep the sensor away from drafts and heat sources.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.