VL53L0X Time-of-Flight (ToF) Laser Abstandssensor - [Teil 2]

Introduction

In the first part of this series we connected the ToF sensor to an ESP8266 NodeMCU D1 Mini and built an acoustic distance warning. In this article I would like to use an ESP32 NodeMCU as well as an Arduino Nano. I want to find out what functionality is still available and whether we can use the GPIO1 and XSHUT pins. Here we go.

Hardware 

Number Component Note
1 VL53L0X Sensor Breakout Board
1 ESP8266 Node MCU D1 Mini
1 ESP32 NodeMCU Modules or ESP32 Dev Kit
1 Arduino Nano.
1 KY-006 Passive Piezo Buzzer Alarm Module for Arduino
Jumper cables
Computer with Arduino IDE and Internet connection


Connect Pins

First, we connect the sensor to an ESP8266 NodeMCU D1 Mini as in Part 1 according to the following diagram:

VL53L0X Pins D1 Mini GPIO
VIN 3.3V
GND GND
SCL SCL (D1 / GPIO5)
SDA SDA (D2/ GPIO4)
GPIO1 -
XSHUT -
KY-006 Buzzer D1 Mini GPIO
- (Minus) GND
S (signal) D7 (GPIO 13)



We do not connect GPIO1 and XSHUT pins.

To remember: For the IqC-Pins SDA and SCL it is advisable to take a look at the overview of the pinouts. On the ESP8266, these pins GPIO4 and GPIO5 are labeled D2 and D1 on the board. This is different from micro controller to micro controller. The pin number 13 must be used in the Arduino IDE. The pin is marked with D7.

In the first part we have the following additions and changes to the sample code vl53l0x made:

#define BUZZER 13
#define FREQ 800
#define DURATION 300

A variable for time measurement:

unsuitable long time = 0;

In setup() Initialize the buzzer pin as output:

pinMode(BUZZER, OUTPUT);

Issue of time measurement in the loop():

if (measure.RangeStatus != 4) {  // phase failures have incorrect data
  Serial.print("Distance (mm):); Serial.Print(measure.RangeMillimeter);  
} ed {
  Serial.Print("out of range");
}

Add Buzzer:

if (measure.RangeStatus != 4) {  // phase failures have incorrect data
  Serial.print("Distance (mm):);
  Serial.Print(measure.RangeMillimeter);

  if (millis() - time >= measure.RangeMillimeter * 3) {
    time = millis();
    tonnes(BUZZER, FREQ, DURATION);
  }   
} ed {
  Serial.Print("out of range");
}

If we download the program to the micro controller, we have the status of the last time and can now proceed.

Complete source code: TOFBuzzer.ESP8266 Adafruit.

ESP32

We now switch to ESP32 NodeMCU modules. To do this, we connect the sensor and the buzzer as follows:

VL53L0X Pins ESP32
VIN 3.3V or 5V
GND GND
SCL GPIO22
SDA GPIO21
GPIO1 -
XSHUT -
KY-006 Buzzer ESP32
- (Minus) GND
S (signal) GPIO13


Depending on the design of the developer board, the arrangement of the pins can vary.


In the Arduino IDE we switch the board to ESP32 using tools and load the same program onto the micro controller. We receive an error message that the function tone() is not known. This is not implemented in the ESP32 Core. There are some derivatives in the library administration. I have found the library Tone32 on Github. It works similar to the Arduino Tone function. There is only one other parameter called "Channel", which we set to 0. You download the source code as ZIP. Next you select the Arduino IDE in the menu Sketch->Include Library->.Add ZIP library.

In the source code of our program we add the following lines:

#include <Tonnes.h>

#define BUZZER CHANNEL 0

Then we change the line:

tonnes(BUZZER, FREQ, DURATION);

and

tonnes(BUZZER, FREQ, DURATION, BUZZER CHANNEL);

This should make it possible to upload and make everything work as it did with the D1 Mini. I have noticed, however, that the sound output causes time delays. Since I don't know the library, I can't tell you exactly why. Apparently, the sound output doesn't work without blocking. It will have to do with the timers used and the PWM generated. There is also a library called ESP32Servo, which can be found in the administration. There is also the tonnes()-Function implemented. However, this shows the same behaviour. If you want to test this, install this library and change the source code as follows:

#include <ESP32Servo.h>

In setup():

 ESP32WM::allocateTimer(0);
  ESP32WM::allocateTimer(1);
  ESP32WM::allocateTimer(2);
  ESP32WM::allocateTimer(3);

and in the loop():

tonnes(BUZZER, FREQ, DURATION);

This is how I took it from the example given. I think, however, that this library is a little heavier, because it also offers other functionalities.

It is possible to manually program the sound production with PWM. I do not want to go into this further, as this article is mainly about the ToF sensor.

Complete source code: TOFBuzzer.ESP32 Adafruit.

Arduino NANO

For an acoustic distance warning WLAN is not really necessary (this is otherwise one of the main reasons to use the ESP). Therefore, I would like to rebuild the circuit with the Arduino NANO.

VL53L0X Pins Arduino NANO
VIN 5V or 3.3V
GND GND
SCL A5
SDA A4
GPIO1 -
XSHUT -
KY-006 Buzzer Arduino NANO
- (Minus) GND
S (signal) D13


 


For the pins SDA and SCL we have to look again in the pinout overview. At Arduino Nano (and also the UN) are the Pins A4 and A5. As we use Pin 13 again for the buzzer, which also controls the internal LED of the nano, we have an optical signal for the acoustic at the same time.

We now open the program that we had loaded on the D1 Mini at the beginning. We might as well reuse that. In the Arduino IDE in the Tools menu we change the board again and select the Arduino Nano. It may be necessary to convert to the old boot loader under "processor". In my case, it is. If there is an error message when uploading, try this option.

If we run the program, the distance alarm works again as on the D1 Mini. The sound sounds a little different. That's because of the slower rate. It is evident that there is no delay in the production of sound. This is due to the tone()-Function from the Arduino Core library, which we can now use again with the nano.

We have now tested the sensor on all three micro controllers. The Adafruit library can therefore be used with one of the devices, depending on the application. If you want to transfer the data to a network, the Arduino Nano will not be considered for the time being. If the delay in tone production is obstructive, leave the ESP32 outside.

Here you can test the Pololu library independently with the other two micro controllers. Use the source code in Part 1.

Complete source code: TOFBuzzer.ESP8266 Adafruit.

Accuracy vs. speed vs. range

The description of the ToF sensor (see Part 1) states that you can change the ranking profiles. The available modes are high accuracy, high speed, long range and default. To convert it, I had to dig a little deeper into the source code of the Adafruit library, as no example was provided.

There the modes are defined in an enum as a new data type. These are called:

  • VL53L0XSENSEDEFAULT
  • VL53L0XSENSELONG RANGE
  • VL53L0XSENSEHIGH SPEED
  • VL53L0XSENSEHIGH ACCURATION

In the Adafruit VL53L0X class there is a function called configSensor(), which is passed to the desired mode. We write in the setup()-Function after initialization of the sensor the following line:

lox.config(Adafruit VL53L0X::VL53L0X SENSE HIGH ACCURACY);

This sets the sensor to the "High Precision" mode. If you leave this line, VL53L0X will automaticallySENSEDEFAULT used. Replace VL53L0XSENSEHIGHACCURACY by VL53L0XSENSELONGRANGE, you can see obstacles up to 2 m distance. This reduces the accuracy. Behind this mode is a switch-case statement in the library which sets the values for timing budget, pulse period and signal rate.

Complete source code: TOFBuzzer.ESP8266ApplesPart2.ino

To make the same change with the Pololu library, we open the example sketch "Single". The possibility to change the mode is implemented there. We just need to comment on one of the lines (I choose the Long Range mode here):

#define LONG RANGE
/'35; define HIGH SPEED
/'35; defines HIGH ACCURACY

In order to incorporate this into our acoustic distance warners, we add to the example the corresponding source code from the Continuous example in Part 1 that we had changed.

Constant:

#define BUZZER 13
#define FREQ 800
#define DURATION 300

Variable for time measurement:

unsuitable long zeitalt = 0;

In setup() insert or customize these lines:

Serial. (115200);
pinMode(BUZZER, OUTPUT);
...
Serial. (F("Failed to detect and initialize sensor!") What?
...

In the loop() Insert the time measurement:

void loop()
{
  if ( sensor.timeoutOccurred (b) Serial. ("Time"); }
  if ( Sensor.readRangeSingleMillimeters () < 4000) {
Serial. ( Sensor.readRangeSingleMillimeters ());
    if (millis() -zeitAlt >= Sensor.readRangeSingleMillimeters (b) 3) {
zeitAlt = millis();
tonnes (BUZZER, FREQ, DURATION);
    }
  }
  ed {
Serial. ("out of range");
  } 
}

I will use the ESP8266 D1 Mini again and upload the program there. We can now also see obstacles with this library with a distance of up to 2 m.

Complete source code: TOFBuzzer.ESP8266HalfSingle LongRange

XSHUT pin and several sensors

The XSHUT pin is there to bring the sensor into a hardware standby mode. For example, you can switch on and off individual sensors. For example, they do not disturb each other (according to the manufacturer, however, no disturbances will occur as long as the sensors are not directed directly at each other). There are different possibilities for the cooperation of sensors. Either the reading of the measured values is synchronized or asynchronous. The GPIO1 can also be used. Thus every sensor is read out only if it can also provide useful values.

When using multiple sensors, setting the I2C address is important. Examples of this are provided in the Adafruit library. The example sketch "vl53l0x dual" shows how to use two sensors simultaneously. Since each sensor has the same default address (0x29), the addresses must be re-assigned. Unfortunately, these will not remain permanently preserved, but will have to be reset every time the micro controller restarts. The sensors must be switched on one after the other using XSHUT and then the respective addresses must be assigned. Adafruit gives a short instruction.

Additional digital pins on the micro controller are needed for the XSHUT pins of the sensors.

I'll just put a sensor to sleep on XSHUT at this point. We extend our circuit at the D1 Mini by connecting from the XSHUT pin to Pin D6 (GPIO12).

 

Now, in the program code for our acoustic distance warning system, we complete the pin assignment and the awakening. I use the Adafruit library here:

A constant for the pin number:

\35; define XSHUT 12

Variables for time measurements and state of the XSHUT pin:

unsuitable long Drag Time 2000;
unsigned long sleepTimeAlt = 0;
bool XSHUT STATE = HIGH;

The Pin in setup() initialize as output and HIGH set:

pinMode(XSHUT, OUTPUT);
pinMode(XSHUT, OUTPUT);
digitalWrite(XSHUT, XSHUT STATE);

If the sensor is switched off by XSHUT at the beginning, it will not be detected in the subsequent initialization. If we do not give the pin a clear state, it may still be in the LOW state, which means that the sensor is not recognized.

At the beginning of the loop() function we add the following lines:

if (millis() -sleepTimeAlt >= sleepTime) {
sleepTimeAlt = millis();
XSHUT STATE XSHUT STATE;
digitalWrite(XSHUT, XSHUT STATE);
  
  if (XSHUT STATE === HIGH)
Serial. ("Sensor On");
    if (! lox. (b)
Serial. (B)"Failed to boot VL53L0X"));
      while(1);
    }   
  }
  ed {
Serial. ("Sensor in Standby");
  }
}

