Near/Mid-field Distance

Ultrasonic rangefinders and infrared (IR) rangefinders used to be the only solution for detecting proximity of largish objects / bodies reasonably accurately. They are however plagued with many issues, such as: + Ultrasonic: It’s not very accurate + Multiple ultrasonic sensors firing away confuse each other + They occasionally suffer from ‘false positive’ or spiky readings – not a good scenario when small changes in measurements are needed + Ultrasonic: If the sensor faces out to a space beyond 4m, the chances of erratic readings are higher + IR: no good for outdoor (i.e. sunlit) scenarios

These days, we also have ToF (time of flight) laser IR rangefinders! Originally designed for the mobile smartphone industry (think proximity sensors used to detect if you have the handset held to your ear), these tiny sensors can now be fitted into smaller setups and achieve similar, if not slightly better performance compared to ultrasonic rangefinders. Since these use the I2C digital protocol to communicate back to microcontrollers, it is a lot simpler to connect hardware-wise. Code libraries are available to get started with the basics quickly. Like any I2C sensor, you need to connect the SDA/SCL lines:

While these do work outdoors, their IR nature means that direct sunlight scenarios are still not recommended. They will work better than IR rangefinders (laser vs LED), but plenty of testing is needed.

Sensor details: https://learn.adafruit.com/adafruit-vl53l0x-micro-lidar-distance-sensor-breakout/pinouts


Libraries Used

(learn how to import them in the Build IDE):


Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_VL53L0X.h>

#define VL53L0X_LOG_ENABLE 0
uint32_t _trace_level = TRACE_LEVEL_ALL;

#if defined(PARTICLE) && (SYSTEM_VERSION >= 0x00060000)
SerialLogHandler logHandler(LOG_LEVEL_ALL);
#endif

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

// how long between each log update? feel free to change this value,
// but this must not be anything less than 1000 milliseconds!
#define INTERVAL_BETWEEN_LOGS 5000

// initialise the timer
Timer dataTimer(INTERVAL_BETWEEN_LOGS, doDataUpdate);

// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();

// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;


// code in this setup function runs just once, when Photon is powered up or reset
void setup() {
    Serial.begin(9600);         // Open a connection via the Serial port / USB cable – useful for debugging

    if (!lox.begin()) {
        Serial.println("Failed to boot VL53L0X");
        while(1);
    }
    Serial.println("VL53L0X API Simple Ranging example\n\n");

    delay(5000);                // Common practice to allow board to 'settle' after connecting online

    dataTimer.start();
}

// code in this loop function runs forever, until you cut power!
// for the A/D blackbox, there is nothing to do in here because data updates are handled by our timer
void loop() {

}

// doDataUpdate runs every interval set in INTERVAL_BETWEEN_LOGS
void doDataUpdate() {
    // IMPORTANT: to prevent server overload, the Particle cloud can only accept
    // update rates of once per second, with the option to 'burst' 4 updates in a
    // second (but then you'll get blocked for the next 4 seconds). 'Ration' your
    // INTERVAL_BETWEEN_LOGS and the number of readings you are publishing; in our
    // default example, we are frugally using just 1 publish, by concatenating
    // all the data we want into a single publish statement

    // get ready to print out all states of the sensor
    String output = "";

    VL53L0X_RangingMeasurementData_t measure;

    lox.rangingTest(&measure, true); // pass in 'true' to get debug data printout!

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

        output = measure.RangeMilliMeter;
    } else {
        output = "e";
        Serial.println(" out of range ");
    }

    // prints this out the Serial port (coolterm) for us humans to verify and debug; comment the next line if you don't want to see it in Coolterm
    Serial.println(output);

    // finally, send it out (and have your IFTTT recipe ready to use it):
    Particle.publish("sensorData", output);
 }