VL53L0X Time-of-Flight (ToF) Laser Abstandssensor - [Teil 1]

Einführung

In diesem Beitrag möchte ich Ihnen den Abstandssensor VL53L0X vorstellen. Ich werde Ihnen zeigen, welche Bibliotheken in der Arduino IDE zur Verfügung stehen und wie Sie den Sensor an einen ESP8266 anschließen. Außerdem bauen wir einen einfachen akustischen Abstandswarner, den sie eventuell aus einem PKW kennen. Los geht's.

Benötigte Hardware

Anzahl Bauteil Anmerkung
1 VL53L0X Sensor Breakout Board
1 ESP8266 Node MCU D1 Mini
1 KY-006 Passives Piezo Buzzer Alarm Modul für Arduino
1 Verbindungskabel
Computer mit Arduino IDE und Internetverbindung

Der Sensor

Der VL53L0X ist eigentlich ein kleines schwarzes Kästchen von der Firma STMicroelectronics, das auf ein Breakout Board aufgelötet ist.


Er erzeugt ein für das menschliche Auge nicht sichtbares gebündeltes Licht mit einer Wellenlänge von 940 nm. Trifft dieses Licht auf ein Hindernis, wird es zurück zum Sensor reflektiert. Mit der Zeit, die das Licht bis zum Hindernis und wieder zurück zum Sensor braucht, wird die Entfernung zum Hindernis gemessen. Die Kommunikation findet über die I²C-Schnittstelle statt. Auf den gängigen Breakout Boards findet man neben den Eingängen der Stromversorgung und den Kommunikationspins (SDA und SCL) auch GPIO1 und XSHUT.

Im Datenblatt findet man dazu passende Informationen. GPIO1 ist ein digitaler Ausgang, der als Interrupt-Signal verwendet werden kann. Der Sensor kann so konfiguriert werden, dass er ein Signal auf dem Pin ausgibt, wenn sich ein Hindernis innerhalb einer festgelegten Distanz befindet. Der XSHUT-Pin ist dafür da, um den Sensor in einen Hardware Standby zu bringen. Dabei ist zu beachten, dass der Pin "active LOW" ist. Auf einigen erhältlichen Varianten des Sensorboards fehlen diese beiden Pins.

Die Spannungsversorgung des Sensors liegt laut Hersteller zwischen 2,6V und 3,5V. Auf dem Breakout Board ist allerdings ein Spannungswandler untergebracht, sodass er auch mit 5V betrieben werden kann.

Der Abstand, der mit dem Sensor gemessen werden kann, variiert zwischen 20 mm und 2m. Dabei ist diese Messung abhängig vom gewählten Messprofil. Es stehen Profile für hohe Genauigkeit (High accuracy), hohe Geschwindigkeit (High speed), Lange Distanz (Long range) und normale Messung (Default mode) zur Verfügung. Außerdem hat man die Wahl zwischen drei verschiedenen Messmodi (Ranging operating modes).

Der Single Modus (Single ranging) startet eine Messung und bringt den Sensor anschließend in einen Software Standby. Mit dem sich wiederholenden Messmodus (Continuous ranging) wird ohne Unterbrechung dauerhaft gemessen, bis der Benutzer die Messungen beendet. Der dritte Modus (Timed ranging) erweitert den dauerhaften Modus durch Pausen zwischen den Messungen, deren Dauer der Benutzer festlegen kann.

Im Vergleich zu anderen Geräten wie dem HC-SR04 Ultraschallmodul, ist dieser Sensor wesentlich kleiner.


Ein anderer Aspekt ist, dass man sich mit weiteren Sensoren vom gleichen Typ nicht so sehr in die Quere kommt. Ultraschall funktioniert (wie der Name schon sagt) mit Schallwellen. Setzt man viele Sensoren davon in einem Raum ein, werden sie sich sehr wahrscheinlich gegenseitig stören, auch wenn sie nicht direkt aufeinander gerichtet sind.

Es ist noch ein weiteres Modell namens VL53L1X im freien Handel erhältlich, mit dem man Hindernisse auf eine Distanz von bis zu 4 m erkennen kann.

Pins verbinden

Zuerst verbinden wir den Sensor mit einem ESP8266 NodeMCU D1 Mini nach folgendem Schema:

VL53L0X Pins D1 Mini GPIO
VIN 3.3V
GND GND
SCL SCL (D1 / GPIO5)
SDA SDA (D2 / GPIO4)
GPIO1 -
XSHUT -


An dieser Stelle wird es wahrscheinlich nötig sein, den Lötkolben aufzuheizen. Das Sensorboard wird mit separaten Pinheadern geliefert, die zuerst angelötet werden müssen, wenn man sie verwenden möchte.


Die Pins GPIO1 und XSHUT lassen wir frei. Für die I²C-Pins SDA und SCL ist es ratsam, einen Blick in die Übersicht der Pinouts zu werfen. Am ESP8266 sind diese Pins GPIO4 und GPIO5, die aber auf dem Board als D2 und D1 beschriftet sind. Das ist von Mikrocontroller zu Mikrocontroller unterschiedlich.

Die Programmierung

Der Chiphersteller STM stellt eine API (Application Programming Interface) zur Verfügung, mit der die verschiedenen Einstellungen des Sensors und sein Verhalten kontrolliert werden können.

In der Arduino IDE über die Bibliotheksverwaltung kann man Bibliotheken von Adafruit (Adafruit_VL53L0X) und Pololu (VL53L0X) installieren. Damit wurden auf Basis der API bereits fertige Bibliotheken geschrieben, die wir verwenden können. Dafür gibt man in das Suchfeld den Namen VL53L0X (Null zwischen L und X) ein. Installieren wir beide Bibliotheken, stehen uns anschließend auch einige Beispiele zur Verfügung.

Adafruit Bibliothek

Wir laden in der Arduino IDE aus der Adafruit_VL53L0X-Bibliothek das Beispiel vl53l0x (Datei->Beispiele->Beispiele aus eigenen Bibliotheken). Als Board wählen wir den Wemos D1 Mini oder NodeMCU 1.0 (ESP-12E Module). Laden wir das Programm auf den Mikrocontroller und öffnen anschließend den Seriellen Monitor, sollte dort die Ausgabe für die gemessene Distanz erscheinen. Achten Sie darauf, dass die Baudrate im Programm mit der des Monitors übereinstimmt.

Der Sensor arbeitet mit den Standardeinstellungen. Die Distanz kann bis ca. 500mm ununterbrochen gemessen werden. Die Standard-I²C-Adresse ist 0x29. In dieser Bibliothek muss man sie nicht angeben. Die I²C-Bibliothek (Wire.h) wird intern geladen und die Adresse übergeben.

Es sind noch einige andere Beispiele vorhanden, wobei dort die Priorität auf der gleichzeitigen Nutzung mehrerer ToF-Sensoren liegt.

Akustischer Abstandswarner

Sie kennen eventuell die akustischen Abstandswarner in PKWs, deren Piepston in immer kürzeren Intervallen ausgegeben wird, je näher man an ein Hindernis heranfährt. Vorzugsweise im Rückwärtsgang. Das möchte ich nun ebenfalls umsetzen. Dafür müssen wir unsere Schaltung so erweitern, dass ein akustisches Signal ausgegeben wird. Ich greife dafür auf einen Piezo Buzzer zurück, der auch als Breakout Board erhältlich ist. Der wird wie folgt angeschlossen:

KY-006 Buzzer D1 Mini GPIO
- (Minus) GND
+ (mittlerer Pin) 5V
S (Signal) D7 (GPIO 13)


Auch hier ist wieder darauf zu achten, dass in der Arduino IDE die Pinnummer 13 verwendet werden muss. Beschriftet ist der Pin mit D7.

Ich nutze den Beispielcode vl53l0x als Vorlage und deklariere zuerst Konstanten für den benutzten Pin, die Frequenz und die Dauer des erzeugten Tones:

#define BUZZER 13
#define FREQ 800
#define DURATION 300

Wir benötigen noch eine Variable für die Zeitmessung:

unsigned long zeitAlt = 0;

Damit werden wir den Piepton nur dann ausgeben, wenn ein bestimmtes Zeitintervall abgelaufen ist.

Im setup() initialisieren wir den Buzzerpin als Ausgang:

  pinMode(BUZZER, OUTPUT);

Als Nächstes suchen wir im Quellcode nach der Stelle, an der die Zeitmessung ausgegeben wird:

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

und fügen die Ausgabe auf den Buzzer hinzu:

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

if (millis() - zeitAlt >= measure.RangeMilliMeter * 3) {
zeitAlt = millis();
tone(BUZZER, FREQ, DURATION);
}
} else {
Serial.println(" out of range ");
}

Immer dann, wenn ein Hindernis im Messbereich detektiert wurde, wird der Abstand auf dem Seriellen Monitor ausgegeben. Wir fügen eine if-Anweisung hinzu, in der die Ausgabe des Tones auf dem Buzzer erzeugt wird. Die Funktion tone() ist in der Arduinoreferenz erklärt. Wir übergeben ihr den Pin, die Frequenz und die Dauer des Tones.

Wir wollen den Ton abhängig von der Entfernung zum Hindernis ausgeben. Je näher dran, desto kürzer das Intervall zwischen zwei Pieptönen. Je weiter weg, desto länger die Pause. Den Abstand in mm nutzen wir dafür als Referenzwert. Wird die Messung durchlaufen, starten wir eine Stoppuhr.

Nach jedem Durchlauf vergleichen wir die abgelaufene Zeit mit dem Abstand in mm. Da wir aber dann mm mit ms vergleichen und der Wert etwas klein ist, habe ich ihn mit 3 multipliziert. Dadurch ergibt sich ein brauchbares akustisches Signal.

Wenn das Programm auf den Mikrocontroller geladen wird, sollte je nach Abstand der Buzzer unterschiedlich schnelle Pieptöne ausgeben.

Als kreative Anregung schlage ich Ihnen vor, mal ein Theremin zu programmieren. Kleiner Tipp: Sie müssen lediglich die Zeitmessung entfernen und den Abstand als Referenz für die Frequenz benutzen. Eventuell reicht es schon aus, den gemessenen Abstand der tone()-Funktion als zweiten Parameter zu übergeben.

Kompletter Quellcode: ToFBuzzerESP8266_Adafruit.ino

Die Pololu-Bibliothek

Mit dieser Bibliothek wurde ebenfalls Beispielcode mitgeliefert. Wir öffnen unter Beispiele->VL53L0X das Projekt "Continuous" und laden es auf den D1 Mini. Bei mir gab es zu Beginn einige Probleme. Das Programm ließ sich zwar hochladen. Der Mikrocontroller hing dann aber in einer Bootschleife. Ich habe im setup() folgende Zeile geändert:

Serial.println("Failed to detect and initialize sensor!");

in

Serial.println(F("Failed to detect and initialize sensor!"));

Das habe ich aus dem Adafruit-Beispiel abgeleitet. Sollten Sie ähnliche Probleme haben, dann probieren Sie diese Lösung aus. Eventuell reicht es auch, den Mikrocontroller vom Strom zu trennen und wieder anzuschließen, um ihn neu zu starten. Den Seriellen Monitor müssen Sie dann ebenfalls schließen und erneut öffnen.

Um nun wieder einen akustischen Abstandswarner zu erhalten, erweitern und ändern den Quellcodes des Beispiels wie folgt:

Wir fügen die gleichen Konstanten aus dem anderen Quelltext ein:

#define BUZZER 13
#define FREQ 800
#define DURATION 300

Außerdem die Variable für die Zeitmessung:

unsigned long zeitAlt = 0;

Im setup() initialisieren wir ebenfalls den Buzzerpin als Ausgang:

  pinMode(BUZZER, OUTPUT);

Wir suchen wieder im Quellcode nach der Stelle, an der die Zeitmessung ausgegeben wird:

void loop()
{
Serial.print(sensor.readRangeContinuousMillimeters());
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); } 

Serial.println();
}

Das ändern wir folgendermaßen:

void loop()
{
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
if (sensor.readRangeContinuousMillimeters() < 4000) {
Serial.println(sensor.readRangeContinuousMillimeters());
if (millis() - zeitAlt >= sensor.readRangeContinuousMillimeters() * 3) {
zeitAlt = millis();
tone(BUZZER, FREQ, DURATION);
}
}
else {
Serial.println(" out of range ");
}
}

Im Sourcecode der Bibliothek gibt es keinen "RangeStatus", der in der Adafruit-Bibliothek verwendet wird, um zu erkennen, ob sich das Hindernis außerhalb der messbaren Reichweite befindet. Schauen wir uns aber die Ausgabe der Messdaten auf dem Monitor an, können wir sehen, dass der Wert über 8000 liegt, wenn der Sensor nichts messen kann.

Da mehr als 2000 mm zu messen gar nicht möglich sind, habe ich als Bedingung "kleiner als 4000" gewählt. Das wäre dann der maximale Messbereich für den anderen Sensor VL53L1X im Long-Range-Modus, falls man diesen verwendet.

Der Rest ist nahezu identisch zum Quelltext aus dem vorherigen Programm. Nur die Funktion für die Messung und das Objekt des Sensors heißen anders.

Laden Sie das Programm auf den ESP8266 D1 Mini, sollte alles genauso funktionieren, wie mit der Adafruit Bibliothek.

Kompletter Quellcode: ToFBuzzerESP8266_Pololu.ino

Ausblick

Die Produktbeschreibung des Sensors verspricht mehr Funktionalität, als nur einfach die Distanz zu messen. Im zweiten Teil dieser Beitragsreihe werden ich das "Ranging Profile" verändern. Dann schaue ich mir an, ob wir die Pins GPIO1 und XSHUT verwenden können. Außerdem werde ich den Sensor an einen ESP32 sowie einen Arduino NANO anschließen.

Bis dahin,

Andreas Wolter

für AZ-Delivery Blog

Precipitador electrostático - 8266Projekte für anfängerSensoren

13 comentarios

Stephan D.

Stephan D.

Hallo,

gibt es eine Möglichkeit, den Sensor am RasPi ( nutze 3b+) mittels Lazarus anzubinden (entweder als direkte Programmierung oder notfalls als Phyton-Script) ?

Ich suche schon länger eine Möglichkeit, an einem selbstgebauten Plasma-Brenntisch mit Steuerung über RasPi und Lazarus eine Höhenregulierung des Brennkopfes umzusetzen, mechanische Lösungen haben sich bisher als nicht ausreichend erwiesen, wenn sich das Blech durch die Hitze verwölbt, auch stören gelegentlich Materialrückstände speziell an der Einbrennstelle (heben dann den Brennkopf aus bzw. er bleibt hängen)

Daher …

1. welche Genauigkeit lässt sich erreichen
2. stört der Plasma-Bogen den “Empfang” des Sensors

Im Voraus schon vielen Dank

Stephan

Hans-Jürgen Purps

Hans-Jürgen Purps

Also der Testaufbau zur Messung des Abstandes der Bowlingkugel von der Messanordnung funktionierte soweit ganz gut. Getestet wurden die Distancen bis ca. 1 m u. ca, 30 Km/h des Balles, was vollkommen ausreicht. Messungenauigkeiten von max. 1 Leiste (2,66cm) sind zugelassen. Wirkt sich die Anordnung des Sensors auf das Ergebnis aus ? (Senkrecht, waagerecht, etc.)

Georg

Georg

Hallo Dieter,
das geht am besten mit einem feuchtigkeitsunempfindlichen Ultraschallsensor (JSN-SR04T) und der Bibliothek HCSR04.h. Die Darstellung auf einem OLED-Display mit der Bibliothek “SSD1306Ascii.h” zeigt Dir dann die Werte.
Gruß Georg

Andreas Wolter

Andreas Wolter

@Joan Boada
the laser light is invisible for the eyes (https://www.st.com/en/imaging-and-photonics-solutions/vl53l0x.html) and if you are too close to your eye, it can be harmful to your retina. But if you take a look at the sensor you can see that the hole for the light emitter is very small.

In German: das Laserlicht ist unsichtbar für das menschliche Auge. Es wird darauf hingewiesen, dass es für die Netzhaut im Auge gesundheitsschädlich sein kann, wenn man zu nah dran ist. Die Öffnung für das Licht ist sehr klein und der Lichtkegel relativ schmal.

@Hans-Jürgen Purps
Der Messabstand beträgt bei diesem Sensor maximal 2m im Long Range Mode. Ich habe einen Test mit einem Fußball gemacht, dessen Abstand gemessen wurde. Das Laserlicht ist gebündelt und hat einen sehr schmalen Kegel (ich finde leider die Informationen zum Durchmesser im Verhältnis zum Abstand nicht mehr). Die Auftrittsfläche des Kegels kann man per Register verändern. Das habe ich aber nicht getestet. Eventuell müssen Sie dafür einen Blick in die Bibliotheken werfen.

Bei runden Oberflächen hängt es natürlich davon ab, auf welche Stelle der Laser trifft. Ich habe eben einen Test mit einer AA-Batterie gemacht, deren Abstand auch erkennt wurde.

Grüße,
Andreas Wolter

Joan Boada

Joan Boada

Andreas Wolter

It is dangerous for the eyes?
¿Es peligroso para los ojos?
thank you very much

Hans-Jürgen Purps

Hans-Jürgen Purps

Mich würde interessieren, ob man mit dem Laser auch Entfernungen bei runden, beweglichen Objekten messen kann (z.B. Bowlingball – Durchmesser ca. 22 cm, Geschwindigkeit bis 30 Kmh). Entfernungswerte liegen zwischen 30 cm und 150 cm (Breite der Bowlingbahn). Wenn ja, warte ich gespannt auf den 2. Teil.
Vielen Dank….

Andreas Wolter

Andreas Wolter

Hallo,
der Sensor sendet ähnlich wie ein Laserpointer einen gebündelten Lichtstrahl ohne fühlbare Wärme ab. Kunststoff als Reflektionsfläche wird kein Problem sein. Das Gleiche gilt für Papier.

Die Oberfläche einer Flüssigkeit ist teilweise reflektiv, teilweise durchlässig. Dadurch Misst der Sensor inkonstante werte. Man müsste daher auf den Ultraschallsensor ausweichen, oder in einer Zysterne eine Art Schwimmer mit einer weißen Oberfläche installieren. Wenn sich der Wasserstand ändert, ändert sich die Lage der Reflecktionsfläche.
Dazu kommt noch, wie bereits in den Kommentaren erwähnt wurde, dass man den Sensor vor Feuchtigkeit schützen muss. Wird er hinter einer durchsichtigen Schutzfläche installiert, kann man ein Offset einstellen (oder man rechnet es im Programmcode selbst aus, wenn man sich eine Kalibrierung für den Abstand zur Reflektionsfläche implementiert).

Grüße,
Andreas Wolter

Franz-Josef Händel

Franz-Josef Händel

Guten Tag,
Folgende Fragen:
Erzeugt der Laser Wärme auf kurzem Abstand? Die angepeilte Reflexionsfläche besteht aus farbigen Kunsstoff und hat einen Abstand von maximal 2cm.

Günther

Günther

Hallo Dieter´s :D Ganz genau meine Frage. Ich hoffe es gibt ne Antwort ob der Laser Sensor auch bei Flüssigkeiten funktioniert.
BG
Günther

Hans Engelen

Hans Engelen

@Dieter I would have to test that but given that it is a SPAD type TOF sensor it should work, the main worry however would be contamination of the sensor in a humid environment. Good thing is you can actually use a filter or thin plastic transparent sheet in front of the sensor without impairing it (depends on the sheet no doubt).

Dieter2

Dieter2

Hi Dieter,
Diese Frage und Idee hatte ich auch :-)
Dieter2

mike

mike

Danke.
Die Artikel machen wirklich Spaß und geben guten Input, auch für neue Ideen

Dieter Wagner

Dieter Wagner

Tolle Sache das,
ich würde gerne den Füllstand einer Zisterne messen. Gibt es da einen Ansatz?
Danke Dieter

Deja un comentario

Todos los comentarios son moderados antes de ser publicados