When the time is up, the state is switched on to the digital pin for the XSHUT. When the sensor is awakened, it is necessary to use lox. () to be re-initialized. If we load the program to the D1 Mini, the distance measurement should be switched on and off in the specified interval. The disadvantage in this case is that the sensor continues to deliver the last measured value after being brought into the standby. To make it a little cleaner and really measure only when XSHUT is on HIGH, we adjust the source code again and set the measurement of the sensor into a if-Instruction:

if (XSHUT STATE)
Serial. ("Reading a measurement...") What?
lox.rangingTest (&measure, false); /pass in'true'to get debug data printout!
 
if (if) measure.RangeStatus Aah! = 4) {// phase failures have incorrect data
Serial. ("Distance (mm):")
Serial. ( measure.RangeMilliMeter );
 
if (millis() -zeitAlt >= measure.RangeMilliMeter *2) ((a)
zeitAlt = millis();
tonnes (BUZZER, FREQ, DURATION);
    }   
} else {
Serial. ("out of range");
  }
}

Thanks to this extension, the sensor is only used if the state of the XSHUT pin is at HIGH. Download the program to the micro controller and try it out.

We have now turned on and off the sensor depending on time. If we were to use the distance sensor in a vehicle, we could connect the XSHUT pin via an electronic circuit, for example, with the reverse gear. Most of the time there is a connection that ensures that the rear-view light is switched on. This would make it possible to use the audible warning device only if you are driving backwards.

