VL53L0X und VL53L1X – ToF Abstandssensoren

Über den Beitrag

In meiner Reihe über Licht-, Gestik-, Bewegungs- und Abstandssensoren, die ich mit einer Gesamtübersicht abschließen werde, möchte ich diesmal die Abstandssensoren VL53L0X und VL53L1X vorstellen. Dabei handelt es sich um die großen Brüder des VL6180X, über den ich in meinem letzten Beitrag geschrieben habe. Ich werde zunächst auf die Eigenschaften der eigentlichen Sensoren und der Module eingehen. Dann werde ich Bibliotheken vorstellen, mit denen man die Funktionen des VL53L0X und VL53L1X bequem nutzen kann. 

Der größte Unterschied zwischen den drei Sensoren ist ihre Reichweite. Den VL6180X könnt Ihr bis zu Entfernungen von 20 cm einsetzen. Der VL53L0X und VL53L1X haben wesentlich höhere Reichweiten von bis zu 200 bzw. 400 cm. Datenblätter für den VL53L0X und VL53L1X gibt es hier bzw. hier.  

Das Messprinzip

Die Sensoren funktionieren nach dem Time-of-Flight (ToF) Prinzip. Sie besitzen dazu einen IR Laser dessen reflektierte Strahlen hinsichtlich ihrer Flugzeit ausgewertet werden. Bei dem IR Laser handelt es sich um einen Vertical Cavity Surface-Emitting Laser (VCSEL) mit der für den Menschen unsichtbaren Wellenlänge von 940 Nanometer. Das reflektierte Licht wird von einem Photodioden Array detektiert. Dabei verwenden die Sensoren sogenannte Single Photon Avalanche Diodes (SPADs).

VL53L0X und VL53L1X erreichen eine Auflösung in Millimetern. Um einen Millimeter zurückzulegen, benötigt Licht ca. 3.3 x 10-12 Sekunden. Daher ist es erstaunlich, dass ein Massenartikel so etwas auflösen kann. Wenn ein Computer oder Microcontroller in dieser Zeit nur einen einzigen Takt ausführte, entspräche das schon einer Taktfrequenz von 330 GHz. Und mit einem einzelnen Takt hat man ja noch lange keine Rechenoperation durchgeführt. 

Für die, die den letzten Beitrag nicht gelesen haben: wer sich für die Details der Methode interessiert, der kann hier noch einen Artikel dazu lesen oder sich hier auf Wikipedia schlau machen. 

Grundlegende Eigenschaften

VL53L0X und VL53L1X - die blanken Sensoren
Die blanken Sensoren – links: VL53L0X, rechts: VL53L1X

VL53L0X vs VL53L1X – Gemeinsamkeiten

Allgemeines

VL53L0X und VL53L1X sind im Gegensatz zum VL6180X reine Abstandssensoren. Beide vertragen einen Spannungsbereich zwischen 2.6 und 3.5 Volt. Das gilt aber nur für die eigentlichen Bausteine. Bei den Modulen hingegen hängt der Spannungsbereich von der individuellen Ausführung ab. Beide Sensoren haben identische Pinouts. 

Kalibrierung

Beide Sensoren können bezüglich verschiedener Parameter kalibriert werden, die insbesondere dann zum Tragen kommen, wenn man die Teile verbaut. So könnt Ihr z.B. einen Abstandsoffset einstellen.

Verbaut ihr den VL53L0X oder VL53L1X hinter einem Abdeckglas, dann kommt es durch die Reflexion zum sogenannten Cross-Talk Effekt, der zu Fehlern in der Abstandsmessung führt. Deshalb könnt ihr auch diesen Effekt „herauskalibrieren“. Für weitere Kalibrierungen schaut bitte in die Datenblätter. 

Kommunikation und Ansteuerung über APIs

Die Kommunikation läuft über I2C. Die voreingestellte I2C Adresse (0x29) könnt ihr über Befehle und nicht wie sonst üblich über Adresspins verändern. Allerdings vergessen beide Sensoren die neue Adresse wieder wenn sie vom Strom getrennt werden. Über geschicktes Nutzen der XSHUT Pins (werden noch besprochen) könnt ihr aber eine Prozedur erstellen, die die Adressänderung bei jedem Einschalten erneut durchführt.

Die Ansteuerung von VL53L0X und VL53L1X ist etwas ungewöhnlich. Denn normalerweise ist man es ja gewohnt Datenblätter mit Registerverzeichnissen zur Verfügung gestellt zu bekommen. Hier hingegen hat sich der Hersteller STMicroelectronics dazu entschieden sogenannte APIs (Application Programming Interfaces) zur Verfügung zu stellen. Ich bin nicht der erste, der sich darüber gewundert hat und auch nicht der einzige, der gerne eine Registerdokumentation gehabt hätte. So gibt es hierzu auch eine Diskussion in der STM Community, einschließlich einer Stellungnahme des Herstellers. 

Die Beschreibung der VL53L0X API findet ihr hier, für den VL53L1X schaut hier

Interrupts

Beide Sensoren haben Interruptfunktionen. Ihr könnt euch über einen Interrupt informieren lassen, wenn ein neuer Messwert vorliegt. Oder ihr stellt ein Level ein oberhalb oder unterhalb dessen ein Interrupt ausgelöst wird. Alternativ könnt ihr auch ein Fenster definieren innerhalb oder außerhalb dessen ein Interrupt ausgelöst wird. 

VL53L0X vs. VL53L1X – Unterschiede

Reichweite

Wie schon erwähnt ist der offensichtlichste Unterschied zwischen dem VL53L0X und VL53L1X die Reichweite. Unter optimalen Bedingungen, d. h. bei guter Reflexion der zu detektierenden Oberfläche und wenig Störlicht, könnt ihr mit dem VL53L0X bis zu zwei Meter erreichen, mit dem VL53L1X hingegen bis zu vier Meter. 

Messprofile

Am VL53L0X könnt ihr diverse Parameter ändern um die Leistung für verschiedene Anwendungsbedingungen zu optimieren. Dazu gehört vor allem die maximale Messzeit (Timing Budget),  aber auch die zulässige Streuung der Ergebnisse, die Laser Pulsperioden und das Minimum der Signalrate. Die Streuung wird als Sigma in mm angegeben, da Störsignale zeitlich versetzt zum Referenzwert detektiert werden und diese Abweichung über die Lichtgeschwindigkeit einer Entfernung entspricht.

Ihr seid relativ frei in der Wahl der Parameter, müsst aber aufpassen, dass die Einstellungen auch harmonieren. Denn im schlechtesten Fall überschreitet ihr immer wieder das Timing Budget ohne dass ein gültiger Messwert vorliegt. Da ist es günstig, dass es in der Beschreibung der API für den VL53L0X vorgefertigte Profile gibt:

Messprofile des VL53L0X
Messprofile des VL53L0X

Der VL53L1X kennt die drei Distanzmodi Long, Medium und Short. Für diese Modi sind die Messparameter in der API vordefiniert bzw. verknüpft. Ihr könnt einige der Parameter jedoch ändern um z.B. unter ungünstigen Bedingungen noch Messwerte zu erzeugen. Wie akkurat diese Messergebnisse dann noch sind ist eine andere Frage. 

