Learn

An Arduino laser ruler with the VL53L0X

Beginner

Or see every lesson.

  • 455parts on the bench
  • 43boards running now
  • 1.00xreal time, on every board
Arduino Uno: VL53L0X laser rulerlive0.000 s 0.00x
Click to open it in the editor
A VL53L0X on I2C on a simulated ATmega328P. Drag the slider on the sensor to move the target.

The VL53L0X is a tiny laser distance sensor on a board the size of a fingernail. It fires a pulse of invisible infrared light, times how long the light takes to bounce back, and reports the distance in millimeters. It is more precise than an ultrasonic sensor at short range, works on soft and angled targets that swallow sound, and has a narrow beam.

The circuit above is an Arduino Uno with a VL53L0X on I2C. Drag the slider on the sensor to move the target and the serial monitor prints the distance five times a second. It runs in your browser on the sketch below, which uses the calls from Pololu’s VL53L0X library.

What you need

  • An Arduino Uno
  • A VL53L0X breakout board (the GY-530 and the Pololu boards are common)
  • A half-size breadboard and four jumper wires

Wiring

Part and pinGoes toNote
VL53L0X VIN5 VMost breakouts have a regulator for 3.3 V or 5 V
VL53L0X GNDGND
VL53L0X SDAA4I2C data on the Uno
VL53L0X SCLA5I2C clock on the Uno
XSHUT and GPIO1Not connectedOnly needed for several sensors or interrupts

How a laser can time something that fast

Light covers a meter in about 3.3 nanoseconds, far too fast for an ordinary clock. The VL53L0X uses a grid of single-photon detectors that count the light coming back and work out the delay from it. All your sketch sees is a number in millimeters, over I2C at address 0x29.

In its default mode it reaches about 1.2 meters on a white target indoors. Past that, nothing useful comes back and the chip reports 8190, which the sketch prints as "out of range". Each reading takes about 33 milliseconds.

The sketch, step by step

setup() starts I2C, sets a 500 millisecond timeout so the sketch never hangs on a missing sensor, and calls init(). If init() fails, the sketch prints "Failed to detect and initialize sensor!" and stops. Otherwise it starts continuous ranging and prints "Laser ruler ready".

loop() reads the latest range with readRangeContinuousMillimeters(). With the target at the start of the slider it prints "distance 300 mm". Move it to 250 mm and the next lines say 250. Move it to 1.5 meters and the lines say "out of range".

The laser ruler sketch
#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  sensor.setTimeout(500);
  if (!sensor.init()) {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {
    }
  }
  sensor.startContinuous();
  Serial.println("Laser ruler ready");
}

void loop() {
  uint16_t mm = sensor.readRangeContinuousMillimeters();
  if (sensor.timeoutOccurred()) {
    Serial.println("timeout");
  } else if (mm >= 8190) {
    Serial.println("out of range");
  } else {
    Serial.print("distance ");
    Serial.print(mm);
    Serial.println(" mm");
  }
  delay(200);
}

VL53L0X or HC-SR04?

The HC-SR04 ultrasonic sensor reaches further, to a few meters, and costs less. The VL53L0X is smaller, faster, more precise up close and has a much narrower beam, so it sees the thing in front of it rather than the wall beside it. It also needs only the two I2C wires, which you can share with other sensors.

For distances past 1.2 meters, its bigger sibling the VL53L1X reaches about 4 meters with the same wiring. Both are on the Mokxi bench.

Two or more sensors on one bus

Every VL53L0X starts up at the same I2C address, 0x29, so two of them on the same wires answer at once and neither works. The fix uses the XSHUT pin, which holds a sensor switched off. Wire each sensor’s XSHUT to its own digital pin. In setup(), hold them all low, then let the first one up, give it a new address with setAddress(0x30), and let the next one up.

The new address lasts until the power goes or XSHUT is pulled low again, so the sketch does this every time it starts. The simulated sensor keeps a new address the same way.

Try it in the editor

Add an LED on pin 9 that gets brighter as the target comes closer, with analogWrite() and map(). Or add a buzzer that beeps faster as the distance shrinks, like a parking sensor.

Then pull the SDA wire and press Run. The sketch prints "Failed to detect and initialize sensor!", which is exactly what a loose wire does on the desk.

Common mistakes

SDA and SCL swapped. On an Uno, SDA is A4 and SCL is A5. On a Mega they are pins 20 and 21.

Two sensors on one bus. Both answer at 0x29. Hold one in reset with XSHUT, give the other a new address with setAddress(), then let the first one up.

Leaving the protective film on. Many boards ship with a thin plastic film over the sensor. Peel it off or the readings come back short.

Expecting it to see through glass or in bright sunlight. Glass reflects the beam, and strong sunlight drowns it, so the range drops.

Questions

How do I connect a VL53L0X to an Arduino Uno?

VIN to 5 V, GND to GND, SDA to A4 and SCL to A5. Then use the Pololu VL53L0X library: init(), startContinuous() and readRangeContinuousMillimeters().

What is the range of the VL53L0X?

About 1.2 meters in the default mode on a white target indoors. A dark target or bright light shortens it. Past its range the sketch reads 8190.

Does the Adafruit VL53L0X library work too?

The example here uses the Pololu library’s calls, which compile in Mokxi. Check the library list in the editor by typing #include < for what else your board can build.

What does Mokxi not model on the VL53L0X?

The few millimeters of noise a real reading has, how the target’s color and the room’s light change the reach, and the long range and high accuracy modes. The distance is exactly what the slider says.

Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.