If you construct a robot, you could equip it with several of these sensors and, depending on the requirements, only turn on one sensor pointing in a certain direction.

Complete source code: TOFBuzzer.ESP8266ApplesPart 2 XSHUT

If you want to use the Pololu library instead of the Adafruit library, the program looks very similar. We had developed our acoustic distance warning from the example "single". We supplement this with the same variables and settings. The only difference is the names of the function calls. To awaken the sensor, it will then take place lox. () the function sensor.init () called, just like in the setup()Function.

Complete source code: TOFBuzzer.ESP8266HalfSingleLongRange.XSHUT

GPIO1 and Interrupts

Finally, I would like to mention the GPIO1 pin on the ToF sensor. This digital pin is switched on when an obstacle is within a defined distance to the sensor. So the theory. Unfortunately, this is not well documented, even though it has been implemented by STM in the API. For the Arduino IDE this has not yet been implemented in detail. First we want to expand the circuit and connect the pin:

 


GPIO1 of the ToF sensor we connect with D5 (in Arduino IDE Pin 14). From this point on I have really long and intensive researched how to use the GPIO1 in conjunction with an interrupt. Kris Winer has used the Pololu library and Github. written an Arduino program for the ESP32. I changed that a bit to make it work with the ESP8266:

The LED pin changed from 5 to 2:

int myLed = 2;

The IqC initialization without parameters:

Wire. ();

The variable in the interrupted service routine must be declared volatile:

volatile bool New Date false;

The Interrupt Service Routine must be loaded into the IRAM on the ESP8266. For this we add the following:

ICACHEU RAM ATTR void myinthandler()
{
newData = true; // set the new data ready flag to true on interrupt
}

If we load the program to the D1 Mini, the distance measurement should be visible in the serial monitor. If we remove the pin D5, the measurement will be interrupted. So the switch works. Unfortunately, no way is implemented to enter the threshold values from which distance the interrupt should be triggered. This means that measurement data are always detected and therefore the interrupt is always triggered. This actually works just as well as the "Continuous" example without interruption functionality. So this is not really useful.

Complete source code: TOFESP8266Interrupt Polo.

With the Adafruit library (version 1.1.0) an example is named vl53l0xmultiextended provided in which an asynchronous mode using the GPIO1 is implemented. The function is called timedasyncread gpio()Yeah. From this one can derive a program similar to the previous one with the Pololu library. The functionality is the same. Unfortunately, there is also no possibility of entering threshold values.

On Github. there is an old version of the Adafruit library that also Interrupt The example calls functions that do not exist in the current version. That's why I installed this old version and then loaded the example onto the D1 Mini. Many warnings already occur during compilation, which is not a good sign. The program itself does not run on the micro controller. It might be possible to rewrite the current version of the library and transfer the functions existing in the old version there. That is no longer trivial. That's why I'm ending my tests here.

Conclusion

I've done a lot of research and testing. Adafruit and Pololu provide libraries to use the sensor based on the API of STMicroelectronics in the Arduino IDE. Interruptions on an Arduino are not usually necessary. However, since the ESPs support deep sleep, an interruption that could wake the micro controller up from a deep sleep would be useful.

Using the different micro controllers with the two libraries in this way has worked. We were also able to set the modes for the ranking profiles.

Due to the possible mutual interference of the acoustic distance sensors, the VL53L0X Time of Flight sensor is also a very good alternative for the obstacle detection of our robot cars.


Andreas Wolter.

for AZ-Delivery Blog

 

Esp-32Esp-8266For arduinoProduktvorstellungenProjects for beginnersSensors

1 comment

Walter

Walter

Hallo Andreas,
vielen Dank für deinen Bericht und deine Mühe.
Konstet Du ermitteln welchen Öffnungswinkel der Sensor besitzt?
Also z.b. bei einer Entfernung von 100 cm muss die Refektionsfläche (bei 90 grad) im minimum …? mm² betragen und was ist wenn sich der Winkel ändert?

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN