In this tutorial you will learn how to use the VL53L1X (also called TOF400C) Laser Range Distance Sensor with an Arduino or any other common microcontroller (ESP32/ESP8266) to measure distances.
The VL53L1X is a is a very small, Time-of-Flight Distance Sensor (ToF) sensor that uses infrared laser light to measure the distance to an object. By measuring the time it takes for the light to be reflected from an objects, it can compute distances with high accuracy.
Required Parts
You will need an VL53L1X Distance Sensor. As for the microcontroller, I used an Arduino Uno for this project, but any other Arduino or any ESP32/ESP8266 will work as well. We also will use an OLED to display the distances measured by the VL53L1X on a screen.
VL53L1X Distance Sensor
Arduino Uno
USB Cable for Arduino UNO
Dupont Wire Set
Breadboard
OLED Display
Makerguides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on Amazon.com. As an Amazon Associate we earn from qualifying purchases.
Features of the VL53L1X
The VL53L1X is a tiny chip (4.4 x 2.5 x 1.56 mm) with two holes on the top. One for the laser light emitter and one for the light detector. The VL53L1X operates by sending out a laser light plus from the emitter, receiving the reflected light from an object in the detector, and based of the time it took (time-of-flight) then computes the distance to the object. The picture below shows the emitter and detector cones.
Here are the main specification of the VL53L1X:
- 940 nm VCSEL emitter (IR light, invisible to eye)
- Measurement time 20ms up to 1000ms
- Programmable region of interest (ROI) size
- Programmable ROI position on the receiving array
- Three distance modes: short, medium, and long
- Distance between 4cm and 400cm
- Resolution: 1mm
- Voltage: 2.6 to 3.5 V
- I2C communication interface (up to 400kHz)
The programmable regions of interest (ROI) of the VL53L1X allow the full field of view to be reduced or divided into multiple zones. You can use this to implement gesture recognition, such as swiping, for instance. For more details have a look at the datasheet of the VL53L1X sensor:
Application Schematic of VL53L1X
The following application schematic shows you the external wiring needed to use the VL53L1X chip. You can see the pull-up resistors for the I2C interface that connects the VL53L1X to a microcontroller (host), and two capacitors that stabilize the power supply.
SDA and SCL are the pins for the I2C interface. XSHUT is the shutdown pin, which allows you to shutdown the sensor, when pulled down. This is useful if you want to connect multiple VL53L1X sensors to the same I2C line. GPIO1 is an interrupt pin that can signal to the microcontroller that data is ready.
However, instead of using the tiny VL53L1X chip directly, it is better to get a breakout board that has the above electronics already integrated and is much easier to connect.
Breakout board for VL53L1X
The following picture shows the back and front of typical breakout board for the VL53L1X. The actual sensor chip is located behind the oval, protective cover. The cover reduces the impact of ambient light on the sensor accuracy.
The pinout has the same pins discussed above. SDA, SCL for I2C, GPIO1 as interrupt signal, XSHUT for chip selection, and VIN and GND for power supply.
Connecting the VL53L1X
Thanks to the I2C interface of the VL53L1X, connecting it to an Arduino is easy. First, connect the SCL and SDA pins of the VL53L1X breakout board to the corresponding pins on the Arduino board as shown below. Next, connect ground to GND and 3.3V to VIN of the VL53L1X.
The VL53L1X breakout board runs on 5V or 3.3V and you can use either for VIN. Here, I am using 3.3V for VIN. Next, let us write some code to test the function of he VL53L1X sensor.
Code for measuring distance with VL53L1X
Before you can measure distances with the VL53L1X sensor, you will have to install a library. The most common ones are the Adafruit VL53L1X Library and the VL53L1X Library by Pololu. I had, however, issues with the Adafruit libraries when writing the tutorial for the VL53L0X Distance Sensor, and will therefore use the VL53L1X Library by Pololu. It also offers more configuration options for the VL53L1X.
Installing the VL53L1X Library by Pololu
To install the VL53L1X Library by Pololu, open the Library Manager, search for VL53L1X, find the one by Pololu and install. The picture below shows how that looks like once the library is installed:
With the library installed, let’s try the sensor out. The following code reads distances measured by the VL53L1X and prints them to the Serial monitor.
#include "VL53L1X.h" VL53L1X sensor; void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) { Wire.begin(); sensor.setTimeout(500); sensor.init(); sensor.setDistanceMode(range_mode); int budget = high_speed ? 33000 : 140000; sensor.setMeasurementTimingBudget(budget); } void setup() { Serial.begin(9600); // range_mode: VL53L1X::Short, VL53L1X::Medium, or VL53L1X::Long sensor_init(VL53L1X::Medium, false); } void loop() { int dist = sensor.readRangeSingleMillimeters(); Serial.println(dist); delay(1000); }
Let’s break down the code into its components for a better understanding.
Including the Library
The code begins by including the necessary library for the VL53L1X sensor. This library provides the functions needed to communicate with the sensor.
#include "VL53L1X.h"
Creating a Sensor Object
Next, we create an instance of the VL53L1X
class, which allows us to interact with the sensor.
VL53L1X sensor;
Sensor Initialization Function
The sensor_init()
function is responsible for initializing the sensor. It takes two parameters: range_mode
which specifies the distance measurement mode, and high_speed
which determines the measurement timing budget.
void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) { Wire.begin(); sensor.setTimeout(500); sensor.init(); sensor.setDistanceMode(range_mode); int budget = high_speed ? 33000 : 140000; sensor.setMeasurementTimingBudget(budget); }
Inside this function:
Wire.begin();
initializes the I2C communication.sensor.setTimeout(500);
sets a timeout for sensor operations.sensor.init();
initializes the sensor.sensor.setDistanceMode(range_mode);
sets the distance mode based on the input parameter.- The measurement timing budget is set based on whether high speed is requested.
According to the datasheet, the VL53L1X timing budget should be set as follows.
- 20 ms is the minimum timing budget and can be used only in short distance mode.
- 33 ms is the minimum timing budget which can work for all distance modes.
- 140 ms is the timing budget which allows the maximum distance of 4 m (in the dark on a white chart) to be reached with long distance mode
In the code, I use 33 ms for the speed mode, since it works with all ranges and otherwise 140ms, since it allows the maximum distance.
For the range, you can use the predefined constants VL53L1X::Short
, VL53L1X::Medium
, or VL53L1X::Long
. The range the sensor can measure depends on the chosen mode and the ambient light. The following table from the datasheet of the VL53L1X shows the dependencies:
Long distance mode allows the longest possible ranging distance of up to 4 m to be reached – under ideal conditions (dark). Generally, the ranging distance is impacted by ambient light. Short distance mode is more immune to ambient light, but its maximum ranging distance is typically limited to 1.3 m.
Setup Function
In the setup()
function, we start the Serial communication and initialize the sensor with a specific distance mode.
void setup() { Serial.begin(9600); // range_mode: VL53L1X::Short, VL53L1X::Medium, or VL53L1X::Long sensor_init(VL53L1X::Medium, false); }
Here, Serial.begin(9600);
sets up the Serial Monitor at a baud rate of 9600. The sensor_init()
function is called with VL53L1X::Medium
as the range mode and false
for high speed, which means the sensor will operate in medium range with a longer timing budget.
Loop Function
Finally, in the loop()
function, we continuously read the distance from the sensor and print it to the Serial Monitor.
void loop() { int dist = sensor.readRangeSingleMillimeters(); Serial.println(dist); delay(1000); }
If you upload and run the code you should see the measured distances printed on the Serial Monitor.
In the next section we are going to add an OLED to our circuit and display the distances on that, instead of printing to the Serial Monitor.
Adding an OLED to display VL53L1X data
Since the OLED is also an I2C device, connecting it is straightforward. We simply connect SDA and SCL to the same pins the VL53L1X sensor is connected to. And since the OLED runs on 3.3V, we can also share the power supply lines.
Code to display distances measured by VL53L1X on OLED
The following code reads distance measurements from the VL53L1X sensor and displays them on the OLED. Have a quick look at the complete code first, and then we will discuss its details.
#include "Wire.h" #include "VL53L1X.h" #include "Adafruit_SSD1306.h" Adafruit_SSD1306 oled(128, 64, &Wire, -1); VL53L1X sensor; void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) { Wire.begin(); sensor.setTimeout(500); sensor.init(); sensor.setDistanceMode(range_mode); int budget = high_speed ? 33000 : 140000; sensor.setMeasurementTimingBudget(budget); } void oled_init() { oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); oled.setTextSize(2); oled.setTextColor(WHITE); } void display() { static char text[30]; int dist = sensor.readRangeSingleMillimeters(); sprintf(text, "%4d mm", dist); oled.clearDisplay(); oled.setCursor(20, 25); oled.print(text); oled.display(); } void setup() { oled_init(); sensor_init(VL53L1X::Medium, false); } void loop() { display(); }
Let’s break down the code into its parts for a better understanding.
Library Inclusions
At the beginning of the code, we include the necessary libraries for our project. The Wire.h
library is used for I2C communication, VL53L1X.h
is for interfacing with the VL53L1X distance sensor, and Adafruit_SSD1306.h
is for controlling the OLED display.
#include "Wire.h" #include "VL53L1X.h" #include "Adafruit_SSD1306.h"
Object Initialization
Next, we create instances of the OLED display and the distance sensor. The OLED display is initialized with a width of 128 pixels and a height of 64 pixels. The &Wire
parameter indicates that we are using the Wire library for I2C communication, and -1
indicates that we are not using a reset pin.
Adafruit_SSD1306 oled(128, 64, &Wire, -1); VL53L1X sensor;
Sensor Initialization Function
The sensor_init()
function initializes the VL53L1X sensor. It takes two parameters: range_mode
to set the distance measurement mode and high_speed
to determine the measurement timing budget. Inside the function, we start the I2C communication, set a timeout for the sensor, initialize it, and configure the distance mode. The measurement timing budget is set based on whether high speed is enabled or not.
void sensor_init(VL53L1X::DistanceMode range_mode, bool high_speed) { Wire.begin(); sensor.setTimeout(500); sensor.init(); sensor.setDistanceMode(range_mode); int budget = high_speed ? 33000 : 140000; sensor.setMeasurementTimingBudget(budget); }
OLED Initialization Function
The oled_init()
function initializes the OLED display. It begins by powering the display using the SSD1306_SWITCHCAPVCC
parameter and setting the I2C address to 0x3C
. We also set the text size to 2 and the text color to white.
void oled_init() { oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); oled.setTextSize(2); oled.setTextColor(WHITE); }
Display Function
The display()
function is responsible for reading the distance from the sensor and displaying it on the OLED screen. It first declares a static character array text
to hold the distance string. The distance is read in millimeters using sensor.readRangeSingleMillimeters()
, and the result is formatted into the text
array using sprintf()
. The OLED display is then cleared, the cursor is set to a specific position, and the distance is printed. Finally, the display is updated to show the new content.
void display() { static char text[30]; int dist = sensor.readRangeSingleMillimeters(); sprintf(text, "%4d mm", dist); oled.clearDisplay(); oled.setCursor(20, 25); oled.print(text); oled.display(); }
Setup Function
In the setup()
function, we call the initialization functions for both the OLED display and the distance sensor. The sensor is initialized with a medium range mode and high speed disabled.
void setup() { oled_init(); sensor_init(VL53L1X::Medium, false); }
Loop Function
Finally, the loop()
function continuously calls the display()
function, which updates the OLED screen with the latest distance measurement from the sensor. This loop runs indefinitely, providing real-time distance readings.
void loop() { display(); }
Conclusions
In this tutorial you learned how to use the VL53L1X Distance Sensor with an Arduino to measure distances and to display them on an OLED.
The VL53L1X Sensor is a is a very small, fast, high-precision sensor that uses infrared laser light to measure distances. The VL53L1X is almost identical to the VL53L0X but has a larger range. The former can measure distances of up to 400cm, while the latter is limited to 200cm.
Another, similar laser range sensor that uses the Time-of-Flight method is the TOF10120 sensor. However, the VL53L1X has more configuration options (long range, fast speed) and has a greater range (up to 400cm vs 180cm).
Other common infrared distance sensors such as the GP2Y0A710K0F or the GP2Y0A21YK0F use triangulation to determine distance based on the angle of the reflected IR light and have shorter range and lower accuracy.
If you have any questions feel free to leave them in the comment section.
Happy Tinkering ; )
Stefan is a professional software developer and researcher. He has worked in robotics, bioinformatics, image/audio processing and education at Siemens, IBM and Google. He specializes in AI and machine learning and has a keen interest in DIY projects involving Arduino and 3D printing.