Vl53L0x - compare values

Friends:

I am a professor doing research with undergraduates. I am turning to this forum because it seems MUCH more collegial, kind, helpful and thoughtful than any other forums which I have read. Here is the issue:

I am testing the Time-of-Flight board for a project and am unclear about inserting a delay value into the code that is based on distance measurements. In summary, at long distances an ERM is activated in one pattern, and at short distances it is activated in another pattern. I need a delay between activation patterns that is proportional to distance but have been unsuccessful. Sample code is inserted with comments. The problem is that the delay must be very short if the distance drops suddenly. I have been unsuccessful in doing so. Suggestions about how to code that DELAY?

Ideally, I’d like to compare a stored previous distance (“int inches”) with a new distance reading (“int new_inches”) but I have been unsuccessful. I would really appreciate specific suggestions of code syntax and placement.

Thanks in advance.

The portion of the sketch with the problem is noted by this line “//HERE IS THE PROBLEM PORTION**”

#include <Wire.h>
#include "Adafruit_VL53L0X.h"

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

int pin5 = 5;// to debug with LED
int ERM = 6;
int y = 10;

int inches;

void setup() {
  pinMode (pin5, OUTPUT);//to debug with LED
  Serial.begin(115200);


  // wait until serial port opens for native USB devices
  while (! Serial) {
    delay(1);
  }

  Serial.println(F("Adafruit VL53L0X test"));
  if (!lox.begin()) {
    Serial.println(F("Failed to boot VL53L0X"));
    while (1);
  }
  // power
  Serial.println(F("VL53L0X test\n\n"));
}


void loop() {
  VL53L0X_RangingMeasurementData_t measure;

  //Serial.print(F("Reading a measurement... "));
  lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

  if (measure.RangeStatus != 4) {  // phase failures have incorrect data
  }

  //This is the IF condition that activates the ERM at long distances
  // 24 to 60 inches away. Inches = mm*0.039.

  if (measure.RangeMilliMeter >= 600 && measure.RangeMilliMeter <= 1524) {

    int inches = (measure.RangeMilliMeter * 0.04); //convert mm to inches
    int PWM = ((-27 * log(inches)) + 250);

    for (int x = 0 ; x <= PWM; x += 4) {
      analogWrite( 6 , x );
      delay (y);
      analogWrite( 6 , 0 );
    }

    for (int x = PWM; x  >= 0; x -= 4) {
      analogWrite( 6 , x );
      delay (y);
      analogWrite( 6 , 0 );
    }

    Serial.print(F("long inches= "));
    Serial.println (inches);
    Serial.println ();
  }

  //At this point, the sketch needs to reassess the distance measurement and
  //DELAY between stimuli (the ISI or inter-stimulus delay) based on that
  //new distance (i.e., long for far away but very short if distance
  //has suddenly dropped. However I'm not sure how best to do this.

  //If the distance has dropped suddenly after the last assessment
  //here, I need to read a new distance measurement from the incoming data stream.
  //I tried creating a new variable to compare to previous inches but have been unsuccessful.
  //The IF conditional below is not working as I'd like. I need the delay to be short 
  //immediately if the distance drops suddenly but stay long if the 
  //distance stays long. Ideas on how to code this? 

  if (measure.RangeMilliMeter > 0 && measure.RangeMilliMeter < 600) {
    delay (50);
  }
  else if (measure.RangeMilliMeter > 600) {
    int inches = (measure.RangeMilliMeter * 0.04); // convert mm to inches
    int ISI01 = (151 * (exp(0.0732 * inches))); // calculate inter-stimulus interval #1
    delay (ISI01); //inter-stimulus #1
  }
  
  //This is the IF condition that activates the ERM at short distances
  // 0 to 24 inches away. Inches = mm*0.039.

  if (measure.RangeMilliMeter >= 0 && measure.RangeMilliMeter <= 600) {
    int inches = (measure.RangeMilliMeter * 0.04); // mm to inches
    int ISI02 = (151 * (exp(0.0732 * inches))); //e = 2.72; calculate ISI #2
    int PWM = ((-27 * log(inches)) + 250);

    Serial.print(F("short inches= "));
    Serial.println (inches);
    Serial.println ();

    analogWrite( 6 , PWM );
    delay (70);
    analogWrite( 6 , 0 );
    delay (ISI02)

  } // close if (measure.RangeMilliMeter 0-600)


  else {
    //Serial.print(F("waiting"));
    //Serial.println();
  }

} //closes Void loop




Hello.

Are you using one of our carrier boards? You are using Adafruit’s library rather than ours, and we aren’t very familiar with it, so we can’t offer much support for it. It looks like you might only be taking a measurement at the start of your main loop routine and I don’t see anywhere where you store that measurement for a comparison when the next measurement is taken (which would be necessary if you want to take some action based on the magnitude of the change). You might find it’s useful to use pseudocode or a flow-chart to work out your logic before implementing the full code to do it.

-Nathan

Nathan:

Thanks for the kind reply. I had worked through the logic but, clearly, I wasn’t seeing the best way to structure the arguments. I am transitioning to your products and have re-written the code logic as you suggested using your library (which seems more user friendly than the one I was using). Thanks for the advice.

My error is apparently corrected by placing the conditions for the post-stimulus delays after the conditions for the two distance assessments (near and far).

