Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

VL53L0x and VL6180X libraries
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

VL53L0x and VL6180X libraries

by KurtE on Fri Jul 24, 2020 11:43 am

Not sure if here is the best place to ask and/or github issues (later PRs?) Sorry in advance if wrong place and/or I am too verbose and/or jump around a bit :D

Up on the PJRC Forum, a member has been trying to get 6 of your VL53... devices to work on a Teensy 3.5. Which I have been trying to assist him with. He is having an issue starting up the 2nd three of them. He is using the capability of starting up one at a time and changing their address: More details up on the thread: https://forum.pjrc.com/threads/61961-In ... Teensy-3-5

Yesterday I remembered that some of this looked familiar as a year or two ago I purchased 3 of your VL6180 to play with on a Turtlebot3. At the time I was experimenting with them using your TCA9548A I2C expander. But I wondered if it makes sense to use the change I2C address..

So I looked at both libraries and find they their implementation very different.

With my first quick look through these libraries, some questions come to mind, including:

a) are these devices enough alike that they should have a common library (or at least base class) to allow you to mix and match them? I can see cases like the hexapod I am playing with that maybe I want a closer range one on each leg to maybe play with seeing where ground or obstacle might be, and maybe some of the longer range ones, in logical front and rear to to maybe know if we are coming up to something..

b) Does the VL6180X support changing the ID in same way as VL53... Currently there are no methods in it's calls (like option to begin or setAddress method).

c) Neither exported class shows any possible capability to do the ranging that does not wait for the range/ping to complete. So for example if I wish to ping all 6 units, and if each one takes n MS than this will take 6 times n... So does it make sense to have a version of API that maybe breaks this up into parts.

That is internally you call VL53L0X_PerformSingleRangingMeasurement, which calls a few more internal functions including: VL53L0X_PerformSingleMeasurement and that function calls: VL53L0X_StartMeasurement
and then VL53L0X_measurement_poll_for_completion
It feels like this would be a good natural break into a set of methods to allow you to start an operation and then query for it to be done and/or wait for it to be done.

c1) I believe there are other options as well, like maybe continuous ranging? Maybe interrupt on completion? Again how much makes sense to expose?

d) the class Adafruit_VL53L0X has a public data member (VL53L0X_Error Status)
That I am not sure how/if this is ever set. At first I thought maybe in Adafruit_VL53L0X::getSingleRangingMeasurement
Which sets and returns status, BUT, it defined a local copy of it: VL53L0X_Error Status = VL53L0X_ERROR_NONE;
Note: obviously the test a few lines down of: if (Status == VL53L0X_ERROR_NONE) {
is not needed as you just set initialized it to that value.

Also could easily combine the two tests for if(debug) into one...

d1) Side note question: in the dual sample - it is unclear are you gaining anything by having measure1 and measuer2. Do they need to be global, i.e. is there anything saved in them from call to call? Or could the read_dual_sensors just as easily been:
Code: Select all | TOGGLE FULL SIZE
void read_dual_sensors() {
  VL53L0X_RangingMeasurementData_t measure;
  lox1.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

  // print sensor one reading
  Serial.print("1: ");
  if(measure.RangeStatus != 4) {     // if not out of range
    Serial.print(measure.RangeMilliMeter);
  } else {
    Serial.print("Out of range");
  }
 
  Serial.print(" ");

  lox2.rangingTest(&measure, false); // pass in 'true' to get debug data printout!
  // print sensor two reading
  Serial.print("2: ");
  if(measure.RangeStatus != 4) {
    Serial.print(measure.RangeMilliMeter);
  } else {
    Serial.print("Out of range");
  }
 
  Serial.println();
}


e) The VL6... library has a lot less details of the underlying ST stuff, make sense to add more?

f) The other question to myself is this the best starting place or does more sense to start with a different set of libraries, such as the ones from pololu? Yours has the advantage of being setup for different Wire objects, but theirs so far appears to expose more ...

Thoughts? And again sorry for rambling.

Thanks,

Kurt
P.S - I have 4 of the VL53... on order from Amazon (Some generics) Would have ordered some direct but PMB....

KurtE
 
Posts: 27
Joined: Fri Apr 25, 2014 8:10 pm

Re: VL53L0x and VL6180X libraries

by KurtE on Fri Jul 24, 2020 4:52 pm

Update:
b) Does the VL6180X support changing the ID in same way as VL53... Currently there are no methods in it's calls (like option to begin or setAddress method).

I added new methods to get and set the address, Issued PR (fixed the PR)... And it now has been merged :D

KurtE
 
Posts: 27
Joined: Fri Apr 25, 2014 8:10 pm

Re: VL53L0x and VL6180X libraries

by KurtE on Fri Jul 24, 2020 10:46 pm

Another quick update:
Code: Select all | TOGGLE FULL SIZE
c) Neither exported class shows any possible capability to do the ranging that does not wait for the range/ping to complete. So for example if I wish to ping all 6 units, and if each one takes n MS than this will take 6 times n... So does it make sense to have a version of API that maybe breaks this up into parts.

That is internally you call VL53L0X_PerformSingleRangingMeasurement, which calls a few more internal functions including: VL53L0X_PerformSingleMeasurement and that function calls: VL53L0X_StartMeasurement
and then VL53L0X_measurement_poll_for_completion
It feels like this would be a good natural break into a set of methods to allow you to start an operation and then query for it to be done and/or wait for it to be done.

Since I have VL6180X (the VL53... arrive next week) - I added some Async calls:
Where I was able to overlap the ranging of 3 sensors, example in sketch:
Code: Select all | TOGGLE FULL SIZE
void timed_async_read_sensors() {
  uint32_t start_time = millis();

  // lets start up all three
  lox1.startRange();
  lox2.startRange();
  lox3.startRange();
 
  // wait for each of them to complete
  lox1.waitRangeComplete();
  lox2.waitRangeComplete();
  lox3.waitRangeComplete();
 
  uint8_t range_lox1 = lox1.readRangeResult();
  uint8_t status_lox1 = lox1.readRangeStatus();
  uint8_t range_lox2 = lox2.readRangeResult();
  uint8_t status_lox2 = lox2.readRangeStatus();
  uint8_t range_lox3 = lox3.readRangeResult();
  uint8_t status_lox3 = lox3.readRangeStatus();
  uint32_t delta_time = millis() - start_time;
  Serial.print(delta_time, DEC);
  Serial.print(" : ");
  if (status_lox1 == VL6180X_ERROR_NONE) Serial.print(range_lox1, DEC);
  else Serial.print("###");
  Serial.print(" : ");
  if (status_lox2 == VL6180X_ERROR_NONE) Serial.print(range_lox2, DEC);
  else Serial.print("###");
  Serial.print(" : ");
  if (status_lox3 == VL6180X_ERROR_NONE) Serial.print(range_lox3, DEC);
  else Serial.print("###");

  Serial.println();
 
}

It did appear to help speed up the time for reading the three sensors on an Teensy 4.1.
Pull Request done and merged

KurtE
 
Posts: 27
Joined: Fri Apr 25, 2014 8:10 pm

Re: VL53L0x and VL6180X libraries

by KurtE on Sat Jul 25, 2020 12:28 pm

I know I am probably just talking to myself (which is not unusual ;) )

Wondering if I should Pull Request up additional changes to example sketch with three sensors. This time I updated it to allow you to select IO pins to connect up to the GPIO pin of the sensor (INPUT_PULLUP) and it has one of the timed tests that starts up the three sensors and waits for each of them to pull down the IO pin to say the Range completed instead of me polling it...
The code for that test looks like:
Code: Select all | TOGGLE FULL SIZE
void timed_async_read_gpio() {
#ifdef GPIO_LOX1
  uint8_t range_lox1;
  uint8_t status_lox1;
  uint8_t range_lox2;
  uint8_t status_lox2;
  uint8_t range_lox3;
  uint8_t status_lox3;


  digitalWrite(TIMING_PIN, HIGH);
  uint8_t pending_sensors = 0x7;
  uint32_t start_time = millis();

  // lets start up all three
  lox1.startRange();
  lox2.startRange();
  lox3.startRange();

  while (pending_sensors && ((millis() - start_time) < 1000)) {
    if ((pending_sensors & 0x1) && !digitalRead(GPIO_LOX1)) {
      range_lox1 = lox1.readRangeResult();
      status_lox1 = lox1.readRangeStatus();
      pending_sensors ^= 0x1;
    }
    if ((pending_sensors & 0x2) && !digitalRead(GPIO_LOX2)) {
      range_lox2 = lox2.readRangeResult();
      status_lox2 = lox2.readRangeStatus();
      pending_sensors ^= 0x2;
    }
    if ((pending_sensors & 0x4) && !digitalRead(GPIO_LOX3)) {
      range_lox3 = lox3.readRangeResult();
      status_lox3 = lox3.readRangeStatus();
      pending_sensors ^= 0x4;
    }
  }
  uint32_t delta_time = millis() - start_time;
  digitalWrite(TIMING_PIN, LOW);
  Serial.print(delta_time, DEC);
  Serial.print("(");
  Serial.print(pending_sensors, DEC);
  Serial.print(") : ");
  if (status_lox1 == VL6180X_ERROR_NONE) Serial.print(range_lox1, DEC);
  else Serial.print("###");
  Serial.print(" : ");
  if (status_lox2 == VL6180X_ERROR_NONE) Serial.print(range_lox2, DEC);
  else Serial.print("###");
  Serial.print(" : ");
  if (status_lox3 == VL6180X_ERROR_NONE) Serial.print(range_lox3, DEC);
  else Serial.print("###");

  Serial.println();
#endif
}

Note: hopefully sometime late next week will try to do the same for VL53... Sensors, once I have them.

This does a pretty good job of reading all three sensors without taking much more time than 1 requires. And during that time the application can be doing something else... Could also setup to ISR with this, but would need to be careful not to do two Wire functions at same time...
screenshot.jpg
screenshot.jpg (9.97 KiB) Viewed 20 times

Note: The above is output from my Saleae Logic Analyzer using their new beta software.
The first two lines are the SCL/SDA of Wire, the next line of Logic analyzer output of pin 13, which is showing the whole time for the three reads, which in this case was about 14ms. The next three lines are the GPIO pins of the three sensors.

KurtE
 
Posts: 27
Joined: Fri Apr 25, 2014 8:10 pm

Please be positive and constructive with your questions and comments.