Die Reichweite hängt je nach Modus unterschiedlich stark vom Umgebungslicht ab. Hier die Werte im Dunkeln / bei starkem Umgebungslicht bei 88% Reflexion und Timing Budget von 100 Millisekunden: 

  • Short: 136 cm / 135 cm
  • Medium: 290 cm / 76 cm
  • Long: 360 cm / 73 cm

Die Auswahl „Long“ beim VL53L1X ist also keine Garantie, dass ihr unter allen Bedingungen wirklich große Reichweiten erreicht! Bei viel Licht erreicht ihr mit „Short“ sogar größere Reichweiten.  

Neben der Wahl des Distanzmodus wird die Reichweite und Genauigkeit des VL53L1X auch durch das Timing Budget beeinflusst. 20 Millisekunden ist die kürzeste Auswahl, die nur im Short Modus funktioniert. Mit 140 Millisekunden können im Dunkeln bei hoher Reflexion die 4 Meter erreicht werden. Im Datenblatt gibt es graphische Darstellungen der Abhängigkeit von Distanz und Wiederholbarkeit vs. Timing Budget. 

Messfrequenz

Beim VL53L0X könnt ihr bezüglich der Messfrequenz folgende Modi einstellen:

  • Single Ranging: einzelne Messung „auf Anfrage“ (polling)
  • Continous Ranging: ist eine Messung beendet, wird sofort die nächste gestartet
  • Timed Ranging: kontinuierliche Messung mit einstellbaren Pausen dazwischen

Bei dem VL53L1X gibt es nur den Continous Mode und den Timed Ranging Mode. 

(De-)Aktivierung der Spads

Der VL53L1X besitzt zur Detektion ein 16 x 16 Spad Array. Standardmäßig sind alle Spads aktiviert. Dadurch entsteht ein Erfassungskegel (FoV = Field of View) mit einer Öffnung von 27°. Durch Deaktivierung eines Teils der Spads lässt sich der Kegel bis auf 15° bei 4 x 4 aktivierten Spads verengen und die Richtung (ROI = Region of Interest) vorgeben. Der VL53L0X kennt diese Optionen nicht. 

VL53L0X und VL53L1X Module

Verschiedene VL53L0X und VL53L1X Module

Preise

VL53L0X Module gibt es z. B. bei Amazon in einer breiten Preisspanne von ca. 7 Euro (einschl. Versand) bis über 20 Euro. VL53L1X Module habe ich nicht unter 16 Euro bei Amazon gesehen (Stand August 2019). Das hängt sicherlich damit zusammen, dass es den Sensor erst seit Anfang 2018 gibt. Der Preis wird sicherlich noch runtergehen.

Eigenschaften

Im Gegensatz zu den blanken Sensoren haben die Module in der Regel Spannungsregulatoren, so dass ihr sie meist zwischen 2.8 und 5.5 Volt betreiben könnt. Prüft dazu die Angaben des Lieferanten.

Die meisten Module haben sechs Ein-/Ausgänge. Neben GND / VCC und SDA/SCL für die I2C Kommunikation sind das XSHUT und GPIO1. Manchmal sind die Bezeichnungen etwas abweichend. XSHUT dient dem Ausschalten des Moduls. Dazu müsst Ihr XSHUT auf LOW setzen. Ein modulinterner Pull-Up Widerstand setzt den Pin auf HIGH, d.h. Ihr könnt ihn einfach unverbunden lassen, wenn ihr die Funktion nicht nutzen wollt. GPIO1 ist der Interruptausgang. Nutzt Ihr keine Interrupts, könnt ihr auch ihn unverbunden lassen. Die Interruptpolarität lässt sich einstellen. 

Beschaltung

Anschluss eines VL53L0X (Modell Adafruit) an einen Arduino UNO
Anschluss eines VL53L0X (Modell Adafruit) an einen Arduino UNO

Die Beschaltung der VL53L0X und VL53L1X Module ist identisch. Pull-Up Widerstände für die I2C Leitungen brauchte ich nicht. Das müsst ihr selbst probieren. Pin 3 dient als Interruptpin. Die LED an Pin 13 wird für einen der Beispielsketche benötigt. 

Bibliotheken

Ich habe einige Bibliotheken für die Sensoren ausprobiert. Leider habe ich für den VL53L0X keine Bibliothek gefunden, mit der ich voll zufrieden war. Insbesondere waren die Interruptfunktionen nicht implementiert. Die Abstandsmessung selbst funktioniert aber z. B. mit der Bibliothek von Adafruit oder mit der von Pololu. Bei der Adafruit Bibliothek wird ein Beispielsketch für den Betrieb von zwei VL53L0X mitgeliefert. Die Prozedur wird zudem hier im Learning Bereich von Adafruit beschrieben. Insgesamt gefiel mir aber die Bibliothek von Pololu besser. 

Für den VL53L1X ist die Bibliothek von Sparkfun mein Favorit, denn in ihr sind alle aus meiner Sicht wichtigen Funktionen implementiert worden. Ihr bekommt sie hier auf Github oder ihr sucht sie über die Bibliotheksverwaltung der Arduino IDE.

Steuerung des VL53L0X mit der Pololu Bibliothek

Der von Pololu mitgelieferte Beispielsketch für Einzelmessungen hat die weiter oben genannten Messprofile aus dem User Manual der VL53L0X API implementiert. Die Voreinstellung ist der Default Mode. Wollt ihr in den Long Range, High Speed oder High Accuracy Modus, dann müsst ihr lediglich die entsprechenden „#define“ Zeilen entkommentieren. Ihr könnt auch noch die Bedingungen für diese Modi ändern. Allerdings – wie schon vorher erwähnt – muss das natürlich alles zusammenpassen. 

/* This example shows how to get single-shot range
 measurements from the VL53L0X. The sensor can optionally be
 configured with different ranging profiles, as described in
 the VL53L0X API user manual, to get better performance for
 a certain application. This code is based on the four
 "SingleRanging" examples in the VL53L0X API.

 The range readings are in units of mm. */

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

VL53L0X sensor;

// Uncomment this line to use long range mode. This
// increases the sensitivity of the sensor and extends its
// potential range, but increases the likelihood of getting
// an inaccurate reading because of reflections from objects
// other than the intended target. It works best in dark
// conditions.

//#define LONG_RANGE

// Uncomment ONE of these two lines to get
// - higher speed at the cost of lower accuracy OR
// - higher accuracy at the cost of lower speed

//#define HIGH_SPEED
//#define HIGH_ACCURACY

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

  sensor.init();
  sensor.setTimeout(500);

#if defined LONG_RANGE
  // lower the return signal rate limit (default is 0.25 MCPS)
  sensor.setSignalRateLimit(0.1);
  // increase laser pulse periods (defaults are 14 and 10 PCLKs)
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
  sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
#endif

#if defined HIGH_SPEED
  // reduce timing budget to 20 ms (default is about 33 ms)
  sensor.setMeasurementTimingBudget(20000);
#elif defined HIGH_ACCURACY
  // increase timing budget to 200 ms
  sensor.setMeasurementTimingBudget(200000);
#endif
}

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

  Serial.println();
}

 

Zu der Bibliothek gibt es auch noch einen Beispielsketch für den Continous Modus. Der macht aber eigentlich nur in Verbindung mit Interrupts wirklich Sinn. Und die sind anscheinend in der Bibliothek nicht implementiert. 

/* This example shows how to use continuous mode to take
range measurements with the VL53L0X. It is based on
vl53l0x_ContinuousRanging_Example.c from the VL53L0X API.

The range readings are in units of mm. */

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

VL53L0X sensor;

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

  sensor.init();
  sensor.setTimeout(500);

  // 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();
}

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

  Serial.println();
}

 

Steuerung des VL53L1X mit der Sparkfun Bibliothek

Als Einstieg in die Sparkfun Bibliothek empfehle ich den Beispielsketch „Example2_SetDistanceMode.ino“. Die Bibliothek hat die Distance Modes „Short“ (bis 1.3 Meter) und „Long“ (bis 4 Meter) implementiert. Ansonsten werden in dem Sketch keine weiteren Einstellmöglichkeiten aufgezeigt. 

/*
  Reading distance from the laser based VL53L1X
  By: Nathan Seidle
  Revised by: Andy England
  SparkFun Electronics
  Date: April 4th, 2018
  License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

  SparkFun labored with love to create this code. Feel like supporting open source hardware? 
  Buy a board from SparkFun! https://www.sparkfun.com/products/14667

  This example prints the distance to an object.

  Are you getting weird readings? Be sure the vacuum tape has been removed from the sensor.
*/

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

//Optional interrupt and shutdown pins.
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3

SFEVL53L1X distanceSensor;
//Uncomment the following line to use the optional shutdown and interrupt pins.
//SFEVL53L1X distanceSensor(Wire, SHUTDOWN_PIN, INTERRUPT_PIN);

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

  Serial.begin(9600);
  Serial.println("VL53L1X Qwiic Test");

  if (distanceSensor.begin() == true)
  {
    Serial.println("Sensor online!");
  }
  
  distanceSensor.setDistanceModeShort();
  //distanceSensor.setDistanceModeLong();
}

void loop(void)
{
  distanceSensor.startRanging(); //Write configuration bytes to initiate measurement

  int distance = distanceSensor.getDistance(); //Get the result of the measurement from the sensor

  distanceSensor.stopRanging();

  Serial.print("Distance(mm): ");
  Serial.print(distance);

  float distanceInches = distance * 0.0393701;
  float distanceFeet = distanceInches / 12.0;

  Serial.print("\tDistance(ft): ");
  Serial.print(distanceFeet, 2);

  Serial.println();
}

 

Einen guten Überblick über die in der Bibliothek implementierten Einstellmöglichkeiten bekommt ihr, wenn ihr Euch die öffentlichen Funktionen der Bibliotheksdatei Sparkfun_VL53L1X anschaut. Diese sind sehr gut kommentiert: 

bool init(); //Deprecated version of begin
  bool begin(); //Initialization of sensor
  bool checkID(); //Check the ID of the sensor, returns true if ID is correct
  void sensorOn(); //Toggles shutdown pin to turn sensor on and off
    void sensorOff(); //Toggles shutdown pin to turn sensor on and off
  VL53L1X_Version_t getSoftwareVersion(); //Get's the current ST software version
  void setI2CAddress(uint8_t addr); //Set the I2C address
  int getI2CAddress(); //Get the I2C address
  void clearInterrupt(); // Clear the interrupt flag
  void setInterruptPolarityHigh(); //Set the polarity of an active interrupt to High
  void setInterruptPolarityLow(); //Set the polarity of an active interrupt to Low
  uint8_t getInterruptPolarity(); //get the current interrupt polarity
  void startRanging(); //Begins taking measurements
  void stopRanging(); //Stops taking measurements
  bool checkForDataReady(); //Checks the to see if data is ready
  void setTimingBudgetInMs(uint16_t timingBudget); //Set the timing budget for a measurement
  uint16_t getTimingBudgetInMs(); //Get the timing budget for a measurement
  void setDistanceModeLong(); //Set to 4M range
  void setDistanceModeShort(); //Set to 1.3M range
  uint8_t getDistanceMode(); //Get the distance mode, returns 1 for short and 2 for long
  void setIntermeasurementPeriod(uint16_t intermeasurement); //Set time between measurements in ms
  uint16_t getIntermeasurementPeriod(); //Get time between measurements in ms
  bool checkBootState(); //Check if the VL53L1X has been initialized
  uint16_t getSensorID(); //Get the sensor ID
  uint16_t getDistance(); //Returns distance
  uint16_t getSignalPerSpad(); //Returns the average signal rate per SPAD (The sensitive pads that detect light, the VL53L1X has a 16x16 array of these) in kcps/SPAD, or kilo counts per second per SPAD.
  uint16_t getAmbientPerSpad(); //Returns the ambient noise when not measuring a signal in kcps/SPAD.
  uint16_t getSignalRate(); //Returns the signal rate in kcps. All SPADs combined.
  uint16_t getSpadNb(); //Returns the current number of enabled SPADs
  uint16_t getAmbientRate(); // Returns the total ambinet rate in kcps. All SPADs combined.
  uint8_t getRangeStatus(); //Returns the range status, which can be any of the following. 0 = no error, 1 = signal fail, 2 = sigma fail, 7 = wrapped target fail
  void setOffset(int16_t offset); //Manually set an offset in mm
  int16_t getOffset(); //Get the current offset in mm
  void setXTalk(uint16_t xTalk); //Manually set the value of crosstalk in counts per second (cps), which is interference from any sort of window in front of your sensor.
  uint16_t getXTalk(); //Returns the current crosstalk value in cps.
  void setDistanceThreshold(uint16_t lowThresh, uint16_t hiThresh, uint8_t window);//Set bounds for the interrupt. lowThresh and hiThresh are the bounds of your interrupt while window decides when the interrupt should fire. The options for window are shown below.
  //0: Interrupt triggered on measured distance below lowThresh.
  //1: Interrupt triggered on measured distance above hiThresh.
  //2: Interrupt triggered on measured distance outside of bounds.
  //3: Interrupt triggered on measured distance inside of bounds.
  uint16_t getDistanceThresholdWindow(); //Returns distance threshold window option
  uint16_t getDistanceThresholdLow(); //Returns lower bound in mm.
  uint16_t getDistanceThresholdHigh(); //Returns upper bound in mm
  void setROI(uint16_t x, uint16_t y); //Set the height and width of the ROI in SPADs, lowest possible option is 4. ROI is always centered.
  uint16_t getROIX(); //Returns the width of the ROI in SPADs
  uint16_t getROIY(); //Returns the height of the ROI in SPADs
  void setSignalThreshold(uint16_t signalThreshold); //Programs the necessary threshold to trigger a measurement. Default is 1024 kcps.
  uint16_t getSignalThreshold(); //Returns the signal threshold in kcps
  void setSigmaThreshold(uint16_t sigmaThreshold); //Programs a new sigma threshold in mm. (default=15 mm)
  uint16_t getSigmaThreshold(); //Returns the current sigma threshold.
  void startTemperatureUpdate(); //Recalibrates the sensor for temperature changes. Run this any time the temperature has changed by more than 8°C
  void calibrateOffset(uint16_t targetDistanceInMm); //Autocalibrate the offset by placing a target a known distance away from the sensor and passing this known distance into the function.
  void calibrateXTalk(uint16_t targetDis

 

Ich habe dann noch einen eigenen Sketch geschrieben, in dem ich ein Interruptfenster definiert habe. Bei Erfassung eines Abstandes innerhalb der Limits wird ein Interrupt ausgelöst, die LED an Pin 13 leuchtet auf und es wird eine Meldung auf dem seriellen Monitor ausgegeben. Dazu habe ich dem Sketch noch eine Funktion spendiert, die zu Beginn einige der Einstellungen des VL53L1X auf dem seriellen Monitor ausgibt. 

#include <ComponentObject.h>
#include <RangeSensor.h>
#include <SparkFun_VL53L1X.h>
#include <vl53l1x_class.h>
#include <vl53l1_error_codes.h>


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

//Optional interrupt and shutdown pins.
#define SHUTDOWN_PIN 2
#define INTERRUPT_PIN 3
volatile bool event = false;
byte ledPin = 13;

//SFEVL53L1X distanceSensor;
//Uncomment the following line to use the optional shutdown and interrupt pins.
SFEVL53L1X distanceSensor(Wire, SHUTDOWN_PIN, INTERRUPT_PIN);

void setup() {
  Wire.begin();
  distanceSensor.sensorOn();
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), blink, FALLING);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Interrupt Test");

  if (distanceSensor.begin() == true) {
    Serial.println("Sensor online!");
  }

  distanceSensor.setInterruptPolarityLow();
  distanceSensor.setDistanceThreshold(300, 1000, 3);
  showSettings();
  delay(2000); // um Zeit zu haben die Settings zu sehen
  distanceSensor.startRanging();
  event = false;
  distanceSensor.clearInterrupt();

}

void loop(void) {
  if (event) {
    int distance = distanceSensor.getDistance();
    Serial.print("Interrupt! Current distance: ");
    Serial.println(distance);
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    event = false;
    distanceSensor.clearInterrupt();
  }
}

void blink() {
  event = true;
}

void showSettings() {
  Serial.print("Interrupt polarity is: ");
  byte interruptPolarity = distanceSensor.getInterruptPolarity();
  if (interruptPolarity == 0) {
    Serial.println("Low");
  }
  if (interruptPolarity == 1) {
    Serial.println("High");
  }
  Serial.print("Offset [mm]: ");
  unsigned int offset = distanceSensor.getOffset();
  Serial.println(offset);
  Serial.print("Distance Mode: ");
  byte distMode = distanceSensor.getDistanceMode();
  if (distMode == 1) {
    Serial.println("Short Mode");
  }
  else if (distMode == 2) {
    Serial.println("Long Mode");
  }
  unsigned int timingBudget = distanceSensor.getTimingBudgetInMs();
  Serial.print("Timing Budget: ");
  Serial.println(timingBudget);

  unsigned int interMeasurementPeriod = distanceSensor.getIntermeasurementPeriod();
  Serial.print("Inter Measurement Period [ms]: ");
  Serial.println(interMeasurementPeriod);

  unsigned int spads = distanceSensor.getROIX();
  Serial.print("Active Spad Array, x: ");
  Serial.print(spads);
  spads = distanceSensor.getROIY();
  Serial.print(", y: ");
  Serial.println(spads);
}

 

Festgestellte Probleme

Die meisten Funktionen funktionieren wunderbar, trotzdem habe ich ein paar kleinere Probleme festgestellt:

  • Ändert man die I2C Adresse mit setI2CAddress(), dann wird daraus eine um ein Bit verschobene Adresse. Intern wird anscheinend das Read/Write Bit zugefügt. 
  • Das Spad Array konnte ich nur auf minimal 11 x 11 reduzieren. Da drunter gab es keine vernünftigen Ergebnisse mehr – egal was ich sonst noch eingestellt habe 
  • Ab und zu macht der VL53L1X nach Änderungen von Einstellungen nicht das was er soll. Dann hilft es ihn zwischenzeitlich kurz vom Strom zu nehmen. Das gilt übrigens auch für den VL53L0X.

Danksagung

Das Männchen auf dem Beitragsbild stammt von Peggy und Marco Lachmann-Anke auf Pixabay. Von Holger Langmaier stammt das Maßband, auch auf Pixabay. Das Fritzing Schema des VL53L0X stammt von Adafruit auf Github. Dann gilt mein Dank natürlich Pololu und Sparkfun für die Bibliotheken.    

