cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L4CD - Signal is below the defined threshold

DrD00m
Associate III

Hey,

I have a custom made board/device which is using 4x VL53L4CD Tof Sensors to measure the distance. I have trouble to calibrate the sensors correctly or get correct values from them from time to time. Sometimes it works well - sometimes it does not.
What I can see is, that for sensor where the distance is not accurate I am receiving the result status " Signal is below the defined threshold", as described in the datasheet.
What exactly does that mean and how can I fix that? What is causing this issue?

The signal threashold is set to 5000 and the sigma is set to be 10.

I noticed when I am running the offset and xtalk calibration - this issue can disappear but it takes multiple calibration iterrations and sometimes it does not fix the problem.

 

And as well: what exactly is a 17% reflective material!? (as mentioned in the datasheet to calibrate offset and xtalk)

27 REPLIES 27
DrD00m
Associate III

I am pretty sure something is wrong with the sensors. I tried to run the Arduino example code again and made it work.

 

#include <Arduino.h>
#include <Wire.h>
#include <vl53l4cd_class.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

#define DEV_I2C Wire
#define SerialPort Serial


// Components.
VL53L4CD sensor_vl53l4cd_sat1(&DEV_I2C, 47);
VL53L4CD sensor_vl53l4cd_sat2(&DEV_I2C, 17);
VL53L4CD sensor_vl53l4cd_sat3(&DEV_I2C, 5);
VL53L4CD sensor_vl53l4cd_sat4(&DEV_I2C, 8);

/* Setup ---------------------------------------------------------------------*/

void setup()
{

  // Initialize serial for output.
  SerialPort.begin(115200);
  SerialPort.println("Starting...");

  // Initialize I2C bus.
  DEV_I2C.begin(38, 48);

  // Configure VL53L4CD satellite component.
  sensor_vl53l4cd_sat1.begin();
  sensor_vl53l4cd_sat2.begin();
  sensor_vl53l4cd_sat3.begin();
  sensor_vl53l4cd_sat4.begin();

  // Switch off VL53L4CD satellite component.
  sensor_vl53l4cd_sat1.VL53L4CD_Off();
  sensor_vl53l4cd_sat2.VL53L4CD_Off();
  sensor_vl53l4cd_sat3.VL53L4CD_Off();
  sensor_vl53l4cd_sat4.VL53L4CD_Off();

  //Initialize VL53L4CD satellite component.
  sensor_vl53l4cd_sat1.InitSensor(43);
  sensor_vl53l4cd_sat2.InitSensor(44);
  sensor_vl53l4cd_sat3.InitSensor(45);
  sensor_vl53l4cd_sat4.InitSensor(46);

  // Program the highest possible TimingBudget, without enabling the
  // low power mode. This should give the best accuracy
  sensor_vl53l4cd_sat1.VL53L4CD_SetRangeTiming(80, 120);
  sensor_vl53l4cd_sat2.VL53L4CD_SetRangeTiming(80, 120);
  sensor_vl53l4cd_sat3.VL53L4CD_SetRangeTiming(80, 120);
  sensor_vl53l4cd_sat4.VL53L4CD_SetRangeTiming(80, 120);

  // Start Measurements
  sensor_vl53l4cd_sat1.VL53L4CD_StartRanging();
  sensor_vl53l4cd_sat2.VL53L4CD_StartRanging();
  sensor_vl53l4cd_sat3.VL53L4CD_StartRanging();
  sensor_vl53l4cd_sat4.VL53L4CD_StartRanging();
}

void loop()
{
  uint8_t NewDataReady = 0;
  VL53L4CD_Result_t results1;
  VL53L4CD_Result_t results2;
  VL53L4CD_Result_t results3;
  VL53L4CD_Result_t results4;
  uint8_t status;
  char report[64];


  sensor_vl53l4cd_sat1.VL53L4CD_ClearInterrupt();
  sensor_vl53l4cd_sat1.VL53L4CD_GetResult(&results1);
  snprintf(report, sizeof(report), "S1[%2u] Distance = %4u mm | ",
          results1.range_status,
          results1.distance_mm,
          results1.signal_per_spad_kcps);
  SerialPort.print(report);

  sensor_vl53l4cd_sat2.VL53L4CD_ClearInterrupt();
  sensor_vl53l4cd_sat2.VL53L4CD_GetResult(&results2);
  snprintf(report, sizeof(report), "S2[%2u] Distance = %4u mm | ",
            results2.range_status,
            results2.distance_mm,
            results2.signal_per_spad_kcps);
  SerialPort.print(report);

  sensor_vl53l4cd_sat3.VL53L4CD_ClearInterrupt();
  sensor_vl53l4cd_sat3.VL53L4CD_GetResult(&results3);
  snprintf(report, sizeof(report), "S3[%2u] Distance = %4u mm | ",
            results3.range_status,
            results3.distance_mm,
            results3.signal_per_spad_kcps);
  SerialPort.print(report);

  sensor_vl53l4cd_sat4.VL53L4CD_ClearInterrupt();
  sensor_vl53l4cd_sat4.VL53L4CD_GetResult(&results4);
  snprintf(report, sizeof(report), "S4[%2u] Distance = %4u mm | \r\n",
            results4.range_status,
            results4.distance_mm,
            results4.signal_per_spad_kcps);
  SerialPort.print(report);

  delay(250);
}

 

 As you can see I initialise all 4 sensors and read there distance value. It is printing the following line:

