Now available: VL53L1X library for Arduino
Because of how complex the VL53L1X is and how difficult it is to learn how it works, developing a library for it has been more of a challenge than writing one for a typical sensor like an LSM303 accelerometer/magnetometer. ST’s public documentation for the VL53L1X does not describe the sensor’s internal registers or the procedures to configure and operate it; instead, they provide an API (application programming interface) for interfacing with the sensor. (This was also the case for the preceding VL53L0X, and some people have not been too thrilled with this kind of support.)
The API consists of set of functions that can be used to communicate with the VL53L1X, and its source code can be customized and compiled for a chosen platform. It’s nice to have official software that should just work, but in practice, there are several factors that make the API a less than ideal solution for the Arduino platform. For one thing, given the limited resources on an 8-bit AVR, the API uses a lot of storage and memory; when compiled for an A-Star with an ATmega32U4 microcontroller, our implementation of the ST API uses 79% of the program storage space and 49% of the dynamic memory. Additionally, the API is structured in a way that makes it a little more awkward to work with multiple sensors.
With these drawbacks in mind, my goal when writing this Arduino library was to create a streamlined software interface that makes it easy to start using the sensor in your own programs and uses less storage and memory than the API. My development process involved first modifying the API to log all of the I²C communication between the Arduino and the sensor, then digging through the API source code to try to understand how it generates all of those accesses and how it could be made more efficient. The latter task was a lot of work because of how the API compartmentalizes logic and splits it into many layers of function calls. For example, here is a call graph for one of the main functions used to initialize the sensor:
This call graph was made with Doxygen, a tool for generating documentation from source code, which I found very helpful for understanding the structure of the API; I wish I had thought of using it when writing our VL53L0X library earlier. There are actually some comments in the API source code that contain Doxygen commands, so it’s a good bet that the engineers at ST used Doxygen while originally developing the API.
I felt that the API splits things up more than is necessary for good organization, so our library combines some operations into fewer functions. For comparison, here is a call graph of the library’s initialization function, whose role includes that of the API’s
VL53L1_StaticInit function shown above (though keep in mind that the library is more limited in capability and scope):
As for memory, part of the reason the API uses so much is that it keeps a copy of the sensor’s configuration registers in memory, manipulating the register values there and writing them to the device in big chunks only when it starts a measurement. This seemed inefficient to me, especially in cases where a particular setting is configured when the sensor starts up and then never changed again, so the library performs a one-time initialization that immediately writes most of the sensor’s configuration and then only writes a few essential registers to start each measurement.
The result is that our library has significantly smaller memory and storage footprints compared to the API: the example sketch in the screenshot above uses 37% of program space and 27% of dynamic memory on an ATmega32U4, while the more minimal “Continuous” example only uses 32% and 17%, respectively. (Some of the storage and memory usage comes from the USB code in the ATmega32U4 Arduino core; it is lower on a non-USB AVR, like the ATmega328P.) The library should also feel more comfortable to work with for a typical Arduino user, since it represents a sensor as an instance of a C++ object the same way most Arduino libraries represent devices.
However, it is important to acknowledge the library’s limitations. Our library does not support everything that ST’s API can do, such as calibrating the sensor to work well under a cover glass or selecting a smaller region of interest (ROI); while I’m interested in adding more functionality in the future, the library will probably never be as capable or flexible as the official API. The library also has less stringent error checking, so it might not be as tolerant of unexpected conditions as the API. Beyond that, while our library seems to work fine, it’s hard for me to be sure that I’ve adapted the API code correctly and that the library is performing the right operations and calculations. Consequently, using ST’s API could still be a better choice for you if you want to make sure you’re interfacing with the VL53L1X correctly, especially if you’re using an Arduino with more memory and storage space that can accommodate the API more easily.
For the typical hobbyist or experimenter, though, I expect this library to be a good way to get started with the VL53L1X and an Arduino. You can learn how to install and use the library on its GitHub page. Please let us know if you have any feedback on it, including any problems you experience or functionality you would like to see added.
(A frequent question we’ve gotten about the VL6180X and VL53L0X is how to use multiple sensors on the same I²C bus, and the VL53L1X works the same way, so I’m planning to write an example program for doing that. Hint: you have to individually enable each sensor and assign it a unique address, which only lasts until the next reset or power-off.)