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

Introduction

Dans la première partie de cette série, nous avons connecté le capteur ToF à un NodeMCU D1 Mini ESP8266 et construit un dispositif d'avertissement acoustique de distance. Dans ce post, je veux utiliser un ESP32 NodeMCU ainsi qu'un Arduino Nano. Je veux savoir quelle fonctionnalité est encore disponible et si nous pouvons utiliser les broches GPIO1 et XSHUT. Allons-y. 

Matériel requis

Nombre Composant Remarque
1 Carte de dérivation du capteur VL53L0X
1 ESP8266 Node MCU D1 Mini
1 Module ESP32 NodeMCU ou Kit de développement ESP32
1 Arduino Nano
1 Module d'alarme KY-006 Passive Piezo Buzzer pour Arduino
Câble de connexion
Ordinateur avec IDE Arduino et connexion Internet


Broches de connexion

Tout d'abord, nous connectons le capteur à un ESP8266 NodeMCU D1 Mini comme dans la partie 1 selon le schéma suivant :

Broches VL53L0X Mini GPIO D1
VIN 3,3 V
GND GND
SCL SCL (D1 / GPIO5)
SDA SDA (D2 / GPIO4)
GPIO1 -
XSHUT -
Buzzer KY-006 Mini GPIO D1
- (moins) GND
S (signal) D7 (GPIO 13)



Nous laissons les broches GPIO1 et XSHUT libres.

Rappel : Pour les broches I²C SDA et SCL, il est conseillé de consulter l'aperçu du brochage. Sur l'ESP8266, ces broches sont GPIO4 et GPIO5, mais sur la carte, elles sont étiquetées D2 et D1. Cela varie d'un microcontrôleur à l'autre. La broche numéro 13 doit être utilisée dans l'IDE Arduino. La broche est étiquetée D7.

Dans la première partie, nous avons apporté les ajouts et modifications suivants au code d'exemple vl53l0x :

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

Une variable pour le timing:

unsigned long zeitAlt = 0;

dans le installer() initialisez la broche du buzzer en tant que sortie:

pinMode(BUZZER, OUTPUT);  

Sortie de la mesure du temps dans le boucle ():

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

Ajouter un buzzer:

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 ");
}

Si nous chargeons le programme sur le microcontrôleur, nous avons le statut de la dernière fois et pouvons maintenant continuer.

Code source complet: ToFavertisseur sonoreESP8266_Adafruit.ino

ESP32

Nous passons maintenant au module ESP32 NodeMCU. Pour ce faire, nous connectons le capteur et le buzzer comme suit:

Broches VL53L0X ESP32
VIN 3,3 V ou 5 V
GND GND
SCL GPIO22
SDA GPIO21
GPIO1 -
XSHUT -
Buzzer KY-006 ESP32
- (moins) GND
S (signal) GPIO13


Selon la conception de la carte de développement, la disposition des broches peut varier.


Dans l'IDE Arduino, nous changeons la carte en ESP32 sous Outils et chargeons le même programme sur le microcontrôleur. Nous obtenons un message d'erreur indiquant que la fonction tone() n'est pas connue. Ceci n'est pas implémenté dans le noyau ESP32. Il y a quelques dérivés dans la gestion de la bibliothèque. J'ai trouvé la bibliothèque Tone32 sur Github. Il fonctionne de manière similaire à la fonction Tone de l'Arduino. Il n'y a plus qu'un seul paramètre appelé "Channel", que nous mettons à 0. Vous téléchargez le code source sous forme de ZIP. Ensuite, vous choisissez Sketch->Inclure une bibliothèque->Ajouter une bibliothèque .ZIP dans le menu de l'IDE Arduino.

Dans le code source de notre programme, nous ajoutons les lignes suivantes :

#include <Tone32.h>

#define BUZZER_CHANNEL 0

Ensuite, nous changeons la ligne:

tone(BUZZER, FREQ, DURATION);

dans

tone(BUZZER, FREQ, DURATION, BUZZER_CHANNEL);  

Avec cela, le téléchargement devrait maintenant être possible et tout devrait fonctionner à nouveau comme avec la D1 Mini. Cependant, j'ai remarqué que la sortie du son fournit des délais. Comme je ne connais pas la bibliothèque, je ne peux pas dire pour l'instant de quoi il s'agit exactement. Apparemment, la sortie du son ne fonctionne pas sans verrouillage. Cela aura à voir avec les timers utilisés et le PWM généré. Il existe une autre bibliothèque appelée ESP32Servo qui se trouve dans l'administration. La fonction tone() y est également implémentée. Cependant, il montre le même comportement. Si vous voulez tester cela, installez cette bibliothèque et modifiez le code source comme suit :

#include <ESP32Servo.H>

dans le installer():

 ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);

et dans le boucle ():

Ton(AVERTISSEUR SONORE, FREQ, DURÉE);

C'est ce que j'ai compris de l'exemple fourni. Cependant, je pense que cette bibliothèque est un peu plus lourde, car elle fournit également d'autres fonctionnalités.

Il y a la possibilité de programmer la génération du son manuellement avec PWM. Je ne veux pas m'étendre sur ce sujet, car cet article porte principalement sur le capteur ToF.

Code source complet: ToFavertisseur sonoreESP32_Adafruit.ino

Arduino NANO

Pour une alerte de distance acoustique, le WLAN n'est pas absolument nécessaire (sinon, c'est l'une des raisons les plus importantes d'utiliser l'ESP). C'est pourquoi je voudrais maintenant reconstruire le circuit avec l'Arduino NANO.

Broches VL53L0X Arduino NANO
VIN 5V ou 3,3V
GND GND
SCL A5
SDA A4
GPIO1 -
XSHUT -
Buzzer KY-006 Arduino NANO
- (moins) GND
S (signal) D13


 


Pour les broches SDA et SCL, nous devons à nouveau consulter l'aperçu du brochage. Pour l'Arduino Nano (et aussi UNO), ce sont les broches A4 et A5. Comme nous utilisons à nouveau la broche 13 pour le buzzer, qui contrôle également la LED interne du Nano, nous avons un signal optique en plus du signal acoustique.

Nous ouvrons maintenant le programme que nous avons chargé sur la D1 Mini au début. Nous pouvons réutiliser cela de la même manière. Nous changeons à nouveau de carte dans l'IDE Arduino, dans le menu Outils, et sélectionnons l'Arduino Nano. Il peut être nécessaire de passer à l'ancien chargeur de démarrage sous "Processeur". Dans mon cas, c'est comme ça. Si un message d'erreur s'affiche pendant le téléchargement, essayez ce paramètre.

Si nous exécutons le programme, l'avertissement de distance fonctionne à nouveau comme sur la D1 Mini. Le son est légèrement différent. Cela est dû à la fréquence d'horloge inférieure. On remarque qu'il n'y a pas de retard dans la génération du son. Ceci est dû à la fonction tone() de la bibliothèque Arduino Core, que nous pouvons maintenant utiliser à nouveau avec le Nano.

Nous avons maintenant testé le capteur sur les trois microcontrôleurs. Ainsi, en fonction du cas d'utilisation, la bibliothèque Adafruit peut être utilisée avec l'un des dispositifs. Si vous souhaitez transférer les données sur un réseau, l'Arduino Nano est hors de question pour le moment. Si le délai est un obstacle à la génération du son, laissez l'ESP32 en dehors de cela.

À ce stade, vous pouvez toujours tester indépendamment la bibliothèque Pololu avec les deux autres microcontrôleurs. Utilisez le code source de la partie 1 pour cela.

Code source complet: ToFavertisseur sonoreESP8266_Adafruit.ino

Précision vs Vitesse vs Gamme

Dans la description du capteur ToF (voir partie 1), il est écrit que vous pouvez modifier les "profils de portée". Les modes disponibles sont : Haute précision, Haute vitesse, Longue portée et Défaut. Pour les modifier, j'ai dû creuser un peu plus loin dans le code source de la bibliothèque Adafruit, car aucun exemple n'était fourni.

Là, les modes sont définis dans un énumérateur comme un nouveau type de données. Ils sont appelés comme suit :

  • VL53L0XSENSDÉFAUT
  • VL53L0XSENSLONG_RANGE
  • VL53L0XSENSEHIGH_SPEED
  • VL53L0XSENSEHIGH_ACCURACY

Dans la classe Adafruit_VL53L0X, il y a une fonction appelée configSensor() à laquelle on passe le mode souhaité. Nous écrivons la ligne suivante dans la fonction setup() après avoir initialisé le capteur :

saumon fumé.configSensor(Adafruit_VL53L0X::VL53L0X_SENSE_HIGH_ACCURACY);

Ceci règle le capteur en mode "Haute précision". Si cette ligne est omise, VL53L0XSENSEDEFAULT est automatiquement utilisé. Si vous remplacez VL53L0XSENSEHIGHACCURACY par VL53L0XSENSELONGRANGE, vous pouvez détecter des obstacles jusqu'à 2 m de distance. Cependant, cela réduit la précision. Derrière ces modes, il y a une instruction de cas de commutation dans la bibliothèque, qui définit les valeurs pour le budget temps, la période d'impulsion et le niveau du signal.

Code source complet: ToFavertisseur sonoreESP8266AdafruitPart2.ino

Pour effectuer le même changement avec la bibliothèque Pololu, nous ouvrons le sketch d'exemple "Single". C'est là que la possibilité de changer de mode est mise en œuvre. Il suffit de commenter une des lignes (je choisis ici le mode longue portée) :

#define LONG_RANGE
//#define HIGH_SPEED
//#define HIGH_ACCURACY

Pour pouvoir l'intégrer dans notre avertisseur de distance acoustique, nous ajoutons dans l'exemple le code source correspondant de l'exemple Continuous de la partie 1, que nous avions modifié.

Constantes :

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

Variable pour la mesure du temps: 

unsigned long zeitAlt = 0;

Dans setup(), insérez ou ajustez ces lignes :

Serial.begin(115200);
pinMode(BUZZER, OUTPUT);
...
      Serial.println(F("Failed to detect and initialize sensor!"));
...

Insérez la mesure du temps dans la boucle() :

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

À ce stade, j'utilise à nouveau le ESP8266 D1 Mini et j'y télécharge le programme. Grâce à cette bibliothèque, nous pouvons désormais détecter des obstacles jusqu'à une distance de 2 mètres.

Code source complet: ToFavertisseur sonoreESP8266PololuSingle_LongRange.ino

XSHUT Pin et capteurs multiples

La broche portant la désignation XSHUT est là pour mettre le capteur en mode veille matérielle. De cette façon, vous pouvez par exemple activer et désactiver des capteurs individuels. Ils n'interfèrent donc pas entre eux (selon le fabricant, il n'y a toutefois pas d'interférence tant que les capteurs ne sont pas directement dirigés l'un vers l'autre). Il existe différentes possibilités de coopération entre les capteurs. Soit la lecture des valeurs mesurées est synchronisée, soit elle est asynchrone. En outre, le GPIO1 peut être utilisé. De cette façon, chaque capteur n'est lu que s'il peut également fournir des valeurs utilisables.

Lorsque vous utilisez plusieurs capteurs, il est important de définir l'adresse I²C. Des exemples pour cela sont fournis dans la bibliothèque Adafruit. L'exemple de sketch "vl53l0x_dual" montre comment utiliser deux capteurs en même temps. Comme chaque capteur a la même adresse par défaut (0x29), les adresses doivent être réaffectées. Malheureusement, ils ne restent pas en permanence, mais doivent être réinitialisés à chaque fois que le microcontrôleur est redémarré. Les capteurs doivent être activés les uns après les autres à l'aide de XSHUT, puis les adresses respectives doivent être attribuées. Adafruit donne une courte instruction à ce sujet.

Des broches numériques supplémentaires sur le microcontrôleur sont nécessaires pour les broches XSHUT des capteurs.

A ce stade, je ne mettrai qu'un seul capteur en veille via XSHUT. Nous étendons notre circuit sur le D1 Mini en connectant la broche XSHUT à la broche D6 (GPIO12).

 

Maintenant, nous ajoutons le mappage des broches et le réveil dans le code du programme pour notre détecteur de distance audible. J'utilise ici la bibliothèque  Adafruit:

Une constante pour le numéro de la broche:

#define XSHUT 12

Variables pour les mesures de temps et l'état de la broche XSHUT :

unsigned long sleepTime = 2000;
unsigned long sleepTimeAlt = 0;
bool XSHUT_STATE = HIGH;

Initialiser la broche dans setup() comme une sortie et la mettre en HAUT :

pinMode(XSHUT, OUTPUT);
pinMode(XSHUT, OUTPUT);
digitalWrite(XSHUT, XSHUT_STATE);

Si le capteur est désactivé dès le début via XSHUT, il ne sera plus détecté non plus lors de l'initialisation suivante. Si nous ne donnons pas un état unique à la broche, il est possible qu'elle soit toujours à l'état BAS, ce qui signifie que le capteur ne sera pas détecté.

Au début de la fonction loop(), nous ajoutons les lignes suivantes :

if (millis() - sleepTimeAlt >= sleepTime) {
  sleepTimeAlt = millis();
  XSHUT_STATE = !XSHUT_STATE;
  digitalWrite(XSHUT, XSHUT_STATE);
  
  if (XSHUT_STATE == HIGH) {
    Serial.println("Sensor On");
    if (!lox.begin()) {
      Serial.println(F("Failed to boot VL53L0X"));
      while(1);
    }   
  }
  else {
    Serial.println("Sensor in Standby");
  }
}

Lorsque le temps est écoulé, l'état est basculé et sorti sur la broche numérique pour le XSHUT. Lorsque le capteur est réveillé, il est nécessaire de le réinitialiser avec lox.begin(). Si nous chargeons le programme sur le D1 Mini, la mesure de la distance devrait être activée et désactivée à l'intervalle spécifié. L'inconvénient dans ce cas est que le capteur continuera à fournir le dernier relevé après avoir été mis en veille. Pour faire un peu plus propre et vraiment mesurer uniquement lorsque XSHUT est HIGH, nous ajustons à nouveau le code source et plaçons la mesure du capteur dans une instruction if :

if (XSHUT_STATE) {
  Serial.print("Reading a measurement... ");
  lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!
 
  if (measure.RangeStatus != 4) {  // phase failures have incorrect data
    Serial.print("Distance (mm): ");
    Serial.println(measure.RangeMilliMeter);
 
    if (millis() - zeitAlt >= measure.RangeMilliMeter * 2) {
      zeitAlt = millis();
      tone(BUZZER, FREQ, DURATION);
    }   
  } else {
    Serial.println(" out of range ");
  }
}

Par cette extension, le capteur est également utilisé uniquement lorsque l'état de la broche XSHUT est HIGH. Chargez le programme sur le microcontrôleur et essayez-le.

Nous avons maintenant activé et désactivé le capteur en fonction du temps. Si nous devions utiliser le capteur de distance dans un véhicule, nous pourrions connecter la broche XSHUT via un circuit électronique à la marche arrière, par exemple. En général, il y a une connexion qui permet d'allumer le feu de recul. Il serait ainsi possible de n'utiliser l'avertisseur sonore de distance que lors de la conduite en marche arrière.

Si l'on devait construire un robot, on pourrait l'équiper de plusieurs de ces capteurs et, en fonction des besoins, n'activer qu'un seul capteur pointant dans une certaine direction.

Code source complet: ToFavertisseur sonoreESP8266AdafruitPart2_XSHUT.ino

Si vous souhaitez utiliser la bibliothèque Pololu au lieu de la bibliothèque Adafruit, le programme est très similaire. Nous avions développé notre avertissement acoustique de distance à partir de l'exemple "Single". Nous complétons cela avec les mêmes variables et paramètres. La seule différence réside dans les noms des appels de fonction. Pour réveiller à nouveau le capteur, nous appelons ensuite la fonction sensor.init() au lieu de lox.begin(), comme dans la fonction setup().

Code source complet: ToFavertisseur sonoreESP8266PololuCélibataireLong RangeXSHUT.ino

GPIO1 et interruptions

Enfin, je voudrais parler de la broche GPIO1 sur le capteur ToF. Cette broche numérique est commutée lorsqu'un obstacle se trouve à une distance donnée du capteur. C'est la théorie. Malheureusement, cela n'est pas bien documenté, même si cela a été implémenté par STM dans l'API. Il n'a pas encore été implémenté en détail pour l'IDE Arduino. Commençons par étendre le circuit et connecter la broche :

 


GPIO1 du capteur ToF nous connectons à D5 (Donc dans l'IDE Arduino broche 14). A partir de ce moment, j'ai vraiment cherché longtemps et durement comment utiliser le GPIO1 en conjonction avec une interruption. Kris Winer a utilisé la bibliothèque Pololu et a écrit un programme Arduino sur Github pour l'ESP32. Je l'ai modifié un peu pour qu'il fonctionne avec l'ESP8266 :

La broche LED est passée de 5 à 2:

int myLed = 2;

L'initialisation I²C sans paramètres:

Wire.begin ();

La variable de la routine de service d'interruption doit être déclarée volatile:

volatile bool newData = false;

La routine de service d'interruption doit être chargée dans l'IRAM sur l'ESP8266. Pour cela, nous ajoutons ce qui suit:

ICACHE_RAM_ATTR void myinthandler()
{
  newData = true; // set the new data ready flag to true on interrupt
}

Si nous chargeons le programme sur le D1 Mini, la mesure de la distance devrait être visible dans le moniteur série. Si nous déconnectons la broche D5, la mesure est interrompue. Donc l'interruption fonctionne. Malheureusement, il n'y a pas de possibilité de saisir les valeurs de seuil à partir desquelles l'interruption doit être déclenchée. Ainsi, les données de mesure sont toujours détectées et par conséquent l'interruption est toujours déclenchée. Donc, il fonctionne en fait de la même manière que l'exemple "Continu" sans la fonctionnalité d'interruption. Ce n'est donc pas vraiment utile.

Code source complet: ToFESP8266Interrupt_Pololu.ino

Un exemple appelé vl53l0xmultiextended est fourni avec la bibliothèque Adafruit (version 1.1.0), qui implémente un mode asynchrone qui utilise GPIO1. Cette fonction s'appelle timedasyncread_gpio(). A partir de cela, vous pouvez dériver un programme similaire au précédent en utilisant la bibliothèque Pololu. La fonctionnalité est la même. Malheureusement, la possibilité de saisir des valeurs seuils fait également défaut.

Sur Github, il existe une ancienne version de la bibliothèque Adafruit qui contient également un exemple d'interruption. Dans l'exemple, des fonctions sont appelées qui n'existent pas dans la version actuelle. J'ai donc installé cette ancienne version et j'ai ensuite chargé l'exemple sur la D1 Mini. Déjà pendant la compilation, de nombreux avertissements apparaissent, ce qui n'est pas bon signe. Le programme lui-même ne fonctionne donc pas non plus sur le microcontrôleur. Il pourrait être possible de réécrire la version actuelle de la bibliothèque et d'y transférer les fonctions présentes dans l'ancienne version. Mais cela n'a plus rien d'anodin. Je termine donc mes tests à ce stade.

Conclusion

J'ai fait beaucoup de recherches et de tests. Adafruit et Pololu fournissent des bibliothèques pour utiliser le capteur dans l'IDE Arduino basé sur l'API de STMicroelectronics. Les interruptions ne sont normalement pas obligatoires sur un Arduino. Cependant, comme les ESP supportent le sommeil profond, une interruption serait utile pour réveiller le microcontrôleur d'un sommeil profond.

Utiliser les différents microcontrôleurs avec les deux bibliothèques de cette manière a fonctionné. Nous avons également pu régler les modes pour les "profils de distance".

En raison de l'interférence mutuelle possible des capteurs de distance acoustiques, le capteur de temps de vol VL53L0X est également une très bonne alternative pour la détection d'obstacles de nos Robot Cars.


Andreas Wolter

pour AZ-Delivery Blog

 

1 commentaire

Walter

Walter

Hallo Andreas,
vielen Dank für deinen Bericht und deine Mühe.
Konstet Du ermitteln welchen Öffnungswinkel der Sensor besitzt?
Also z.b. bei einer Entfernung von 100 cm muss die Refektionsfläche (bei 90 grad) im minimum …? mm² betragen und was ist wenn sich der Winkel ändert?

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés