Skip to Content

VL53L0X/TOF0200C Sensore di Distanza con Arduino

VL53L0X/TOF0200C Sensore di Distanza con Arduino

In questo tutorial imparerai come utilizzare il sensore di distanza VL53L0X (chiamato anche TOF0200C) con un Arduino o qualsiasi altro microcontrollore comune (ESP32/ESP8266) per misurare le distanze.

Il VL53L0X è un sensore di distanza Time-of-Flight (ToF) molto piccolo che utilizza un laser a infrarossi per misurare la distanza da un oggetto. Misurando il tempo impiegato dalla luce per riflettersi su un oggetto, può calcolare distanze con alta precisione. Le dimensioni compatte e il basso consumo energetico del sensore lo rendono adatto a una vasta gamma di progetti fai-da-te, inclusi robotica, riconoscimento gestuale e rilevamento di prossimità.

Componenti necessari

Ovviamente, ti servirà un sensore di distanza VL53L0X. Per quanto riguarda il microcontrollore, ho usato un Arduino Uno per questo progetto, ma qualsiasi altro Arduino o ESP32/ESP8266 funzionerà altrettanto bene. Per visualizzare le distanze misurate, ho scelto un display OLED, ma potresti anche optare per un LCD display.

Sensore di distanza VL53L0X

Arduino

Arduino Uno

USB Data Sync cable Arduino

Cavo USB per Arduino UNO

Dupont wire set

Set di fili Dupont

Half_breadboard56a

Breadboard

OLED display

Display OLED

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Caratteristiche del VL53L0X

Il VL53L0X è un chip minuscolo (4,4 x 2,4 x 1,0 mm) con due fori sulla parte superiore. Uno per l’emettitore del laser e uno per il rilevatore di luce. L’immagine qui sotto mostra il chip:

VL53L0X Chip
Chip VL53L0X (source)

Il VL53L0X funziona emettendo un impulso laser dall’emettitore, ricevendo la luce riflessa da un oggetto nel rilevatore e, basandosi sul tempo impiegato (time-of-flight), calcola la distanza dall’oggetto. L’immagine qui sotto mostra i coni dell’emettitore e del rilevatore.

Principio di funzionamento del VL53L0X (source)

Ecco le principali specifiche del VL53L0X:

  • Emettitore VCSEL a 940 nm (luce IR, invisibile all’occhio)
  • Tempo di misura 30 ms
  • Distanza fino a 2 m
  • Funziona in condizioni di scarsa luce e basso contrasto
  • Tensione: 2,6V – 5,5V
  • Interfaccia di comunicazione I2C

Puoi trovare maggiori dettagli nel datasheet

Schema applicativo del VL53L0X

Lo schema applicativo seguente mostra il cablaggio esterno necessario per usare il VL53L0X. Puoi vedere le resistenze di pull-up per l’interfaccia I2C che collega il VL53L0X a un microcontrollore (host) e due condensatori per stabilizzare l’alimentazione.

Application Schematic of VL53L0X
Schema applicativo del VL53L0X (source)

SDA e SCL sono i pin per l’interfaccia I2C. XSHUT è il pin di spegnimento, che permette di spegnere il sensore quando viene portato a massa. Questo è utile se vuoi collegare più sensori VL53L0X sulla stessa linea I2C. GPIO1 è un pin di interrupt che può segnalare al microcontrollore che i dati sono pronti.

Invece di usare direttamente il piccolo VL53L0X, è meglio procurarsi una breakout board che integra già l’elettronica sopra descritta ed è molto più facile da collegare.

Breakout board per VL53L0X

L’immagine seguente mostra una tipica breakout board per il VL53L0X. Il rettangolo bianco indica il punto in cui si trova il chip VL53L0X vero e proprio.

Breakout board per VL53L0X (source)

Il pinout ha i pin di cui abbiamo parlato prima: SDA, SCL per I2C, GPIO1 come segnale di interrupt, XSHUT per la selezione del chip, e VIN e GND per l’alimentazione. Nota che devi portare a massa XSHUT se vuoi spegnere il chip.

Collegare il VL53L0X

Grazie all’interfaccia I2C del VL53L0X, collegarlo a un Arduino è semplice. Prima collega i pin SCL e SDA della breakout board VL53L0X ai corrispondenti pin sull’Arduino come mostrato sotto. Poi collega il GND a massa e il 3.3V a VIN del VL53L0X.

Connecting VL53L0X with Arduino
Collegamento VL53L0X con Arduino

La breakout board VL53L0X funziona a 5V o 3.3V e puoi usare uno dei due per VIN. Nel cablaggio sopra, sto usando 3.3V per VIN.

Ora scriviamo un po’ di codice per testare il funzionamento del sensore VL53L0X.

Codice per misurare la distanza con VL53L0X

Prima di poter misurare distanze con il sensore VL53L0X, devi installare una libreria. Io uso la Adafruit VL53L0X Library qui. Puoi install it via the Library Manager come al solito:

Installing Adafruit VL53L0X Library via Library Manager
Installazione della libreria Adafruit VL53L0X tramite Library Manager

L’installer potrebbe chiederti se vuoi installare solo la libreria o la libreria con le sue dipendenze. Premi semplicemente “INSTALL ALL” in questo caso:

Installing dependencies for Adafruit VL53L0X Library
Installazione delle dipendenze per la libreria Adafruit VL53L0X

Con la libreria installata, eseguiamo un semplice codice di test per provare il sensore.

// Measure distance with VL53L0X sensor
// by Makerguides
#include "Adafruit_VL53L0X.h"

Adafruit_VL53L0X sensor = Adafruit_VL53L0X();

void setup() {
  Serial.begin(9600);
  sensor.begin();
}

void loop() {
  VL53L0X_RangingMeasurementData_t measure;    
  sensor.rangingTest(&measure, false); 

  if(measure.RangeStatus == 4) {
    Serial.println("---");
  } else {
    Serial.println(measure.RangeMilliMeter);
  }
 
  delay(100);
}

Come puoi vedere, il codice include la libreria Adafruit_VL53L0X.h e crea l’oggetto sensore. Nella funzione setup() inizializziamo il sensore tramite sensor.begin(). Nella funzione loop() creiamo un oggetto measure che riceve i dati di misura chiamando sensor.rangingTest(). Se il valore RangeStatus è 4, significa che nessun oggetto è stato rilevato e stampiamo “—“. Altrimenti, otteniamo la distanza da RangeMilliMeter e la stampiamo.

Se carichi il codice sopra sul tuo Arduino, dovresti vedere i valori di distanza stampati sul Serial Monitor. Se non c’è nessun oggetto davanti al sensore o è troppo lontano, vedrai “—” stampato.

Distances measured with VL53L0X printed on Serial Monitor
Distanze misurate con VL53L0X stampate sul Serial Monitor

Se hai problemi e il sensore sembra non funzionare, assicurati che il cablaggio sia corretto e che i pin SDA e SCL usati sul microcontrollore siano quelli giusti. Puoi anche controllare il diodo laser del sensore scattando una foto con una fotocamera digitale (telefono cellulare). Anche se la luce IR è invisibile all’occhio umano, la fotocamera la vede e sullo schermo della fotocamera dovresti vedere il LED laser lampeggiare (ogni 100 ms).

Laser LED of VL53L0X flickering
LED laser del VL53L0X che lampeggia

Uso della libreria VL53L0X di Pololu

Ho avuto notevoli difficoltà a far funzionare la Adafruit VL53L0X Library con codice che usa la Adafruit_SSD1306 Library per visualizzare le distanze su un OLED. Ne parlerò meglio nella sezione successiva.

Qui voglio solo darti un’implementazione alternativa che usa la VL53L0X Library by Pololu. Oltre a funzionare meglio con il display OLED, offre anche più opzioni di configurazione per il VL53L0X. Per esempio, puoi passare dalla modalità a lungo o corto raggio, e tra modalità lenta o veloce.

Installazione della libreria VL53L0X di Pololu

Per installare la VL53L0X Library by pololu, cerca semplicemente VL53L0X, trova quella di Pololu come mostrato sotto e installala usando il Library Manager. L’immagine sotto mostra come appare la libreria una volta installata:


Installing VL53L0X Library by pololu via Library Manager
Installazione della libreria VL53L0X di Pololu tramite Library Manager

Esempio di codice per la libreria VL53L0X di Pololu

Qui sotto c’è l’esempio di codice che usa la libreria di Pololu per il VL53L0X per misurare distanze:

#include "Wire.h"
#include "VL53L0X.h"

VL53L0X sensor;

void sensor_init(bool long_range, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  if (long_range) {
    sensor.setSignalRateLimit(0.1);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
  }
  int budget = high_speed ? 20000 : 200000;
  sensor.setMeasurementTimingBudget(budget);
}

int get_distance() {
  return sensor.readRangeSingleMillimeters();
}

void setup() {
  Serial.begin(9600);
  sensor_init(true, false);
}

void loop() {
  Serial.println(get_distance());
}

Iniziamo includendo la Wire.h e la VL53L0X.h libreria e poi creiamo l’oggetto sensore.

La funzione sensor_init() configura il sensore. Ti permette di passare tra modalità corto o lungo raggio e tra velocità di misura alta o bassa. Nota che le modalità lungo raggio e veloce sono meno accurate. Le due tabelle seguenti tratte dal datasheet mostrano i compromessi tra velocità, raggio e precisione:

Range Profiles of VL53L0X
Profili di portata del VL53L0X (source)
Ranging Accuracy of VL53L0X
Precisione di misura del VL53L0X (source)

La funzione get_distance() restituisce la distanza misurata in millimetri. Se l’oggetto è fuori portata, il sensore restituisce il valore 8190. Ho riscontrato che in modalità lungo raggio si può misurare fino a 2400 mm e in modalità corto raggio fino a 1300 mm. Questo test è stato fatto in interno contro una parete bianca.

Nella funzione setup() inizializziamo il sensore e nella funzione loop() otteniamo la distanza e la stampiamo sul Serial Monitor.

Se carichi ed esegui il codice, dovresti vedere le distanze misurate stampate sul Serial Monitor.

Distances measured with VL53L0X printed on Serial Monitor
Distanze misurate con VL53L0X stampate sul Serial Monitor

Nota che l’output inizia con una distanza di 8190, che indica che nessun oggetto era abbastanza vicino al sensore per essere rilevato. Poi ho puntato il sensore verso il soffitto ottenendo una distanza di circa 1700 mm e infine ho messo la mano davanti al sensore a circa 100 mm.

Nella sezione successiva aggiungeremo un OLED al nostro circuito e useremo entrambe le librerie (Adafruit, Pololu) per misurare le distanze e visualizzarle.

Aggiungere un OLED per visualizzare i dati del VL53L0X

Poiché l’OLED è anch’esso un dispositivo I2C, collegarlo è semplice. Basta collegare SDA e SCL agli stessi pin a cui è collegato il sensore VL53L0X. E dato che l’OLED funziona a 3.3V, possiamo condividere anche le linee di alimentazione.

Connecting OLED and VL53L0X with Arduino
Collegamento di OLED e VL53L0X con Arduino

La foto qui sotto mostra il cablaggio completo su una breadboard reale:

Cablaggio di OLED e VL53L0X con Arduino

Se hai difficoltà con l’OLED, dai un’occhiata al tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino.

Installazione della libreria Adafruit_SSD1306 per OLED

Nelle due sezioni seguenti scriveremo codice per mostrare la distanza misurata dal sensore VL53L0X su uno schermo OLED. Nella prima sezione useremo la libreria Adafruit per il VL53L0X e nella seconda useremo la libreria di Pololu.

Tuttavia, prima di poter visualizzare qualcosa sull’OLED, dobbiamo installare un’altra libreria. In questo tutorial useremo la libreria Adafruit_SSD1306, che puoi installare tramite il Library Manager come al solito. L’immagine sotto mostra la libreria dopo l’installazione:

Adafruit_SSD1306 library installed in Library Manager
Libreria Adafruit_SSD1306 installata nel Library Manager

Nota che l’indirizzo I2C per il display OLED è impostato su 0x3C in oled.begin(). La maggior parte di questi piccoli OLED usa questo indirizzo (or 0x27) ma il tuo potrebbe essere diverso. Se non vedi nulla sull’OLED, probabilmente ha un indirizzo I2C differente e devi cambiarlo.

Se non conosci l’indirizzo I2C, dai un’occhiata al tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino per scoprirlo. Anche il tutorial Use SSD1306 I2C OLED Display With Arduino ti spiegherà come usare un OLED.

Visualizzare le distanze misurate con la libreria VL53L0X di Adafruit su OLED

Il codice qui sotto usa la libreria di Adafruit per il VL53L0X per leggere le misure di distanza dal sensore VL53L0X e poi visualizzarle sull’OLED. Dai un’occhiata al codice completo prima di analizzarne i dettagli.

// Measure distance with VL53L0X sensor and show on OLED
// by Makerguides
#include "Adafruit_VL53L0X.h"
#include "Adafruit_SSD1306.h"

Adafruit_SSD1306 oled = Adafruit_SSD1306();
Adafruit_VL53L0X sensor = Adafruit_VL53L0X();

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

void display() {
  VL53L0X_RangingMeasurementData_t measure;
  sensor.rangingTest(&measure, false);

  oled.clearDisplay(); 
  oled.setCursor(25, 10); 
  if (measure.RangeStatus == 4) {
    oled.print(" -----");
  } else {
    oled.print(measure.RangeMilliMeter);
    oled.print(" mm");
  }
  oled.display();
}

void setup() {
  oled_init();
  sensor.begin();
}

void loop() {
  display();
  delay(100);
}

Librerie

Iniziamo includendo la libreria Adafruit_VL53L0X per il sensore VL53L0X e la Adafruit_SSD1306 Library per il display OLED.

#include "Adafruit_VL53L0X.h"
#include "Adafruit_SSD1306.h"

Oggetti

Poi creiamo gli oggetti sensor e oled:

Adafruit_SSD1306 oled = Adafruit_SSD1306();
Adafruit_VL53L0X sensor = Adafruit_VL53L0X();

Funzione oled_init

La funzione oled_init() inizializza l’OLED e imposta la dimensione e il colore del testo:

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

Nota che l’indirizzo I2C per il display OLED è impostato su 0x3C in oled.begin(). La maggior parte di questi piccoli OLED usa questo indirizzo ma il tuo potrebbe essere diverso. Se non vedi nulla sull’OLED, probabilmente ha un indirizzo I2C differente e devi cambiarlo. Se non conosci l’indirizzo I2C, dai un’occhiata al tutorial How to Interface the SSD1306 I2C OLED Graphic Display With Arduino.

Funzione display

La funzione display() chiama prima rangingTest() per misurare la distanza. Poi puliamo il display, impostiamo la posizione del cursore e stampiamo la distanza. Se non è stata misurata alcuna distanza (RangeStatus == 4), visualizziamo “—-” per indicare che nessun oggetto era nel raggio d’azione:

void display() {
  VL53L0X_RangingMeasurementData_t measure;
  sensor.rangingTest(&measure, false);

  oled.clearDisplay(); 
  oled.setCursor(25, 10);   
  if (measure.RangeStatus == 4) {
    oled.print(" -----");
  } else {
    oled.print(measure.RangeMilliMeter);
    oled.print(" mm");
  }
  oled.display();
}

Funzioni setup e loop

Nella funzione setup() chiamiamo gli inizializzatori per l’OLED e per il sensore VL53L0X, e nella funzione loop() visualizziamo la distanza misurata ogni 100 ms:

void setup() {
  oled_init();
  sensor.begin();
}

void loop() {
  display();
  delay(100);
}

Problemi con la libreria Adafruit_VL53L0X

Scrivendo il codice sopra, ho incontrato diversi problemi. Primo, non potevo usare il mio solito codice per creare l’oggetto OLED:

Adafruit_SSD1306 oled(128, 64, &Wire, -1);

Secondo, non potevo usare la funzione sprintf() per stampare testo formattato su un buffer da visualizzare sull’OLED.

In entrambi i casi il codice compilava, poteva essere caricato ma poi il programma non partiva, senza mostrare messaggi di errore. Sospetto ci sia un conflitto di accesso alla memoria tra le librerie Adafruit_SSD1306 e Adafruit_VL53L0X.

A causa di questi problemi con la libreria Adafruit_VL53L0X, ho deciso di provare un’altra libreria. Nella sezione seguente ti mostro il codice che usa la libreria VL53L0X di Pololu.

Visualizzare le distanze misurate con la libreria VL53L0X di Pololu su OLED

Il codice seguente usa la libreria di Pololu per il VL53L0X per leggere le misure di distanza dal sensore VL53L0X e visualizzarle sull’OLED.

#include "Wire.h"
#include "VL53L0X.h"
#include "Adafruit_SSD1306.h"

Adafruit_SSD1306 oled(128, 64, &Wire, -1);
VL53L0X sensor;
const int maxdist = 2400;

void sensor_init(bool long_range, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  if (long_range) {
    sensor.setSignalRateLimit(0.1);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
  }
  int budget = high_speed ? 20000 : 200000;
  sensor.setMeasurementTimingBudget(budget);
}

int get_distance() {
  return sensor.readRangeSingleMillimeters();
}

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

void display() {
  static char text[30];
  int dist = get_distance();
  if (dist > maxdist)
    sprintf(text, " -----");
  else
    sprintf(text, "%4d mm", dist);

  oled.clearDisplay();
  oled.setCursor(20, 25);
  oled.print(text);

  int w = map(dist, 0, maxdist, 0, 120);
  oled.drawFastHLine(4, 45, w, WHITE);
  oled.display();
}

void setup() {
  oled_init();
  sensor_init(true, false);
}

void loop() {
  display();
}

Se carichi ed esegui il codice, dovresti vedere le distanze in millimetri visualizzate sull’OLED con una barra sotto proporzionale in lunghezza alla distanza.

Measured Distance shown on OLED
Distanza misurata mostrata su OLED

Se non c’è nulla davanti al sensore (o oltre i 2 m), il display mostrerà “la distanza massima” “—–” e una linea a tutta lunghezza.

No object detected
Nessun oggetto rilevato

Librerie

Iniziamo includendo le librerie necessarie per l’OLED e il VL53L0X. In questo esempio di codice usiamo la libreria VL53L0X di Pololu per leggere i dati di distanza dal sensore VL53L0X.

#include "Wire.h"
#include "VL53L0X.h"
#include "Adafruit_SSD1306.h"

Oggetti e costanti

Poi creiamo gli oggetti oled e sensor. Con la libreria VL53L0X di Pololu non ho avuto difficoltà a creare l’oggetto oled nel modo usuale (oled(128, 64, &Wire, -1)), mentre questo codice non funzionava usando la libreria VL53L0X di Adafruit.

Adafruit_SSD1306 oled(128, 64, &Wire, -1);
VL53L0X sensor;

const int maxdist = 2400;

La costante maxdist specifica la distanza massima che il codice riporterà nelle misure. Oltre questa distanza, il codice segnalerà che nessun oggetto è stato rilevato.

Funzioni sensor_init e get_distance

Le funzioni sensor_init() e get_distance() sono le stesse di prima. sensor_init() inizializza il sensore VL53L0X e imposta le diverse modalità operative, mentre get_distance() legge la distanza misurata dal VL53L0X.

void sensor_init(bool long_range, bool high_speed) {
  Wire.begin();
  sensor.setTimeout(500);
  sensor.init();
  if (long_range) {
    sensor.setSignalRateLimit(0.1);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
    sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
  }
  int budget = high_speed ? 20000 : 200000;
  sensor.setMeasurementTimingBudget(budget);
}

int get_distance() {
  return sensor.readRangeSingleMillimeters();
}

Funzione oled_init

La funzione oled_init() rimane invariata. Inizializza l’OLED e imposta la dimensione e il colore del testo.

void oled_init() {
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.setTextSize(2);
  oled.setTextColor(WHITE);
}

Funzione display

La funzione display() ottiene la distanza misurata dal sensore VL53L0X. Se la distanza è maggiore di maxdist, assume che nessun oggetto sia nel raggio d’azione e stampa “—–” sull’OLED. Altrimenti, stampa il valore della distanza.

void display() {
  static char text[30];
  int dist = get_distance();
  if (dist > maxdist)
    sprintf(text, " -----");
  else
    sprintf(text, "%4d mm", dist);

  oled.clearDisplay();
  oled.setCursor(20, 25);
  oled.print(text);

  int w = map(dist, 0, maxdist, 0, 120);
  oled.drawFastHLine(4, 45, w, WHITE);
  oled.display();
}

Oltre all’output testuale, la funzione display() disegna anche una linea orizzontale sotto il testo con una lunghezza proporzionale alla distanza misurata.

Funzioni setup e loop

La funzione setup inizializza l’OLED e il sensore VL53L0X. La modalità del sensore è impostata su lungo raggio e velocità predefinita (sensor_init(true, false)).

Nella funzione loop() chiamiamo semplicemente la funzione display(). Il loop gira alla massima velocità con cui il sensore può fornire dati (circa 30 ms a velocità predefinita).

void setup() {
  oled_init();
  sensor_init(true, false);
}

void loop() {
  display();
}

E questo è tutto. Ora hai il tuo strumento per misurare le distanze

Conclusioni

In questo tutorial hai imparato come usare il sensore di distanza VL53L0X con un Arduino per misurare distanze e visualizzarle su un OLED.

Il sensore VL53L0X è un sensore molto piccolo, veloce e ad alta precisione che usa un laser a infrarossi per misurare le distanze. Il VL53L0X è molto simile al sensore TOF10120 per dimensioni, funzione e caratteristiche. Entrambi i sensori usano il metodo Time-of-Flight per calcolare la distanza da un oggetto. Il VL53L0X offre più opzioni di configurazione (lungo raggio, velocità veloce) e in modalità lungo raggio può rilevare oggetti a distanze leggermente maggiori (2400 mm contro 1800 mm) anche se con precisione ridotta.

Altri sensori di distanza a infrarossi come il GP2Y0A710K0F o il GP2Y0A21YK0F usano la triangolazione per determinare la distanza basandosi sull’angolo della luce IR riflessa e hanno portata più corta e precisione inferiore.

Se hai domande, sentiti libero di lasciarle nella sezione commenti.

Buon divertimento con il fai-da-te ; )