Read multiple VL53L1X with master/slave configuration

Hello guys,

I'm trying to read the data from 6 distance sensors (VL53l1X) more or less at the same time. First thing I tried is too hook all sensors up to one mega, but that isnt an option because it takes way too long to read the sensors one after another, since no parallel code execution is possible.
So I thought I could hook up each sensor to an individual nano(as slaves) and then give a go command from the master(mega) for taking a messurement. This way they should take the messurements at the same time, because each one is running on a separate hardware, and I then wanted to transmit the data over I2C back to the master (using Wire.h) for further actions.
The problem is that the distance sensors already transmit their messurement data using I2C and since I need to connect the slaves with the master over I2C aswell all sensors would end up using the same I2C which would lead to interferenences.

Is there a way to solve my problem using I2C? or maybe an alternative?
I dont need the data from the sensors in real time, but they have to be taken at the same time(up to 50ms difference is fine I guess). So e.g. I could save them on a sd card, but then I'd also need 6 sd card modules, for each nano one, and it's a really shitty solution.

Appreciating any help :slight_smile:

I then wanted to transmit the data over I2C back to the master (using Wire.h) for further actions.

Why I2C? Why not SPI (for very short distances) or RS-485 (for longer distances)? BTW, if you think I2C on the Mega is too slow, why should it be faster to have many Nanos in between?

irst thing I tried is too hook all sensors up to one mega, but that isnt an option because it takes way too long to read the sensors one after another, since no parallel code execution is possible.

How did you connect all together on the same I2C bus? The sensor has a fixed I2C address.

I dont need the data from the sensors in real time, but they have to be taken at the same time(up to 50ms difference is fine I guess). So e.g. I could save them on a sd card, but then I'd also need 6 sd card modules, for each nano one, and it's a really shitty solution.

Please explain your project. You have to get the distance from 6 sensors within 50ms just to store them on an SD card? Doesn't really make sense to me. What are you trying to achieve?

Thanks for trying to help me!

pylon:
Why I2C? Why not SPI (for very short distances) or RS-485 (for longer distances)? BTW, if you think I2C on the Mega is too slow, why should it be faster to have many Nanos in between?

To be honest I'm not familiar with all the possible communications.If I can take something else then I2C which works then I'm fine with it. But I also need an sd-card module which uses SPI right? But I can still let the masters and slaves communicate through SPI then? I dont need any long distances, the sensors are max. 20 cm away from each other.
With the nanos as slaves, which just speak to one sensor each, it should get faster because then they can take the messurements at the exact same time (because multiple hardware are running in parallel). With just the mega I had to make them one after another which causes a delay of about 300 ms between first and last messurement (not acceptable for my case).
A messurement of the sensor takes 33 ms, so I cant get below that for sure.

pylon:
How did you connect all together on the same I2C bus? The sensor has a fixed I2C address.

The sensor has a shutdown pin. When starting them again I can set individual addresses

I'll explain the project a bit more, trying to keep it short:
I want to mount the distance sensors to a sphere (front, back, left hand side, right hand side, top , bottom). Then I'm putting the sphere in a known environment (means I know exactly how the track looks like) and want to locate the sphere with the combination of values of the distance sensors on that track (without any infrastructure). This combination of distances will be unique in my track, so that I can theoretically localize the absolute position of the sphere.
Because the sphere is spinning (very slowly, bit still moving) I need to get the messurements best case scenario at exactly the same time so that the quality of my dataset for the mapping part will be good.I want to save the data on a sd card because the mapping would be too demanding for the mega to calculate. So I want to run a program on a pc which does that with the data from the sd card(not in real time).
For another purpose I also have an IMU (BNO055) which should also write it's data on the sd card. And the question is if I can get this all running together and in which way.

I dont need any long distances, the sensors are max. 20 cm away from each other.

That's quite a long distance for either SPI or I2C. The maximum bus length is about 50cm, with SPI and slower wire speeds you may reach 1m if you shield the cable.

With the nanos as slaves, which just speak to one sensor each, it should get faster because then they can take the messurements at the exact same time (because multiple hardware are running in parallel)

In theory this is correct but how do you synchronize all the Nanos?

With just the mega I had to make them one after another which causes a delay of about 300 ms between first and last messurement (not acceptable for my case).

How did you calculate the delay? You can start the measuring process on all sensors within a few milliseconds and later collect all the measured values.

pylon:
The maximum bus length is about 50cm, with SPI and slower wire speeds you may reach 1m if you shield the cable.

The sphere’s radius will be <20 cm so if the microcontroller is in the middle about 10 cm to each sensor, so that shouldnt be a problem.

pylon:
In theory this is correct but how do you synchronize all the Nanos?

I thought I can just set a pin to high (from the master) and let the nanos check when this happens and react to it.

pylon:
How did you calculate the delay?

After each messurement I took a timestamp and then checked the difference between the first and last result. Since the sensors need 33 ms for a messurement, I have at least 5*33=165 ms between the first and last result, but I calculated about 280-300 ms.Either way that’s too long

pylon:
You can start the measuring process on all sensors within a few milliseconds and later collect all the measured values.

How exactly can I do that?You mean all through I2C? How can I ensure I wont have intereferences when they try to give me the messurements back?

The sphere’s radius will be <20 cm so if the microcontroller is in the middle about 10 cm to each sensor, so that shouldnt be a problem.

It’s not a definite show-stopper but you would be at the limit.

I thought I can just set a pin to high (from the master) and let the nanos check when this happens and react to it.

That’s a possible solution but needs another wire to every Nano.

After each messurement I took a timestamp and then checked the difference between the first and last result. Since the sensors need 33 ms for a messurement, I have at least 5*33=165 ms between the first and last result, but I calculated about 280-300 ms.Either way that’s too long

The measurement is started with a command over I2C. The chip sets GPIO1 low when the measurement value is available. In the meantime you can send the start measurement command to the other chips.

How exactly can I do that?You mean all through I2C? How can I ensure I wont have intereferences when they try to give me the messurements back?

The chip doesn’t send the results, the master has to request it and it has to request it from every chip. As you already have connected six of the sensors you must have some kind of multiplexer in place otherwise you cannot connect more than one sensor. What did you use for the time the measurements if you request one value after the other?

pylon:
The measurement is started with a command over I2C. The chip sets GPIO1 low when the measurement value is available. In the meantime you can send the start measurement command to the other chips.

ok, understood. but the nano also gets it’s data from the VL53l1X through I2C, isnt that a problem?since the nano is connected with the master through I2C, doesnt that mean all sensors are using the same I2C and I wouldnt have any advantage using 6 nanos instead of just the mega?

pylon:
What did you use for the time the measurements if you request one value after the other?

the library just comes with a read function you can call to get the messurements from the sensor.This was the code I was using:

#include <Wire.h>
#include <VL53L1X.h>

#define XSHUT_pin1 32
#define XSHUT_pin2 34
#define XSHUT_pin3 36
#define XSHUT_pin4 38
#define XSHUT_pin5 40
#define XSHUT_pin6 42

//ADDRESS_DEFAULT 0b0101001 or 41
#define Sensor1_newAddress 43 
#define Sensor2_newAddress 45
#define Sensor3_newAddress 47
#define Sensor4_newAddress 49
#define Sensor5_newAddress 51
#define Sensor6_newAddress 53

VL53L1X Sensor1;
VL53L1X Sensor2;
VL53L1X Sensor3;
VL53L1X Sensor4;
VL53L1X Sensor5;
VL53L1X Sensor6;

void setup()
{ 

  pinMode(XSHUT_pin1, OUTPUT);
  pinMode(XSHUT_pin2, OUTPUT);
  pinMode(XSHUT_pin3, OUTPUT);
  pinMode(XSHUT_pin4, OUTPUT);
  pinMode(XSHUT_pin5, OUTPUT);
  pinMode(XSHUT_pin6, OUTPUT);
  
  Serial.begin(9600);
  
  Wire.begin();
  Wire.setClock(100000); 


  pinMode(XSHUT_pin1, INPUT);
     if (!Sensor1.init())
  {
    Serial.println("Failed to detect and initialize sensor1!");
    while (1);
  }
  delay(10);
  Sensor1.setAddress(Sensor1_newAddress);

 pinMode(XSHUT_pin2, INPUT);
     if (!Sensor2.init())
  {
    Serial.println("Failed to detect and initialize sensor2!");
    while (1);
  }
  delay(10);
  Sensor2.setAddress(Sensor2_newAddress);
  
  pinMode(XSHUT_pin3, INPUT);
     if (!Sensor3.init())
  {
    Serial.println("Failed to detect and initialize sensor3!");
    while (1);
  }
  delay(10);
  Sensor3.setAddress(Sensor3_newAddress);

   pinMode(XSHUT_pin4, INPUT);
     if (!Sensor4.init())
  {
    Serial.println("Failed to detect and initialize sensor4!");
    while (1);
  }
  delay(10);
  Sensor4.setAddress(Sensor4_newAddress);

  pinMode(XSHUT_pin5, INPUT);
     if (!Sensor5.init())
  {
    Serial.println("Failed to detect and initialize sensor5!");
    while (1);
  }
  delay(10);
  Sensor5.setAddress(Sensor5_newAddress);

  pinMode(XSHUT_pin6, INPUT);
     if (!Sensor6.init())
  {
    Serial.println("Failed to detect and initialize sensor6!");
    while (1);
  }
  delay(10);
  Sensor6.setAddress(Sensor6_newAddress);

  
  Sensor1.setTimeout(500);
  Sensor2.setTimeout(500);
  Sensor3.setTimeout(500);
  Sensor4.setTimeout(500);
  Sensor5.setTimeout(500);
  Sensor6.setTimeout(500);


  
  Sensor1.setDistanceMode(VL53L1X::Medium);
  Sensor1.setMeasurementTimingBudget(33000);
  Sensor2.setDistanceMode(VL53L1X::Medium);
  Sensor2.setMeasurementTimingBudget(33000);
  Sensor3.setDistanceMode(VL53L1X::Medium);
  Sensor3.setMeasurementTimingBudget(33000);
  Sensor4.setDistanceMode(VL53L1X::Medium);
  Sensor4.setMeasurementTimingBudget(33000);
  Sensor5.setDistanceMode(VL53L1X::Medium);
  Sensor5.setMeasurementTimingBudget(33000);
  Sensor6.setDistanceMode(VL53L1X::Medium);
  Sensor6.setMeasurementTimingBudget(33000);

}


void loop()
{
   Sensor1.startContinuous(200);
   Sensor1.read();
   Sensor1.stopContinuous();
   long time1 = millis();
   Sensor2.startContinuous(200);
   Sensor2.read();
   Sensor2.stopContinuous();
   Sensor3.startContinuous(200);
   Sensor3.read();
   Sensor3.stopContinuous();
   Sensor4.startContinuous(200);
   Sensor4.read();
   Sensor4.stopContinuous();
   Sensor5.startContinuous(200);
   Sensor5.read();
   Sensor5.stopContinuous();
   Sensor6.startContinuous(200);
   Sensor6.read();
   Sensor6.stopContinuous();
   long time2 = millis();
   
   
  Serial.print("Sensor 1 Range: ");
  Serial.print(Sensor1.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print("Sensor 2 Range: ");
  Serial.print(Sensor2.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print("Sensor 3 Range: ");
  Serial.print(Sensor3.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print("Sensor 4 Range: ");
  Serial.print(Sensor4.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print("Sensor 5 Range: ");
  Serial.print(Sensor5.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print("Sensor 6 Range: ");
  Serial.print(Sensor6.ranging_data.range_mm);
  Serial.print(" ");
  Serial.print(" Time between end of 1st and end of 6th messurement: ");
  Serial.print(time2-time1);

  
  Serial.println();

  delay(1000);
}

ok, understood. but the nano also gets it's data from the VL53l1X through I2C, isnt that a problem?since the nano is connected with the master through I2C, doesnt that mean all sensors are using the same I2C and I wouldnt have any advantage using 6 nanos instead of just the mega?

In that setup, there is no Nano. All sensors are connected to the Mega by a bus multiplexer.

Your solution with the XSHUT pin is also possible but then you get a much longer bus length.

so basically it would be the same setup I already had, but instead of reading the values from the sensor one by one I first send all start commands and after that I read the data from them one by one, when it isnt time critical anymore.
but how can I messure at what time the sensor made their messurements? until now I just set a time stemp after I received data, but that wouldnt be accurate anymore with the new scenario.

It might be the time to describe in more detail what exactly you're trying to achieve.

You have several possibilities to get a more or less exact time stamp. Connect every GPIO1 output with the appropriate circuit to an Arduino pin and use the pin change interrupt to capture the exact time when the measurement was finished.

Or store the time differences of the start measurement commands, time stamp the arrival of the first sensor measurement complete, then add the stored time differences to get the time stamps of the other sensors. That solution is a bit less exact than the first one but depending on the application you would even have to correct the time stamps of the first method as the interrupt is called when the first measurement is available for read, not when it happened. You might have to make laboratory tests to find the exact time of the measurement.