Was ist besser zur Distanzmessung?
Ultraschall-Modul HC-SR04 versus TOF-Modul VL53L0X
Als erstes stellt sich natürlich die Frage: Wozu braucht man Distanzmessung überhaupt?Dafür gibt es so einige Anwendungsgebiete. Oft will man vermeiden, irgendwo reinzufahren bzw. rechtzeitig vorher abzubremsen. So vermeidet man zum Beispiel, sein Auto in das hinter einem parkenden zu setzen (Einparkhilfe) oder dass der Staubsaugerroboter ständig gegen die Wand fährt und unnötig rumlärmt und sich abnutzt. Oder der Quadcopter kann sanfter landen, wenn er weiß, wie weit es noch bis zum Boden ist.
Aber man könnte natürlich auch ausrechnen, wieviele Quadratmeter ein Raum hat, indem man die beiden Abstände zwischen den beiden gegenüberliegenden Wänden misst. Mithilfe von Elektronik geht das sehr viel schneller und bequemer als mit der klassischen Methode und einem Zollstock (jaja, ich weiß: es heißt richtig Gliedermaßstab). Dafür gibt es sogar spezielle Geräte für den Handwerker, die es als Ultraschall Entfernungsmesser zu kaufen gibt. Die funktionieren auch nicht anders als der Aufbau, den ich heute vorstelle.
Oder man baut das kleine Platinchen (jetzt rede ich von dem TOF-Modul) in einem Monitor ein und kann so protokollieren, ob und wielange jemand am Arbeitsplatz ist. Oder zählt vorbeifahrende Produkte in einem bestimmten Abstand am Fließband.
Bisher hatte ich zur Distanzmessung immer Ultraschall und das Modul HC-SR04 benutzt.
Die Hardware: Das Ultraschall-Modul HC-SR04
In meinem Artikel Ultraschall-Abstandswarner mit dem Multi Function Shield gehe ich auf den Ultraschall - Sender / Empfänger und seinen Einsatz auf einem Arduino Uno genauer ein.
Deshalb nur ganz kurz zur Funktionsweise des HC-SR04: Wenn man den Trigger Pin triggert, dann sendet das Modul Ultraschallwellen, also für Menschen unhörbare Schallwellen aus, die an dem Objekt, das in Sichtlinie zum Sensor ist, reflektiert werden und dann wieder auf das Modul treffen. Die Empfangsseite merkt das und setzt den Echo Pin auf High. Damit haben wir die Laufzeit für Hin- und Zurück. Dies halbiert und verknüpft mit der Schallgeschwindigkeit von 343.2 m/s ergibt die Distanz zum Objekt.
Die Hardware:Das TOF-Modul VL53L0X
Das Time-of-Flight-Modul VL53L0X von ST hingegen funktioniert nicht mit Schall, sondern mit Licht. Es sendet statt Schall einen Infrarot-Laserstrahl aus, der wieder reflektiert wird und zum Modul zurückkommt. Eigentlich das selbe Prinzip, nur ist Licht viel viel schneller als Schall und darum sollte die Genauigkeit auch besser sein gegenüber dem Ultraschall-Modul HC-SR04.
Ein Arduino oder ESP8266/ESP32 wäre wohl doch ein bisschen zu langsam bzw. ungenau, solch kurze Zeiten zu messen. Ein Laser, der auf ein Objekt in einem halben Meter Abstand aufträfe, wäre schon in einer 300 Millionstel Sekunde wieder zurück, also in nur 3.3 Nanosekunden. Darum hat der VL53L0X einen spezialisierten Microcontroller eingebaut, der uns das Ergebnis über das I2C-Protokoll zurückgibt.
Der Class 1-Laser (940 nm Wellenlänge), die Fotodiode zum Empfang und der Microcontroller finden alle in einem winzigen Gehäuse mit den Maßen 4.4 x 2.4 x 1 mm Platz.
Die Platine, auf der das Modul verbaut ist, ist zwar sehr klein, wirkt im Vergleich zum eigentlich VL53L0X-Modul von ST allerdings riesig. Hier sind die wichtigen Pins der MCU des Moduls herausgeführt:
- VIN: Spannungsversorgung 2.7V bis 5V, wird an die 3.3V-Schiene des ESP8266 angeschlossen
- GND: Ground/Masse, kommt an die Masseleitung GND des ESP8266
- SCL und SDA: I2C-Bus mit Clock und Data, kommt an zwei Data-Pins des ESP8266
- GPIO1: kann mit einem Data-Pin des ESP8266 verbunden werden, dann können Interrupt-Signale empfangen werden
- XSHUT: hierüber kann das Modul abgeschaltet werden. Werden mehrere Module gleichzeitig benutzt, dann lässt man jeweils nur eins davon an und fragt sie der Reihe nach hintereinander ab.
Außerdem sind auf der Platine Spannungswandler verbaut, so dass das Modul mit 2.7V oder mit 5V betrieben werden kann. Das ST Modul selbst möchte nämlich 2.6 bis 3.5 Volt Versorgungsspannung, was die Spannungswandler automatisch bereit stellen.
So kann das Modul auch auf 5V-Plattformen wie dem Arduino Uno oder Nano betrieben werden. Und natürlich kommt das Modul auch mit den 3.3V des ESP8266 zurecht, bei dem es nicht groß etwas umwandeln muss.
Das Modul kann im Polling oder im Interrupt-Modus betrieben werden, was mit den entsprechenden I2C-Befehlen eingestellt werden kann.
Im Polling fragt des ESP8266 per I2C-Befehl nach den aktuellen Daten und bekommt sie dann geliefert. Im Interrupt-Modus wird über GPIO1 ein Signal geschickt, immer wenn ein neues Messergebnis bereit steht.
Guckt der TOF-Sensor die meisten Zeit ins Leere und will man Strom sparen, so benutzt man den Interrupt-Modus, der signalisiert, sobald sich was tut und den ESP8266 aus dem stromsparenden Deep Sleep Modus über einen Hardware-Pin aufweckt.
Der Versuchsaufbau
Um den Ultraschall-Sensor HC-SR04 und den TOF-Sensor VL53L0X gut miteinander vergleichen zu können und gleiche Mess-Bedingungen zu haben, will ich beide nebeneinander auf einem Breadboard installieren und in die selbe Richtung "blicken" lassen.
Das der eine mit Schall und der andere mit Licht funktioniert, ist ausgeschlossen, das sich beide stören.
Auf einem OLED-Display will ich die Messwerte gleichzeitig und nahe beiander anzeigen lassen, um einen direkten Vergleich zu erleichtern.
Als Grundaufbau soll mir dafür ein ESP8266 dienen, der auf dem Breadboard bereits über I2C mit einem SSD 1306-OLED verbunden ist. Für das sehr gebräuchliche SSD 1306-OLED gibt es für alle Plattformen Bibliotheken: Raspberry Pi, Arduino, STM32, ESP8266, ESP32. Die passende zu finden, sollte also kein Problem sein.
Das OLED benutzt wie gesagt I2C und ich habe es an die Pins D1 = SCL und D2 = SDA des ESP8266 angeschlossen.
Da I2C ein Bus ist, an dem mehrere Geräte angeschlossen sein dürfen und man diese Geräte mit deren I2C-Adresse anspricht, geht der I2C-Bus gleich weiter an SDA und SCL an unserem TOF-Modul.
Das TOF-Modul bekommt dann noch 3.3V Versorgungsspannung und wird an GND angeschlossen und schon ist es fertig angeschlossen.
Auch das Ultraschall-Modul bekommt GND und Versorgungsspannung, allerdings reichen hier 3.3V nicht aus. Es müssen schon volle 5 V sein, sonst misst es nicht oder nicht richtig.
Vorsicht! Ich habe hier dann auch am Echo-Pin am Oszilloskop eine Spannung von 4.85V gemessen. Dafür ist der ESP8266 (und andere moderne Microcontroller) eigentlich nicht ausgelegt. Wer sicher gehen will, sollte hier Logic Converter von 5V auf 3.3V einbauen oder eine Spannungsteiler-Schaltung. Meinem ESP8266 hat er aber überlebt, was wohl auch daran liegt, dass die Signale immer nur sehr kurz und nicht dauerhaft anliegen. Trotzdem: Weglassen der Schutzschaltungen auf eigene Gefahr (was sowieso für alle Experimente und Anleitungen von mir gilt).
Der Trigger und Echo-Pin des Ultraschall-Sensor bekommen ihren eigenen Pin am ESP8266, ich habe D5 und D6 genommen, es gehen natürlich auch andere, dass kann im Soruce-Code bei den Defines angepasst werden.
Die Software / Libraries / Firmware
Für das SSD 1306-OLED findet man "an jeder Ecke" eine passende Bibliothek.
Ich habe hier die SSD1306 Library von ThingPulse / Fabrice Weinberg hergenommen, weil ich bisher gute Erfahrungen damit gemacht habe und sie nicht so riesig ist. Ich habe aktuell Version 4.1.0 installiert, es gäbe aber eine neue Version 4.3.0, mit der es sicher auch funktioniert.
Für das TOF-Modul habe ich die Library VL53L0X von Pololu in Version 1.3.1 hergenommen.
Die war die erste, die mir unter gekommen war und da ich Pololu schon mal gehört hatte, habe ich die genommen.
Und da alles ohne Probleme funktioniert hat, was ich brauchte, und wie ich wollte, bin ich dabei geblieben, ohne noch weitere auszuprobieren.
Für den Ultraschall-Sensor habe ich mir kurzerhand meine eigene Funktion geschrieben. Die Abfrage ist eigentlich ganz einfach und eine Library wäre hier irgendwie Overkill.
Function getUltrasonicDistance() (klicken, um diesen Abschnitt aufzuklappen)
float getUltrasonicDistance() {
long duration;
float distance;
// Trigger-Pin triggern, um eine Messung anzustoßen
digitalWrite(PinTrig, LOW);
delayMicroseconds(2);
digitalWrite(PinTrig, HIGH);
delayMicroseconds(10);
digitalWrite(PinTrig, LOW);
// Die Zeitspanne messen, bis das Signal wieder zurückgekommen ist
// und den Echo-Pin auf High gezogen hat
duration = pulseIn(PinEcho, HIGH, EchoTimeout);
//Serial.println(duration);
if ( duration == 0 ) duration = EchoTimeout;
distance = duration * 343.2/10000.0 / 2.0; // 343.20 m/s ist die Schallgeschwindigkeit in 20°C Luft
return distance;
}
Man muss nämlich einfach nur eine Messung über den Trigger-Pin anfordern und dann die Zeit messen, bis der Echo-Pin high wird. Daraus kann man dann den Abstand errechnen.
esp8266-oled-ultraschall-tof.ino (klicken, um diesen Abschnitt aufzuklappen)
////////////////////////////////////////////////////////
// (C) 2023 by Oliver Kuhlemann //
// Bei Verwendung freue ich mich über Namensnennung, //
// Quellenangabe und Verlinkung //
// Quelle: http://cool-web.de/esp8266-esp32/ //
////////////////////////////////////////////////////////
#define PinSCL D1 // I2C-Bus für OLED und TOF
#define PinSDA D2
#define PinTrig D5 // für Ultraschall
#define PinEcho D6
#define EchoTimeout 30000 // ca. 5 Meter
#include <Arduino.h>
#include <Wire.h>
#include <SSD1306Wire.h> // für OLED (legacy: #include "SSD1306.h")
#include <VL53L0X.h> // https://github.com/pololu/vl53l0x-arduino/
// Initialize the TOF-sensor
VL53L0X TOFSensor;
//#define LONG_RANGE // für weitere Entfernungen, dafür ungenauer (besser im Dunkeln)
//#define HIGH_SPEED // dflt: ausgeglichen
//#define HIGH_ACCURACY // genauer
// Initialize the OLED display using SSD1306Wire
SSD1306Wire oled(0x3c, PinSDA, PinSCL); // ADDRESS, SDA, SCL
int errTOF=0;
void setup(void) {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PinTrig, OUTPUT);
pinMode(PinEcho, INPUT);
Serial.begin(115200); // wird nur für evtl. Debug-Ausgaben benötigt
Serial.print(F("Programmstart"));
Wire.begin();
TOFSensor.setTimeout(500);
if (!TOFSensor.init()) {
Serial.println("Konnte TOF-TOFSensor nicht finden oder initialisieren.");
errTOF=1;
} else {
// LONG_RANGE geht bis ca. 190 cm statt nur 125 cm, ist aber etwas ungenauer
#if defined LONG_RANGE
// lower the return signal rate limit (default is 0.25 MCPS)
TOFSensor.setSignalRateLimit(0.1);
// increase laser pulse periods (defaults are 14 and 10 PCLKs)
TOFSensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
TOFSensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#endif
// wenn man es schneller braucht (ungenauer)
#if defined HIGH_SPEED
// reduce timing budget to 20 ms (default is about 33 ms)
TOFSensor.setMeasurementTimingBudget(20000);
// wenn man besonders genau braucht (weniger Reichweite, langsamer)
#elif defined HIGH_ACCURACY
// increase timing budget to 200 ms
TOFSensor.setMeasurementTimingBudget(200000);
#endif
}
oled.init();
oled.flipScreenVertically(); // falls anders herum eingebaut
oled.clear();
oled.setTextAlignment(TEXT_ALIGN_LEFT);
oled.setFont(ArialMT_Plain_16);
}
void loop(void) {
float distance;
char tmp[100];
digitalWrite(LED_BUILTIN, LOW);
distance=getUltrasonicDistance() - 1.0; // -1.0 ist Abstand zur Breadboardkante
oled.clear();
oled.drawString(0, 0, F("US:")); // US = Ultraschall oder auch Ultrasonic
oled.drawString(0, 20, F("TOF:")); // TOF = Time-of flight
oled.drawString(100, 0, F("cm"));
oled.drawString(100, 20, F("cm"));
snprintf(tmp, sizeof(tmp), "%0.1f", distance);
oled.drawString(50, 0, tmp);
if (errTOF) {
oled.drawString(50, 20, "ERROR"); // TOF-Sensor konnte nicht init. werden
} else {
distance = TOFSensor.readRangeSingleMillimeters() / 10.0 - 2.0; // -2.0 ist Abstand zur Breadboardkante
// Serial.println(distance);
if (TOFSensor.timeoutOccurred()) {
oled.drawString(50, 20, "Timeout");
} else if (distance > 800) { // wenn die Range zu groß wird, gibt er immer 817 zurück
oled.drawString(50, 20, "> max");
} else {
snprintf(tmp, sizeof(tmp), "%0.1f", distance);
oled.drawString(50, 20, tmp);
}
}
oled.display();
digitalWrite(LED_BUILTIN, HIGH);
delay (200); // kleinerer Wert für mehr Aktualisierungen in der Sekunde
}
float getUltrasonicDistance() {
long duration;
float distance;
// Trigger-Pin triggern, um eine Messung anzustoßen
digitalWrite(PinTrig, LOW);
delayMicroseconds(2);
digitalWrite(PinTrig, HIGH);
delayMicroseconds(10);
digitalWrite(PinTrig, LOW);
// Die Zeitspanne messen, bis das Signal wieder zurückgekommen ist
// und den Echo-Pin auf High gezogen hat
duration = pulseIn(PinEcho, HIGH, EchoTimeout);
//Serial.println(duration);
if ( duration == 0 ) duration = EchoTimeout;
distance = duration * 343.2/10000.0 / 2.0; // 343.20 m/s ist die Schallgeschwindigkeit in 20°C Luft
return distance;
}
Testen der Sensoren
Für den Testaufbau richte ich das Breadboard auf meiner Schneidematte auf Zentimeter 5 aus und wähle dann Abstände von 5, 10, 15 und 22 Zentimetern.
Beide Sensoren schlagen sich gut, sind genau genug und die Ergebnisse stimmen weitgehend überein. Beide Sensoren sind schnell genug und es ist kein Problem fünf Messungen pro Sekunde durchzuführen.
Hin und wieder gibt es kleine Ausreißer in den Messungen. Mehrere Messungen durchzuführen und diejenigen zu eliminieren, die aufgrund irgendwelche Ursache zu sehr vom Mittelwert abweichen erscheint mir eine gute Idee für zuverlässige Ergebnisse.
Es stellt sich heraus, wie wichtig es ist, die Sensoren genau rechtwinklig auszurichten, weil ansonsten bei einer Schrägstellung auf die Tischplatte gezielt wird und von dort reflektiert wird und zu kurze Distanzen herauskommen. Auf dem Breadboard kann sich der Winkel durch eine kleine Unachtsamkeit schnell verändern.
Nahbereich
Es stellt sich heraus, dass der Ultraschall-Sensor im extremen Nachbereich unter 4 cm Probleme hat. Er zeigt zwar einen kleinen (aber zu hohen) Wert an, wenn der Abstand nur einen Zentimeter beträgt, dieser wird aber kleiner, wenn sich der Abstand vergrößert. Erst ab einem Abstand von ca. 5 cm ist die Messung mit dem Ultraschall-Sensor zuverlässig.
Der TOF-Sensor ist allerdings auch im extremen Nahbereich zuverlässig und funktioniert schon ab 0.5 cm. Im Nahbereich hat der TOF-Sensor also die Nase vorn und ist klarer Sieger.
Der TOF-Sensor hat nämlich einen weiteren Vorteil gegenüber dem Ultraschall-Sensor. Während der HC-SR04 den Schall in einem relativ breiten Kegel abstrahlt und wieder einfängt, strahlt der VL53L0X TOF nur in einem Winkel von 35 Grad ab und fängt den Laserstrahl in einem Winkel von 25° wieder ein.
Dadurch ist er genauer auf den Punkt und hat weniger Probleme mit Doppelabbildungen, bei denen der Sensor nicht entscheiden kann, ob das Objekt sehr nah oder sehr weit entfernt ist.
Der Ultraschall-Sensor funktioniert am besten in einem Bereich von 30 Grad um den Mittelpunkt herum, fängt aber auch Strahlen in einem Bereich bis 90 ° darum ein, was zu Fehlmessungen führen kann. Dies lässt sich eventuell mit Mehrfachmessung und Mittelung bzw. Eliminierung der Abweichungen korrigieren.
Fernbereich
Allerdings steigt der TOF-Sensor schon bei 125 cm Objektentfernung im Normal-Modus aus. Auch die Benutzung des Long Range-Modus erweitert den Bereich nur auf ca. 190 cm. Um Räume zu vermessen reicht das nicht aus.Der Ultraschall-Sensor funktioniert hingegen auch mit höheren Abständen von bis über 5 Metern (mehr konnte ich nicht messen). Mit ihm kann man also auch Räumen vermessen. Wie es mit großen Hallen aussieht, kann ich nicht sagen.
Eigentlich hätte ich erwartet, dass man mit einem Laser größere Entfernungen genauer messen kann, aber wurde hier überrascht bzw. vom TOF-Sensor enttäuscht. ADer Fairness halber: ST gibt im Datenblatt auch an, dass der Sensor nur bis 2 m funktioniert.
Im Fernbereich gewinnt also der Ultraschall-Sensor. Und auch bei 5 Metern ist er noch schnell genug für mehrere Messungen in der Sekunde.
Störfestigkeit
Als letztes habe ich getestet, wie störanfällig gegen äußere Einflüsse die Sensoren sind.Bei dem Ultraschall-Sensor kann ich mir nur vorstellen, dass er gegen extremen Lärm oder eine andere Ultraschall-Quelle gestört werden kann. So viel Lärm konnte ich allerdings nicht machen und selbst ein anderer Ultraschall-Sender müsste genau im selben Augenblick senden; und diese Zeiträume sind doch ziemlich kurz.
Bei dem TOF-Sensor, der mit einem Infrarot-Laser funktioniert, hätte ich mir vorstellen können, dass er doch helles Licht, durch eine Infrarotlichtquelle oder durch Laserstrahlung gestört werden könnte.
Doch weder eine helle Taschenlampe, oder eine Infrarot-Fernbedienung oder ein stärkerer grüner Laserpointer konnten den TOF-Sensor aus dem Konzept bringen oder das Messergebnis verfälschen.
Punkt an beide Sensoren, die sich als störfest beweisen.
Fazit / Zusammenfassung
Es lassen sich folgende Vergleiche und Ergebnisse festhalten:Feature | Ultraschall HC-SR04 | TOF-Modul VL53L0X |
---|---|---|
Abmessungen Modul | groß: 45.4 x 20.5 x 17.8 mm | sehr klein: 24.9 x 10.7 x 3.6 mm |
Spannungsversorgung | zwingend 5V | 2.7 bis 5V |
Funktionsart | Ultraschall | Infrarot-Laser |
Effektiver Messbereich | 5 cm bis > 500 cm | 0.5 cm bis 125 cm (Normalbetrieb) 0.5 cm bis 190 cm (Long Range, ungenauer) |
Störfestigung Schall | störfest | störfest |
Störfestigung Licht/IR/Laser | störfest | störfest |
Für mich ist der Klassiker, das Ultraschall-Modul HC-SR04 der Sieger in diesem Vergleich. Es ist günstig und liefert gute Arbeit in dem Entfernungsbereich, den man meist braucht. Das der TOF-Sensor schon bei 1.25 m aussteigt, ist enttäuschend.
Allerdings würde ich mir ein Update für den HC-SR04 wünschen, so dass er auch mit 3.3V zuverlässig funktioniert.
Der große Vorteil des TOF-Moduls ist seine Größe und wahrscheinlich auch ein geringerer Stromverbrauch (jaja, ich weiß, das heißt richtig Leistungsaufnahme). Man kann ihn eigentlich überall verbauen, ohne dass er auffällt. Wenn die Baugröße oder die Nahbereichsgenauigkeit bis 5 cm das entscheidene Kriterium ist, dann würde ich auf ihn zurückgreifen. Allerdings ist er ein bisschen teurer, aber doch noch bezahlbar.