57 thoughts on “VL53L0X und VL53L1X – ToF Abstandssensoren

  1. Hallo. kann jemand mir helfen?

    Ich habe solches Problem 2xVL53L0X aus Aliexpress und 1xMPU6050 und Arduino Mega. Alleine die Sensore mit den Bord arbeiten top, aber zusammen in einem Sketch, kommt Verlansammerung des Prozes, sogar stop und das meistens bei Winkelmessung von Gyroskope in MPU6050. Idee?
    Ich nutze Adafruit_VL53L0X und Jeff Rolberg library für IMU sensor. Die Sensoren nehemen Strom von Arduino. keine Pullup wiederstande, direkte verbindung zu pin 20 und 21.

    1. Hallo, eine sehr spezielle Frage. Bei zwei Bibliotheken ist die Fehlersuche natürlich schwierig, besonders weil die VL530X Bibliothek ziemlich komplex ist. Ich kann nur raten. Fragst du die Sensoren in fester Reihenfolge hintereinander ab und ist für die VL530X der Single Measurement Mode eingestellt? Wenn ich das richtig sehe dann ist die Abfrage mit der Funktion rangingTest() im Single Mode. Eine Messung mit mit dem VL530X nimmt im Default Mode 30 Millisekunden in Anspruch. Bei zwei VL530X sind das schon 60 Millisekunden. Dann kannst du nur alle 60 Millisekunden den MPU6050 abfragen. Im Continuous Mode musst du nicht auf das Ergebnis warten, das geht schneller.
      Du könntest mir deinen Sketch mal zusenden (wolfgang.ewald@wolles-elektronikkiste.de). Dann schaue ich mal rein. Ich verspreche aber lieber nichts – ich kann nicht viel Zeit investieren.

  2. Hallo,
    ich möchte mir für meine Gartenzisterne eine Niveaumessung mit dem v53l1x bauen. Dazu hab ich mir den Code „VL53L1X_Interrupt_Example.ino“ kopiert und im Prinzip funktioniert es auch. Aber ich vermute, dass der Messkegel zu breit ist. Am Ende des Codes werden die Werte von ROIX und ROIY ausgelesen (16×16). Wie müsste die Weiterführung des Codes sein, um neue Werte für X und Y (z.B. 8×8) zu setzen. Mein bescheidenes Programmierwissen gibt das nicht her. Für Hilfe wäre ich sehr dankbar. Beste Grüße.

    1. Hallo Ludwig, für die Einstellung der Spads gibt es die Funktion setROI(roix, roiy). Für 8×8 also setROI(8,8). Die Funktion kommt ins Setup. Ich hatte Probleme, wenn ich unter 11×11 gegangen bin. Und wahrscheinlich wird die Reichweite geringer. Viel Erfolg & viele Grüße, Wolfgang

      1. Hallo Wolfgang,
        danke erstmal für die schnelle Info. Wenn ich jetzt z.B. „setROI(11,11);“ ins setup schreibe kommt die Fehlermeldung „’setROI‘ was not declared in this scope“. Hab schon rumprobiert, komm aber nicht zu einer Lösung. In der Lib wird die Funktion mit „void setROI(uint16_t x, uint16_t y); “ angegeben. Was muss ich tun, um den Code zum Laufen zu bringen? Am Ursprungs-Code hab ich bis auf Einfügen von setROI… nichts verändert. Gruß Ludwig

        1. Du musst noch den Objektnamen davor setzen, also distanceSensor.setROI(11,11). Dann sollte es gehen.

  3. Hallo!
    Ich habe hier eine sehr spezielle Frage / Anwendung zu dem VL53L0X:
    Ich benutze in einer Anwendung 2 VL53L0X gleichzeitig. Damit das geht, vergebe ich jedem Sensor eine eigene Adresse. Das geht auch ganz gut mit den Beispielen von Pololu oder Adufruit. Jedoch ist die Anwendung batteriebetrieben, und ich messe nur alle 15min. Dazwischen ist der uC (LoRaWAN Heltec cubecell) im Deep Sleep Mode. In der Zeit möchte ich die Spannung von den Sensoren wegnehmen und den XShut-Pin auf Low setzen (sonst benötigt der Sensor teilw. Strom), um eine maximale Batterielebensdauer zu erreichen.
    Jedoch nach dem Aufwecken und initialisieren (Adressen wieder neu vergeben etc.) der Sensoren (bei Adafruit geht das über die Funktion „setID“) klappt das nicht mehr. Die Sensoren gehen in Fehler. Erst ein Neustart / Reset bringt alles wieder zum laufen. Nach dem Deep Sleep wieder das Gleiche 🙁
    Was kann da das Problem sein? So viel kann man da doch nicht falsch machen, oder? Nach dem Deep Sleep schalte ich wieder die Spannung für die Sensoren zu warte bis diese stabil anliegt. Dann mache ich die Initialisierung der Sensoren…Für Tipps wäre ich dankbar.
    Beste Grüße
    Martin

    1. Hallo Martin,

      aus der Ferne und bei einem µC den ich noch nicht ausprobiert habe ist das mit der Fehleranalyse nicht so einfach.

      Vom Prinzip her sehe ich das so wie du: wenn die VL53L0X abschaltest und vom Strom trennst, dann sollten sie im Prinzip mit derselben Prozedur wieder initialisierbar sein wie beim frischen Start.

      Vielleicht findest du hier noch einen Hinweis:
      https://learn.adafruit.com/adafruit-vl53l0x-micro-lidar-distance-sensor-breakout/arduino-code

      Bekommst du denn eine Fehlermeldung beim erneuten Initialisieren? Die SetID Funktion aus den Adafruit Beispielen sollte ja „Failed to boot first VL53L0X“ liefern, wenn das nicht funktioniert.

      Du könntest auch mal die Initialisierung mit lox1.begin(LOX1_ADDRESS, true) vornehmen. Das True schaltet die Debug Funktion der Bibliothek an und du bekommst mehr Meldungen.

      Oder es ist irgendetwas auf der µC Seite. Vielleicht mag er nicht, dass irgendwelche Variablen nochmal initialisiert werden?

      VG, Wolfgang

      1. Hallo Wolfgang,

        ja, ich bekomme die Fehlermeldung „Failed to boot first VL53L0X“.
        Die Debug-Funktion habe ich mal aktiviert. Wenn ich die Spannung nicht wegnehme läuft alles sauber durch (auch das mehrmalige initialisieren der Variablen ist kein Problem) und die Debug-Meldung sieht wie folgt aus:
        VL53L0X Info:
        Device Name: VL53L0X ES1 or later, Type: VL53L0X, ID: VL53L0CBV0DH/1$1
        Rev Major: 1, Minor: 1
        VL53L0X: StaticInit
        VL53L0X: PerformRefSpadManagement
        refSpadCount = 4, isApertureSpads = 0
        VL53L0X: PerformRefCalibration
        VL53L0X: SetDeviceMode

        Wenn ich zwischendurch die Spannung komplett wegschalte (VCC = 0V UND XShut auf Low) erhalte ich folgende Fehlermeldung aus dem Debug heraus:

        VL53L0X Info:
        Device Name: VL53L0X ES1 or later, Type: VL53L0X, ID: 
        Rev Major: 1, Minor: 15
        Error expected cut 1.1 but found 1,15
        VL53L0X Error: -5
        Failed to boot first VL53L0X

        Aber wer kann jetzt damit was anfangen?
        Ich werde nochmal lesen, ob unter dem Link von Dir etwas zu finden ist…
        Ansonsten bin ich natürlich dankbar für weitere Hinweise!

        Beste Grüße
        Martin

        1. Ich habe ein bisschen in der Bibliothek gewühlt und das zum Error -5 gefunden:

          #define VL53L0X_ERROR_NOT_SUPPORTED ((VL53L0X_Error)-5)
          /*!< Function is not supported in current mode or configuration */ Auch nicht wirklich hilfreich. Und Rev Major / Rev Minor haben irgendetwas mit der Sensor Version zu tun. Aber da ja alles funktioniert, wenn du die Sensoren frisch startest, glaube ich nicht, dass da das Problem liegt. Tut mir leid, ich glaube ich kann die da aus der Ferne wenig helfen.

        2. Hallo Martin

          ich nutzte zwar nicht den Deep Sleep oder schalte die VCC der Sensoren ganz weg, jedoch hatte ich einige Mühe zwei Sensoren mit der VL53L0X Pololu Bibliothek (1.3.0) zum laufen zu bringen.
          Ich habe dann die SetID Funktion aus der Adafruit Bibliothek übernommen und vor und nach der Initialisierung einen I2C Scan gemacht um die Adressen zu kontrollieren.

          Als alles funktionierte, habe ich den I2C Scan rausgenommen und promt ließ sich einer der beiden Sensoren nicht mehr Initialisieren.
          Mit der Funktion Wire.setClock(100000) nach Wire.begin ging es dann plötzlich wieder.
          Vielleicht hilft dir das ja weiter.

          Gruß
          Robert

  4. Doch noch mal eine Frage …
    Vielleicht muss ich mit dem SPAD Array experimentieren, damit das Ganze für meinen Anwendungsfall funktioniert. Scheinbar geht das nur mit der original API oder der Bibliothek von SparkFun. Mit welchem VL53L1X Sensor hast Du die SparkFun lib ausprobieren können?

    Danke Peter

    1. Die Sparkfun Bibliothek hat mit den oben abgebildeten Sensoren funktioniert, also Pimoroni und Melopero. Das mit den Spads hat auch funktioniert, aber das habe ich mit jedem Modul ausprobiert. Ich gehe davon aus, dass das nicht modulabhängig ist.

      1. Verrückte Sache:
        1) Libraries von Github (SparkFun_VL53L1X_Arduino_Library, 1.2.9)
        Wire oder auch I2C Scanner findet den Sensor, die SparkFun Routine begin() schlägt fehl. Auch ein Ändern der Adresse im Quellcode von Default 0x52 auf 0x29 führt nicht zum Erfolg.
        2) Libraries von PlatformIO (SparkFun VL53L1X 4m Laser Distance Sensor, 1.2.9)
        funktioniert – die andere I2C Adresse interessiert scheinbar nicht

  5. Wie hoch ist der tatsächliche, ggf. genau bestimmte, Energiebedarf? Wichtig für stand alone IoT solar Anwendungen iV mit LoRaWAN Datenübertragung?

    Hat das mal wer bestimmt?

    Danke

    gerhard

    1. Ich habe es nicht nachgemessen, aber der Strombedarf hängt auch davon ab, wieviel man wirklich misst und welche Parameter man einstellt. In den Datenblättern steht ein bisschen was dazu. Für beide Module gilt, dass sie im Standby Modus wenige Mikroampere verbrauchen. Für den aktiven Zustand werden in den Datenblättern Beispiele genannt, die um die 20 mA liegen. Aber man muss ja für die meisten Anwendungen nicht ständig messen.

      1. Danke.
        Ja das stimmt. Ich möchte eine Präsenzdetektion durchführen, die nicht zeitkritisch ist und daher nur wenige Male tägliche durchgeführt werden wird.

        Dieses Modul werde ich mir mal genauer ansehen.

        Ps: Schöne Schreibe!

  6. Hallo,

    ich benötige einen Laser Entfernungsmesser mit dem man kleine Entfernungen messen kann.
    Die Entfernung beträgt max. 30 mm.
    Der Sensor sollte eine hohe Messgenauigkeit bieten. Am besten wenn dieser sogar im 0,5 mm Bereich messen könnte. Gibt es überhaupt einen solchen Sensor?

    1. Am ehesten ginge wohl noch der VL6180x mit knapp 20 cm Reichweite. 0,5 mm könnte damit vielleict gehen. Bestimmt gibt es solche Sensoren, aber wahrscheinlich nicht im Arduino/Hobby/Consumer Bereich.

  7. Hallo Danke für den Beitrag, aber bei mir ist das alles sehr ungenau. Gibt es eine art der Kalibrierung? Denn ich habe auf Din A4 länge gemessen, aber angezeigt wird mir 333. Müsste aber 24. Hat jemand eine Idee? Ich habe auch 2 verschiedene laser Probiert. Immer selbe ergebnis.

    1. Erst nochmal ein paar Rückfragen:
      1) Welchen der beiden Sensoren benutzt du?
      2) 333 statt 24? Das wäre ja nicht ungenau, sondern komplett daneben. mm?
      3) Was misst du für ein Objekt? Ist es vielleicht zu klein?
      4) Wenn du möchtest kannst du mir mal deinen Sketch zuschicken.

  8. Hallo liebe Tüftler,
    Ich habe eine etwas ungewöhnliche Anwendung für den VL53L0X:
    Ich brauche nicht den absoluten Abstand sondern letztlich von drei dieser Sensoren möglichst genau (< +/- 0,1mm) den Unterschied. Eine Messdauer zum Mitteln der Messwerte von etwa 8-15s wäre vertretbar.
    Temperaturdrift spielt also keine Rolle, da die Messung wie gesagt nicht absolut erfolgen muss und alle Sensoren gleichzeitig messen können.
    Das muss nicht mit einer Library gehen, zur Not auch drei microcontroller oder drei I2C-Channels – es geht also zunächst nur um die tatsächliche Auflösung der Messwerte.
    Ziel ist es mit drei Sensoren den Winkel eines geeignet reflektierenden Gegenstandes gegenüber den drei Sensoren möglichst genau zu erfassen.
    Kommt man irgendwie an die Sensorrohdaten anstatt auf mm gerundete Werte?
    Ich habe mir die Pololu- und Adafruit Library angeschaut aber durch diese API-Geschichte habe ich noch nicht gefunden wo ich das ggfs abgreifen könnte.
    Bisher messe ich ein paar tausend Messwerte in mm und bilde den Durchschnitt, jedoch geht hier durch die mir unbekannte Rundung auf mm eines jeden Einzel-Messwerts natürlich Genauigkeit flöten.
    Es ist schon klar dass das nicht viel ist, denn 3 Prozent auf z.b. 29mm (in etwa das Minimum) sind bereits 0,87mm (falls die 3 Prozent Toleranz überhaupt auf den jeweils gemessenen Abstand zu beziehen sind).
    Ich suche also nach einer Lösung die Rundung auf ganze mm zu umgehen.
    Gerne auch andere Sensoren vorschlagen.

    Details:
    benötigtes FoV: 1 Grad würde genügen
    Zielabstand: je Sensor fester Wert +/- 3mm, 2 Sensoren haben 50 +/-3 mm und einer 100 +/-3mm Abstand vom Target)
    Target ist immer das selbe Material
    Keine Helligkeitseinflüsse (bzw können unterbunden werden)
    Temperaturdrift nicht relevant
    Korrektheit des absoluten Abstandes nicht relevant
    Regelmäßige Kalibrierung der Sensoren zueinander auf Referenzfläche zulässig

    Hat jemand Tipps?

    1. Hallo,

      ich bin über diese API Lösung auch nicht besonders glücklich. Wie man da an die Rohdaten herausziehen kann, vermag ich leider nicht zu sagen. Im Bereich von mm genau zu messen wird aber sicherlich nicht einfach. Da braucht man auch geeignete Gegenstände. Am besten plan und groß. Viel mehr fällt mir leider nicht ein. Vielleicht hat ja jemand anderes noch eine Idee.

  9. Hallo,

    ich hätte eine Frage bzgl. VL53LX Tofs. Ich würde diese gerne mit dem Raspi benutzen. Die Pimoroni Lib VL53L1X für multiple I2Cs funktioniert leider nicht zuverlässig bzgl. der Messwerte. Ich habe es auch schon mit der Adafruit I2C Mux sowie den 8086 Mux versucht. Leider ohne Erfolg. Mein Problem ist, dass ich für den Rest meines Projektes schon alles in Python auf Raspi habe. Deshalb meine Frage, gibt es ToFs, die sich auf verschiedene I2C Adressen (hart) stellen lassen, die ähnliche oder gleiche Eigenschaften haben wie die VL53L1X ToF family. Ich benötige zuverlässige Messungen in der Nahdistanz (10-50 cm) die ich dann via Python / Raspi ansprechen bzw. auserten kann.
    Suche bisher leider vergeblich und wäre dankbar für jeden Tipp.

    1. Hi Peter, außer den VL53LX kenne ich nur noch den VL6180X, der nach dem TOF Prinzip funktioniert. Der hat allerdings nur eine Reichweite von 20cm. Muss es denn unbedingt ein TOF Sensor sein? Hinsichtlich der Genauigkeit habe ich mit den guten alten Ultraschallsensoren auch keine schlechten Erfahrungen gemacht.

      Andererseits verstehe ich aber auch nicht was das Problem bei zwei Sensoren sein soll. Sofern man es bewerkstelligen kann, beiden eine unterschiedliche Adresse zu geben, sollte man sie getrennt ansprechen können. Hat das denn funktioniert? Auch für Python gibt es I2C Adressscanner, damit solltest du das prüfen können. Und hast du Pullups in die I2C Leitungen eingebaut?

      1. Hi Ewald,

        Ultraschall habe ich schon probiert. Selbst die teuren Teil von PIBorg versagen leider kläglich wenn Hochglanz Metallfüßen :-(. Das Problem mit der VL531lx Lib von Pimoroni ist, dass es zwei funmktioniert, allerdings die Lib wohl nicht sauber arbeitet bzgl. der getrennten i2c-Busse. Ich bekomme manchmal auf beiden Tofs dieselben Werte oder eine mißt völligen Quatsch bei z.B. 40 cm 4 m usw. Pullups bringen auch nichts. Es gibt wohl eine experimentell VL531lx, die bekomme ich aber nicht zum Laufen (wobei ich hier wohl nicht der einzige bin). Die Experimental Version ist eine Github Fork und diese installiert sich wohl nicht richtig? Eine Nachfrage beim Autor ist seit Wochen leider unbeantwortet. Mit einem Arduino Uno läuft es einwandfrei, allerdings benutze ich einen PiBorg Motorcontroller und das ist alles Python. Ich habe schon überlegt den Ardunio mit dem Raspi zu koppeln, aber dann benötige noch eine weitere Stromquelle :-(, was auch nicht ideal ist. Ich überlege, ob ich die SDC/SDA Leitung per Relais physikalisch umschalten könnte, so dass aus Software-Sicht immer zum Zeitpunkt des messen, ein ToF aktiv ist wäre. Ich benötige nur 2, das ginge dann vielleicht.
        Trotzdem danke für deine Antwort.
        Schönen Sonntag

        1. Getrennt ansteuern ginge wohl auch. Ich würde dann aber einfach einen Transistor als Schalter nehmen. Ich hoffe du bekommst die Geschichte noch ans Laufen.

    1. Hallo, ich gehe davon aus, du beziehst dich auf den VL53L0X, denn soweit ich weiß, hat Adafruit keinen VL53L1X im Programm und keine Bibliothek dazu. Ich hatte versucht, in der VL53L0X Bibliothek die Interruptfunktion zu finden, leider vergeblich. Entweder ist die Funktion gut versteckt oder nicht implementiert. Ich hätte schon längst selber eine Bibliothek geschrieben, aber der Zugang zu dem VL53L0X über die API, also nicht wie gewohnt über direkten Registerzugriff, ist recht gewöhnungsbedürftig. Abgesehen vom Preis würde ich immer zum VL53L1X greifen und die sehr komfortable Sparkfun Bibliothek benutzen.

  10. Hi Wolfgang,
    vielen Dank für diesen und auch die anderen Beiträge.
    Ich teste gerade den L0 und L1 Sensor.
    Der L0 funktioniert recht gut mit den verschiedenen Libraries (Adafruit, Pololu), wenn auch mit einer kleinen Unlinearität.
    Der L1 macht „Probleme“ – er misst nur Mist. Bis 50 cm mit einem ordentlichen Offset und darüber gar nicht mehr. Egal mit welcher Library (SF, Pololu) und welchem Beispielprogramm (SF, Pololu, Wolles). Der Messaufbau und Randparameter sind dieselben wie beim Test des L0.
    Irgend eine Idee?
    Grüße,
    Rally

    1. Hi Rally, auf die Entfernung schwer zu sagen. Ich denke mal laut vor mich hin: da du ja den L0 zum Laufen bekommen hast, sollte bei der Schaltung alles stimmen. Hast du Pullup Widerstände für die I2C Leitungen verwendet? Ich hatte ja geschrieben ich brauchte keine. Als ich gestern wegen einer anderen Anfrage nochmal probiert hatte, brauchte ich dann doch welche. Allerdings würde ich dann eher erwarten, dass gar nichts geht. Welchen L1 benutzt du? Vielleicht kannst du mir den Link zur Bezugsquelle schicken, dann könnte ich nochmal schauen, ob mir da etwas auffällt.

      1. Hi Wolfgang,

        es ist ein original Pololu, bestellt via großem Internet-Händler. Also eher unauffällig.
        Habe es an einem nackigen Uno getestet ohne Pullups, sollte aber wie gesagt zu Busfehlern führen und nicht zu Messfehlern. Hatte verschiedene Lichtverhältnisse und mit und ohne Interrupt getestet. Werd es trotzdem nochmals mit Widerständen versuchen und berichten.

        1. …die Lösung war einfach, wenn man lesen kann:
          „Are you getting weird readings? Be sure the vacuum tape has been removed from the sensor.“ steht als Kommentar im Header der Sparkfun Beispiele.
          Kaum so getan funktioniert es 🙂

  11. Ich habe einen CJMCU 402 mit dem VL53LOX erworben, der offenbar chinesischer Produktion ist. Der I2C Scanner zeigt die Adresse 0x4C und nicht 0x29. Die angeführten Bibliotheken gehen damit nicht. Was kann man da tun? Ich habe keine große Ahnung von der Programmierung.

    1. Hallo Christian, ich musste ein bisschen „wühlen“ um die Antwort zu finden. Ich gehe davon aus, dass du die die Pololu Bibliothek verwendest. Dann kannst du die Adresse leider nicht im Sketch einstellen, sondern nur in der Bibliothek. Das ist wirklich unschön, normalerweise sollte man so etwas von außen einstellen können. Aber keine Sorge, es ist nicht schwer: 1) Gehe in das libraries Verzeichnis und dort in das Verzeichnis VL53L0X. 2) Öffne die Datei VL53L0X.cpp mit einem Texteditor (z.B. notepad++). 3) In Zeile 13 (jedenfalls ist es in meiner Version Zeile 13) findest du den Eintrag:

      #define ADDRESS_DEFAULT 0b0101001

      4) Ersetze sie durch

      #define ADDRESS_DEFAULT 0x4C

      Speichere die Datei. Dann sollte es gehen. Eine Rückmeldung ob es geklappt hat würde mich freuen.

      1. Hallo Wolfgang, leider hat es nicht geklappt. Ich bekomme immer noch die Fehlermeldung in dem Sketch Single von Pololu

        Failed to detect and initialize sensor!

        Habe das auch noch mal mit dem I2C Scanner überprüft und der liefert die Antwort 0x4C, also müsste der Sensor ansprechbar sein. Auf dem deutschen Markt gibt es fast nur noch den CJMCU 402, aber man findet nirgends eine brauchbare Beschreibung. Der Sensor ist auch nicht beschriftet, nur das Breakout Board.

        1. Ich war der Meinung du hättest einen VL53L0X und war ganz darauf fixiert dafür die Anpassung der I2C-Adresse zu finden. Jetzt habe ich aber nochmal nach dem CJMCU-402 geschaut. Der hat anscheinend überhaupt nichts mit dem VL53L0X zu tun außer dem Messprinzip. Nach einer kleinen Recherche bin ich auf diese Bibliothek gestoßen:
          https://github.com/sparkfun/SparkFun_RFD77402_Arduino_Library
          Sie könnte mit deinem Modul funktionieren. Zumindest stimmt auch schon mal die I2C Adresse.

          1. Lieber Wolfgang,
            das ist ja großartig, wie Du das herausgefunden hast, so schnell, und ich habe schon tagelang daran gewurzelt. Da ich keinerlei Beschreibung gefunden hatte und auch nicht wusste, dass es zu dem VL53L0X noch eine Alternative gibt und auch keine Beschriftung auf dem Chip ist. Das ist das Ergebnis des Beispiels BasicReadings
            distance: 1098mm
            distance: 1085mm
            distance: 1079mm
            distance: 1075mm
            distance: 1093mm
            distance: 1088mm
            Der Chip geht auch bis zwei Meter.
            Gaaanz großen Dank!!!
            Bitte publiziere das auch entsprechend, dass nicht noch mehr Leute auf dem Schlauch stehen.

      2. Hallo Wolfgang,

        sehr schöne Erläuterungen…
        Ich habe ein ähnliches Problem. Mit einem I2C Scanner wird mein VL53L1X unter 0x29 gefunden.
        Sowohl die Pololu lib als auch die SparkFun lib lassen das Setzen einer Adresse zu (Pololu = setAddress()).
        ich habe also mit
        Wire.begin();
        sensor.setAddress(I2C); // I2C = 29

        mein Glück versucht. Leider wird er nicht erkannt.
        Idee?

        1. Zunächst schreibst du 0x29, weiter unten I2C = 29. Hast du vielleicht einfach vergessen, die I2C Adresse als Hexadezimal anzugeben oder in Dezimal umzurechnen (0x29 = 41)? Es wäre schon komisch, wenn beide Bibliotheken einen Fehler hätten.

          1. Oops!

            Super Danke! War etwas durcheinander, weil „0b0101001“ = 29. Bekomme jetzt Timeout vom Sensor, aber immerhin wird er schon mal erkannt.

            Danke noch mal!
            Peter

          2. Ja, seltsam. Habe jetzt gelesen, dass der VL53L1X eine hard coded I2C HEX-Adresse 0x29 hat. Jetzt wird er auch im default modus erkannt. Brauchte wohl einen kleinen „Anstubser“.
            Leider bekommen ich als Messergebnis immer nur 0. Habe schon verschiedene Libs und Lib-Versionen getestet (Pololu, SparkFun, QTRobot).
            Auch der Tausch (habe zufällig noch einen zweites breakout eines anderen Herstellers) führte zu nichts … Messwerte = 0.
            Wo könnte ich noch dran „schrauben“, um dem Problem auf die Spur zu kommen.

            Gruß Peter

            1. Hast du denn mal einfach die unveränderten Beispielsketche der Bibliotheken verwendet? Die sollten auf jeden Fall funktionieren.

              Und ja, die Standardadresse ist 0x29. Man kann per Software eine andere Adresse einstellen, die wird aber vergessen wenn man die Stromversorgung trennt. Wenn man zwei Sensoren hat, kann man einen über xshut ausknippsen, bei dem anderen stellt man die neue Adresse ein, schaltet dann den zweiten ein und hat so beide mit unterschiedlichen Adressen ansteuern.

              1. Ich verwende die Sensoren nicht parallel. Zufälligerweise habe ich zwei verschiedene zum Testen (QCRobot und Pimoroni). Erst habe ich den ersten getestet. Nachdem da nichts passierte, habe ich den zweiten ausprobiert. Der erste könnte ja defekt sein. Beide werden jeweils am I2C-Bus erkannt. Ja, ich verwende natürlich erst mal die Beispiel-Sketche. Aber egal welche, die Werte sind immer 0. Dumme Frage: sollte da nicht irgendwas leuchten? Ich meine im Netz mal ein Foto gesehen zu haben…

                Danke für Deine Geduld – Peter

                1. Wirklich merkwürdig. Ich habe gerade nochmal 2 Module mit dem unveränderten Sparkfun Beispielsketch Example1_ReadDistance laufen lassen und alles funktioniert. Leuchten tun meine Module übrigens auch nicht. Wenn man den Sketch nicht verändert, dann kan man eigentlich nichts verkehrt machen.

                  1. bin am Ende meines Lateins. Habe mir gerade ein original Pololu-Breakout bestellt….
                    In Arbeit hatte ich jetzt das VL53L1X-Breakouts von Pimoroni und cqrobot. SparkFun lib schlägt komplett fehl. Es sei denn, man ändert das setup von xxx.begin() auf xxx.init(), wie SparkFun es in seinem eigene guide vorsieht. Danach passiert allerdings nichts mehr.
                    Die anderen libs von Pololu, cqrobot, oder auch die original api von STM scheinen zu laufen, liefern aber Werte 0. Verzichte ich auf Messungen und frage nur Chip-Infos ab (ID, etc.) kommt ebenfalls 0.
                    Ich verwende allerdings keinen Arduino, sondern ein Feather M0 RF69HCW 433 MHz board. Daran kann es eigentlich nicht liegen. Mit dem board habe ich schon diversen Sensoren über I2C betrieben.
                    Ich bin mal gespannt, wie das Ergebnis mit dem original Pololu board aussieht.

                    Danke nochmal für Deine Hilfe.

                  2. Fehler gefunden!
                    Ich nutze boards in Batteriebetrieb unter Verwendung von deep sleep modi. Dazu versorge ich die Sensoren über das Hochschalten einzelner „Daten Pins“. Der VL53L1X braucht für den Betrieb laut Doku 20mA, je nach Konfiguration bis zu 40 mA. Die Datenpins meines boards sind auf 10mA begrenzt.

  12. Vielen Dank für diese sehr umfassende und vor allem lesbare und verständliche Zusammenfassung.

  13. Shouldn’t line 24 be:
    attachInterrupt ( digitalPinToInterrupt ( INTERRUPT_PIN ) , blink, FALLING )

    1. Hi J.S., I can’t see the difference to what I have written!? Maybe it’s too late in the evening for me 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.