S1[ 4] Distance = 1879 mm | S2[ 4] Distance = 1804 mm | S3[ 4] Distance = 1804 mm | S4[ 4] Distance = 1822 mm | 

Even the second sensor is working just fine here. BUT - and this is increadibly strange - sensor 2 and 3 always showing the exact same values. If I put my finger ontop of sensor 2, sensor 3 shows the same changes and the other way around. This is super strange.
I then changed the I2C addreses for all sensors from the above to be:

sensor_vl53l4cd_sat1.InitSensor(43);
sensor_vl53l4cd_sat2.InitSensor(45);
sensor_vl53l4cd_sat3.InitSensor(47);
sensor_vl53l4cd_sat4.InitSensor(49);

I basically just increased the address by 2 instead of 1 and now both ssensors show different values. How can this be? This is clearly an issue with the sensors and I am pretty sure this is the reason why my code does not work either. I tried to also change the I2C Addresses in my toit code but it was not fixing the problems.

John E KVAM
ST Employee

Don't get me started on how bad that I2C bus is, but you found your issue. And it's a sneaky one. 

A USB address consists of a 7-bit address and a write/read bit. 

At boot the ToF sensors are at address 0x29 - which is the 7-bit number. 

To write to the chip, one shifts the 0x29 left by one = 0x52 and then sets the LSB to 0.

To read from the chip, set the LSB to one and you get 0x53. 

So, each USB device, has in effect, and address pair. 

But it seems silly to keep doing that shift by one all the time, so some drivers reference the chip by its 8-bit address. 

Your seeming duality was in fact, just that. Address 0x52 and 0x53 are addresses to the same chip. 

And that is why some returned the same number. You were reading the same chip twice. 

Sorry I did not spot that sooner. I should have. I've been there; done that. 

-john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

Do you have any explanation for the interrupt which can not be cleared? Did you had a chance to check the code?
I am currently in the installation phase of my hardware and I am about to swap the sensor because I am pretty sure it is an issue of this sensor not being able to communicate properly via I2C. 

You mentioned that the interrupt should only trigger if there was a valid distance reading, but I get interrupts when it is actually reading 0 mm. After it initialises the sensor I have the GPIO for the interrupt LOW which triggers the interrupt code which then clears that interrupt but it never gets cleared. 

I did change the I2C addresses now to be 20, 30, 40 and 50. 
Which are 0x14, 0x1e, 0x28, 0x32

 

Is there any way to get a call and talk to someone here? I can not get anywhere with this.

@John E KVAM it would be nice to get a littlebit better and faster support here. is that possible?

The I2C Address issue from earlier does not fix the problem with the sensors.
Didn't you said, that the sensor should not give back 0mm?

I see 0mm often on this sensors. Whenever it was 0 I was printing all data:

Sensor VL53_2 [0x1e]
Distance: 1651 mm [✗ Error: Phase out of valid limit]
Distance: 1871 mm [✗ Error: Phase out of valid limit]
Distance: 1666 mm [✗ Error: Phase out of valid limit]
Distance: 1903 mm [✗ Error: Phase out of valid limit]
Distance: 1661 mm [✗ Error: Phase out of valid limit]
Distance: 1867 mm [✗ Error: Phase out of valid limit]
Distance: 1647 mm [✗ Error: Phase out of valid limit]
Distance: 1888 mm [✗ Error: Phase out of valid limit]
Distance: 1661 mm [✗ Error: Phase out of valid limit]
Distance: 1875 mm [✗ Error: Phase out of valid limit]
Result: SPAD=203,   Signal=592,   Ambient=392,   Sigma=8,  Distance=0,  Signal/SPAD=2,  Ambient/SPAD=1 | ✗ Error: Phase out
 of valid limit
Distance:    0 mm [✗ Error: Phase out of valid limit]
Distance: 1876 mm [✗ Error: Phase out of valid limit]
Distance: 1669 mm [✗ Error: Phase out of valid limit]
Distance: 1879 mm [✗ Error: Phase out of valid limit]
Distance: 1661 mm [✗ Error: Phase out of valid limit]
Distance: 1896 mm [✗ Error: Phase out of valid limit]
Distance: 1667 mm [✗ Error: Phase out of valid limit]
Distance: 1894 mm [✗ Error: Phase out of valid limit]
Result: SPAD=203,   Signal=616,   Ambient=376,   Sigma=7,  Distance=0,  Signal/SPAD=3,  Ambient/SPAD=1 | ✗ Error: Phase out
 of valid limit
Distance:    0 mm [✗ Error: Phase out of valid limit]
Distance: 1882 mm [✗ Error: Phase out of valid limit]
Result: SPAD=203,   Signal=648,   Ambient=368,   Sigma=7,  Distance=0,  Signal/SPAD=3,  Ambient/SPAD=1 | ✗ Error: Phase out
 of valid limit
Distance:    0 mm [✗ Error: Phase out of valid limit]
Distance: 1865 mm [✗ Error: Phase out of valid limit]
Distance: 1664 mm [✗ Error: Phase out of valid limit]
Distance: 1894 mm [✗ Error: Phase out of valid limit]
Distance: 1662 mm [✗ Error: Phase out of valid limit]

 The setup has not changed - the device is still pointing towards my ceiling without any other object close by.
Why do they return 0 mm as distance here?

Somehow this seems a bit odd as well. Because if I calculate that in a excel table I do not see any collision here:

DrD00m_0-1714989152269.png

There is and should be no collision? Is this a bug in your sensors?
I only had this issue with Sensor 2 and 3 (43 and 44) but based on your answer this should have happened to all 4 sensors then. 


John E KVAM
ST Employee

You are of course correct. If one uses the 7-bit base address, they can go up by one. 

So that wasn't it. 

Let's talk about:

Distance: 1651 mm [✗ Error: Phase out of valid limit]

 This happens when the two sub-ranges do not match. 

We use two sub-ranges with different Pulse Repetition Intervals (PRI) to prevent something called radar aliasing or wrap-around. Aliasing happens when a target is past the max distance the sensor can range. The photons from pulse N were received AFTER pulse N+1 got sent out. So, a target at 4.2Meters would be detected at 0.4Meters. 

With two different PRI we can detect this condition. But it can be caused by other things. 

Motion can cause the two sub ranges to disagree - but both are valid. 

A weak return signal can cause one range to fail, and the other pass. 

In your case that ceiling is just bright enough that it's detected by one on the ranges, but not the other.  

You might increase your timing budget. This will allow both ranges to pass and you'd get better accuracy. 

I still don't know what is going on. Perhaps covering the some of the sensors with bits of paper to determine it there is some interaction we don't understand?

- john


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

@John E KVAM Why do you think this is an issue? 
It measure the correct distance more or less but the ceiling is clearly out of the range (the spec says 1.3m). So this is fine, right?

I would be more interested, why it shows 0mm some times even tho I do not change anything on the setup. 
We discovered aglitch yesterday on the data line.

image.png

 This should not be there I think. I changed the pull-up resistor on one of the boards to be 4.7k instead of 2.2k and the spike was gone. But also reducing the I2C speed from 400kHz to 300kHz made this spike disappear. Not sure what is causing this spike tho but I think it is coming from the ESP32-S3. 

Since then I did not had the problem with a sensor being stuck in the interrupt.

 

But still this value 0mm is strange. The sensor measures the distance in default mode to determine a threshold, then sets the sensor into low power mode and sets this threshold to be interrupted when below. 
To do so I measure 25 times and take the average of that measurment. So far this worked pretty well but if the sensor sends 0mm the average will be wrong. I even had the situation where the sensor was sending only 0mm.
So what is the default behavior of the sensor or how should I handle such situations? 
Should I ignore 0mm values? 
I do not mind that while measuring the distance, if there is no object. That can happen if the sensor points into nothingness - then I will set the threshold to be 1300mm anyway. But should the sensor give me a value every time or 0mm a valid measurment? This is what I still don't understand

DrD00m
Associate III

@John E KVAM I got the issue again where the sensor never clears its interrupt no matter what I do. 
This can only be solved by removing power entirly from the board (and therefor from the sensor) and restarting it. Somehow the Sensor can be stuck in this very strange state where it delivers bad values like below 200 even tho the next object (my ceiling) is 1800mm away combined with the interrupt which can not be cleared.
The interrupt is LOW immediately.

I don't know how the sensor can be brought into this state and I also don't know why this is always only on sensor 2 of my 4 sensors where all running the same code-path. 
Electrically the board looks fine. I think this is an I2C timing issue because adding 5ms after each i2c write, lowering the communication speed from 400kHz to 300kHz and also wait ~1s after each sensor initialisation seem to help somehow. 

Any idea what could cause this on the sensor?