I have inserted the pseudocode. If you have criticisms or corrections to the logic, I’d be happy to hear them.

Thanks again, Frederick

// This example uses continuous mode with the VL53L0X library.
// It is based on vl53l0x_ContinuousRanging_Example.c
//from the VL53L0X API.
// The range readings are in mm converted to inches (mm *.039)

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  sensor.init();
  sensor.setTimeout(1000);

  // Start continuous back-to-back mode (take readings as
  // fast as possible).  To use continuous timed mode
  // instead, provide a desired inter-measurement period in
  // ms (e.g. sensor.startContinuous(100)).

  sensor.startContinuous(100); // slow this for debugging
  Serial.println (F("Let's begin!"));
  Serial.println();
}

void loop() {

  int inches  = ((sensor.readRangeContinuousMillimeters() * .04));// convert mm to inches
  if ((inches > 0) && (inches < 60)) {

    Serial.println ();
    Serial.println (F("THIS IS THE BEGINNING OF THE LOOP"));
    Serial.print (F("initial inches from the beginning of the void loop = "));
    Serial.println (inches);
    Serial.println ();

    if ((inches > 24) && (inches < 60)) {
      Serial.print (F("Inches are between 24 & 60, they = "));
      Serial.println (inches);
      Serial.println (F("Doing the FAR routine"));
      Serial.println ();
    }

    if ((inches > 0) && (inches <= 24)) {
      Serial.print(F("Inches are 0 to 24, they = "));
      Serial.println (inches);
      Serial.println (F("do the SHORT routine"));
      Serial.print(F("implement a SHORT delay based on distance"));
      Serial.println ();
    }

    int changedInches = ((sensor.readRangeContinuousMillimeters() * .04));
    Serial.print(F("Assess another distance measurement...CHANGED INCHES = "));
    Serial.println(changedInches);
    Serial.println ();

    if (changedInches < inches) {
      Serial.println(F("CHANGED INCHES is SMALLER than original INCHES"));
      Serial.println(F("Object is CLOSER"));
      Serial.print(F("implement a SHORT delay based on distance"));
      Serial.println();
    }
    else if (changedInches >= inches) {
      Serial.println(F("CHANGED INCHES is EQUAL or LARGER than original INCHES"));
      Serial.println(F("Object is at same distance or moved FARTHER AWAY"));
      Serial.println(F("implement a LONG delay based on distance"));
      Serial.println();
    }

     if (sensor.timeoutOccurred()) {
      Serial.print(F("TIMEOUT"));
      Serial.println();
    }
  }
  delay (1);

}

Hello, Frederick.

That seems like a good start. If you need to do things concurrently (like continue to take measurements while turning on and off your output pin in a specific pattern), you might look at the “Blink Without Delay” example Arduino sketch. In your loop, you would have a few different variables to keep track of when it’s time to turn things on, off, or take another measurement and then have a few blocks of if statements to check current time and execute the appropriate action.

-Nathan

Nathan:

Thanks! (You all are so nice on this forum!)

I have placed all of the real code into the new format and all works just as anticipated. Your next – very good—suggestion regarding using millis() is spot on; I do have a one problem with the code to solve that is a result of using “delay”. If the distance to an object is FAR and a LONG delay is used, it stops the program from responding during that delay, as you noted. By the time the delay is over, the object could have collided with the sensor if it approaches quickly. So, rather than using a delay, an interval would be preferable. But, it’s not clear to me precisely how that would be implemented. This is because if I am getting signals infrequently when an object is FAR away and frequent signals if an object is CLOSE, it’s not clear to me how to link (logically) the time intervals, “millis()” to the distances. “inches”. It seems that I would have to assess velocity and direction. For instance, on an ongoing basis, if OLD_DISTACE minus NEW_DISTANCE is positive (object is approaching) and its ratio to OLD_millis() minus NEW_millis() is over some THRESHOLD (velocity is over threshold), then activate a signal. Otherwise, if there is no object approach, or velocity is low, do not signal. Make sense?

The only problem, for which I am not seeing a solution as yet, is altering the frequency of the signal as distances shorten. I am currently using non-linear functions to alter the frequency by manipulating delays (and also PWM’s or signal strength); for instance, shortDelay = (151 * (exp(0.0732 * changedInches)));
So, if you have a thought regarding an approach to using millis(), please let me know. I am going to take your suggestion and brainstorm… or maybe it’ll just be a drizzle.

Thanks again, Frederick

Hi, Frederick.

This Adafruit tutorial might have be helpful if you are still having troubles:

-Nathan

Thank you very much, Nathan. I am still working on this sketch. There is some simple point of logic that I am missing in the code that I am constructing. I understand what I went to do and preliminary sketches work. The simplistic logic is this:

Measure distance continuously
A long as distance stays FAR do #1 at a slow rate
As long as distance is NEAR do #2 at a fast rate

The characteristics of #1 and #2 (PWM & duration) change non-linearly as distance changes. I’ve had no problem writing the program using except that it stops the continuous measurements. I haven’t quite figured out how to factor in millis() successfully as yet.

The issue is that if #1 is being executed and distance falls to NEAR during the inter-event interval (intervals between #1 events), I need #2 to be executed immediately even if the interval between #1’s has not finished. Make sense? Suggestion?

I will re-read the example that you suggest, Thanks again. I am sure that I will have another question on this one!

You are not alone.