Wie groß bin ich? - Körpergröße messen mit VL53L0X ToF Sensor und Sprachausgabe in MicroPython - AZ-Delivery

This post is also available as PDF document.

At the Theremin I had used the Time of Flight sensor VL53L0X to adjust the pitch of a synthesizer. Distance values ​​were implemented in the frequencies of a PWM signal. In this project we want to use the relatively precise distance measurement per se. Apart from the very extensive driver module of the VL53L0X, which we do not want to illuminate in detail, it is a fairly simple project with expansion potential.

I would also like to use a completely different kind of output medium. For the OLED display, the VL53L0X and the ESP32, a fourth assembly will be paused with which a voice output is possible. In addition, I will chat a little out of the workshop. There was a tricky problem in development, not homemade, but on the eye by the Micropython development team.

Welcome to a new episode of the series

Micropython on the ESP32 and ESP8266

today

How tall am I?

Tof is the acronym for Time of Flight, and the module VL53L0X Time-of-Flight (TOF) Laser distance sensor Doesn't do anything else to measure the flight time of an IR laser impulse emitted by him until reflection on an obstacle and back.

This succeeds in most solid surfaces if you reflect enough light in the IR area. Unfortunately, we cannot perceive how much that is. At best, this can be an IR camera or a converted web cam from which the IR filter was operated out.

As a reflector, people can also easily serve people, for example when passing a door. This article is about exactly this application. The structure should determine the size of people and communicate the result via a loudspeaker on a mini-MP3 player.

Hardware

1

ESP32 Dev Kit C unpleasant

or ESP32 NODEMCU Module WiFi Development Board

or Nodemcu-ESP-32S kit

1

VL53L0X Time-of-Flight (TOF) Laser distance sensor

1

0.91 inch OLED I2C Display 128 x 32 pixels

1

Mini MP3 Player DFPlayer Master modules

1

2 pieces 3 watts 8 ohm mini loudspeakers

1

Breadboard Kit - 3x Jumper Wire M2M/F2M/F2F + 3 Set MB102 Breadbord Compatible with Arduino and Raspberry Pi - 1x Set

2

Resistance 1kΩ

2

Resistance 2.2kΩ

The structure is very easy, sensor and OLED display are both connected to the common i2c bus. An ESP32 takes over the chief position. For its use, two Breadboards are required, which are connected to a power rail in the middle, so that you can get there with the intervals of the pin rows and cable can also be inserted on the edge.

Figure 1: Body-size meter-structure

Figure 1: Body-size meter-structure

Because of the very extensive VL53L0X driver module, the use of an ESP8266 is excluded. But not only for this reason the little brother of the ESP32 is unsuitable, because it cannot offer a second uart interface, and we need it to control the DF player.

Uart is acronym for Universal Asynchronous Receiver / Transmitter. We also talk to our controller from the terminal in Thonny about such an interface. The ESP32/ESP8266 is connected to the PC via the USB cable and a USB-RS232-TTL converter passes data traffic to the UART0 interface. Therefore, we cannot use UART0 to send commands to the mini-MP3 player and receive data from it. The ESP8266 has a second UART interface, but that is actually only half because only one TXD line (transmission line) and no RXD line (reception management) is available.

The software

For flashing and the programming of the ESP32:

Thonny or

µpycraft

Used firmware for the ESP32:

Micropython firmware

Please flash the version specified here, otherwise the VL53L0X control will not work correctly.

V1.18 (2022-01-17).

The micropython programs for the project:

Vl53l0x.py Modified driver module for the TOF sensor adapted to ESP32 (s)

SSD1306.PY Hardware driver for the OLED display

oled.py API for OLED displays

distance.py Test program for the VL53L0X

bodysize.py Operating software

dfplayer.py

Micropython - Language - Modules and Programs

To install Thonny you will find one here Detailed instructions (English version). There is also a description of how that Micropython firmware (As of 05.02.2022) on the ESP chip burned becomes.

Micropython is an interpreter language. The main difference to the Arduino IDE, where you always flash entire programs, is that you only have to flash the Micropython firmware once on the ESP32 so that the controller understands micropython instructions. You can use Thonny, µpycraft or ESPTOOL.PY. For Thonny I have the process here described.

As soon as the firmware has flashed, you can easily talk to your controller in a dialogue, test individual commands and see the answer immediately without having to compile and transmit an entire program beforehand. That is exactly what bothers me on the Arduino IDE. You simply save an enormous time if you can check simple tests of the syntax and hardware to trying out and refining functions and entire program parts via the command line before knitting a program from it. For this purpose, I always like to create small test programs. As a kind of macro, they summarize recurring commands. Whole applications then develop from such program fragments.

Autostart

If the program is to start autonomously by switching on the controller, copy the program text into a newly created blank tile. Save this file under boot.py in WorkSpace and upload it to the ESP chip. The program starts automatically the next time the reset or switching on.

Test programs

Programs from the current editor window in the Thonny-IDE are started manually via the F5 button. This can be done faster than the mouse click on the start button, or via the menu run. Only the modules used in the program must be in the flash of the ESP32.

In between, Arduino id again?

Should you later use the controller together with the Arduino IDE, just flash the program in the usual way. However, the ESP32/ESP8266 then forgot that it has ever spoken Micropython. Conversely, any espressif chip that contains a compiled program from the Arduino IDE or AT-Firmware or Lua or ... can be easily provided with the micropython firmware. The process is always like here described.

The circuit

Figure 2: Body-Size meter-circuit

Figure 2: Body-Size meter-circuit

Because the DF player Mini has to be supplied with 5 volts and therefore also apply to the TX and BUSSY 5V levels, but the ESP32 only tolerates 3.3V to its GPIOS, we need voltage divisors there, which the tension to a compatible level to reduce. I chose 1kΩ and 2.2kΩ. You can also take other values ​​that are in a ratio of 1: 2.

If the speakers are placed on GND with the black line, a current of approx. 450mA flows in the 5V circle! This is because the connections SP1 and SP2 lead 5V level. Therefore, only connect the two speakers to SP1 and SP2, not to GND. Even if you only use one loudspeaker, its lines belong to SP1 and SP2. Otherwise you would have to connect the speakers via an ELKO.

The driver module of the VL53L01 for the ESP32

Figure 3: VL53L0X - laser removal meter

Figure 3: VL53L0X - laser removal meter

As usual, the data sheet for the VL53L01 does not provide a register map and a description for the values ​​to be set. Instead, an API is described that serves as an interface to the building block. In a colorful variety, the elongated identifiers patter down to the reader. This has my zeal, writing my own module, very quickly screwed down to zero. Fortunately, I'm looking for a little bit Github found what they were looking for. There is a package that was written for a Wipy, with a readme file, an example for use and with the very extensive module VL53L0X.PY (648 lines). The first start of the sample file Main.py brought disillusionment, although I uploaded the module to the ESP32S and rewritten the pins for the ESP32.

The original

From machine import I2C
I2C = I2C(0)
I2C = I2C(0, I2C.MASTER)
I2C = I2C(0, pins=('P10','P9'))
became too
From machine import Softi2c
I2C = I2C(0,scl=Pin code(21),sda=Pin code(22))

The micropython interpreter complained a missing chrono object, in the module VL53L0X.VL53L0X in line 639. After the module is written for another port, Wipy Devices Made by Pycom, it could be good that more of such mistakes would appear. Other firmware, other identifiers for GPIO pins, different integration of hardware modules of the ESP32 ...

However, since, in addition to the I2C pins, no further connection between ESP32 and VL53L01 was used in the example, I classified the probability of further problem areas than low. So I took the method perform_single_ref_calibration() in the module VL53L0X.VL53L0X in the editor. The name Chrono indicated a time object.

And indeed, in the WIPY firmware, the use of hardware timers is solved differently than with the native ESP32. In principle, however, it is only about the initialization and review of a timeout.

From machine import timer
...
...
   def perform_single_ref_calibration(self, vhv_init_byte):
       chrono = timer.Chrono()
       self._register(Sysrange_start, 0x01|vhv_init_byte)
       chrono.begin()
       while self._register((Result_interrupt_Status & 0x07) = 0):
           Time_elapsed = chrono.read_ms()
           IF Time_elapsed > _IO_TIMEOUT:
               return False
       self._register(System_interrupt_Clear, 0x01)
       self._register(Sysrange_start, 0x00)
       return True
But I have my own software solution for that. A function, forgiveness, a method, we move in the definition of a class, i.e. a method Time-out(), which takes a period of time in milliseconds and returns the reference to a function inside. Such a construct is called Closure. I have now simply replaced time control, but shorter but just as effective.
    def Time-out(self,T):
       begin=time.Ticks_MS()
       def compare():
           return intimately(time.Ticks_MS()-begin) >= T
       return compare
    def perform_single_ref_calibration(self, vhv_init_byte):
       self._register(Sysrange_start, 0x01|vhv_init_byte)
       chrono = self.Time-out(_IO_TIMEOUT)
       while self._register((Result_interrupt_Status & 0x07) == 0):
           IF chrono() :
               return False
       self._register(System_interrupt_Clear, 0x01)
       self._register(Sysrange_start, 0x00)
       return True
In addition, relief spread when no further error message was shown when the demo program was started again. On the contrary, in the terminal after the start of my test program distance.py Loud nice distance values ​​output in cm.
# distance.py

import sys
From time import Sleep_ms,Ticks_MS, Sleep_us, sleep
From machine import Softi2c, Pin code
From OLED import OLED
From SSD1306 import SSD1306_I2C
import VL53L0X

# ************ create objects and variables *************
Scl=Pin code(22)
Sda=Pin code(21)

I2C=Softi2c(Scl,Sda)
D=OLED(I2C, Heightw=32)

button=Pin code(0,Pin code.IN)  

tof = VL53L0X.VL53L0X(I2C)
tof.set_vcsel_pulse_period(tof.vcsel_period_type[0], 18)
tof.set_vcsel_pulse_period(tof.vcsel_period_type[1], 14)
tof.begin()
print("Started")

spacer=9999

tof.read()
D.clearall()
D.writer("Body Size",2,0,False)
D.writer(" METER ",2,1,False)
D.writer("{: .1f} cm".format(spacer),4,3)
sleep(2)

while True:
   GC.collect()
   spacer=0.0
   n=10
   for I in range(n):
       spacer += tof.read()
   spacer /= (n*10) # cm
   D.writer("{: .1f} cm".format(spacer),4,2)
   print (spacer)
   sleep(1)  
   # End the loop
   IF button.value()==0:
       D.clearall()
       D.writer("Body Size",4,0,False)
       D.writer(" METER ",4,1,False)
       D.writer("Termined",3,2)
       sys.exit()

So far everything went quite well. But when I switched to a larger Breadboard to be able to accommodate the other bobs (break-out boards), I would soon be desperate. There was already an ESP32 on the second board, so I saved it. But everything that had just run perfectly did not work anymore, the VL53L0X only brought completely unusable values. After various unsuccessful attempts, I exchanged the VL53L0X, used another ESP32, took a V4 instead of an ESP32 DEV KIT V2, controlled and compared the two buildings several times, always checked the contacts, no decent function. The I2C bus worked normally, the VL53L0X reported to work. But that's it. When I took the ESP32 from the first board, the enlightenment came. Lo and behold, it worked correctly. And then I noticed the main difference. The ESP32 on the first test board had a Micropython kernel 1.18 and everyone else had the last release 1.19. After I also flashed the second ESP32 with version 1.18, he also purred like a satisfied kitten.

I already had something similar in terms of the use of PWM. I don't understand why the Micropython developers pass such bugs. A feature works perfectly and when updating with the subsequent version, gray hair gets gray hair because nothing works. Errors should be eliminated in the new version and not newly installed.

Sure, it can also happen that a component is defective, even a complex like a controller. If something does not work as it should when experimenting or replicating a circuit, then not only look for mistakes in the program or in the circuit, but also remember that the operating system of an ESP, the kernel, can be buggy. Therefore, I have already pointed out that you absolutely have to use 1.18 so that this project works.

The DF player Mini

Figure 4: DF player Mini with 4 GB SD card

Figure 4: DF player Mini with 4 GB SD card

The MP3 player is addressed via an RS232 line. I used to write a Micropython module for it. Because that was on an ESP8266, I had saved myself the trouble of taking routines for data reception, the little one, as I have already noted, has no line available, which is used as SD-D1 for the external flash chip . I therefore expanded the module for the ESP32. For example, you can now also query the version, the number of files on the SD card or the volume level.

Communication with the DF player always happens in the same way. Blocks of 10 bytes are sent and received. The structure of such a block looks like this. The method broadcommand() takes care of the correct transmission.

Start -byte 0x7e

Version number 0xff

Length of the Payoad 0x06 (From version number to parameter 2 incl.)

Command

Feedback 0x00 (no) or 0x01 (yes)

Parameter 1

Parameter 2

Checks high

Checks Low

Endebyte 0xef

The command codes can be found in data sheet find. I used this to implement the most important codes into methods of the module. We only need a few of them for the current project. But take a look at the file dfplayer.py.

In order for a voice output to be possible, we need the digits and numbers as individual, short sound files. I recorded the texts for this in one piece with my cell phone and transferred it to the PC via Bluetooth, where I then divided the file into the voice clips with Audacity. Audacity is a freewaretool for editing audio files. As an alternative, you can also use language generators, as in the series of contributions The speaking color detector with DFPlayer and TCS3200 has been used.

To create your own language modules, take the following texts. The numbers in the second column are the numbers that are later used as file names of the clips when saving on the SD card.


an 000

One 001

Two 002

ten 010

Elf 011

twelve 012

Thirteen 013

Nineteen 019

twenty 020

Thirty 030

Ninety 090

one hundred 100

Hundred 101

and 102

The file from the cell phone probably has the ending m4a. Unfortunately, Audacity cannot do anything with that. We have to be a type conversion after MP3 make. That works fine with that Online tool Convertio. Follow the link and then pull your M4A file onto the red field.

Figure 5: Convertio Start window © convertio.co

Figure 5: Convertio Start window © convertio.co

In the next window, click on Convert. The file is uploaded to the server and ...

Figure 6: Convertio - convert © convertio.co

Figure 6: Convertio - convert © convertio.co

After a few seconds you can download your MP3 file.

Figure 7: Convertio - Download © convertio.co

Figure 7: Convertio - Download © convertio.co

Now start Audacity (or alternatively an audio editor of your choice) and pull the file into the machining window.

Figure 8: Audacity with sound file

Figure 8: Audacity with sound file

With the Ctrl key and the mouse wheel zoom in and out on the trail. Now mark a clip by pulling with the mouse.

Start the memory process of the selection with Ctrl + Shift + A. Enter the numbers from the list above as file names. You can also add a text supplement at the back, about 007 seven. Click on "Save". Then enter three times, continue to the next clip.

Figure 9: Save Audacity - Clip

Figure 9: Save Audacity - Clip

Now copy the clips to a Mini SD card into the 00 folder laid out there.

How the Bodysize.Py program works

Four external modules must be uploaded to the ESP32: Vl53l0x.py, dfplayer.py, oled.py and SSD1306.PY. Then we start with imports.

# bodysize.py

import VL53L0X
From dfplayer import Dfplayer
From machine import Softi2c,Pin code
From OLED import OLED
From time import sleep
import sys

tof = VL53L0X.VL53L0X(I2C)
We instantiate an I2C object that we pass on to the constructor of the OLED class and the VL53L0X class.

The VL53L0X object is initialized and started. The first value is read in and stamped, that means we do nothing. In Height Let us put the height in centimeters, in which the sensor is later attached, for example on the top of the door.

tof.set_vcsel_pulse_period(tof.vcsel_period_type[0], 18)
tof.set_vcsel_pulse_period(tof.vcsel_period_type[1], 14)
tof.begin()
size=tof.read()
print("Tof Started")
Height=200
Then the DF player is on. The PIN numbers of the serial cables RXD and TXD as well as the Bussy line are declared and passed on to the constructor. We wait two seconds for the player to initialize. The connection works if the player reports the number of titles on the card with 31.
Rx_pin = 18
Tx_pin = 19
buss type = 17
DF=Dfplayer(Bussypinnbr=buss type, TXD=Tx_pin, RXD=Rx_pin, volume=80)
sleep(2)
numoftitles=DF.getnumbered()
print("Number of titles:",numoftitles)

A pin object for the flash button on the ESP32 is declared, then we define two functions that do the actual work and determine the body size.

def game(n):
   assert n <= 199, "The value must be between 1 and 199"
   H=n // 100
   rest=n % 100
   Z=rest // 10
   E=n % 10
   print(H,Z,E)
   S=[]
The number to be expressed must be between 1 and 199. We secure that with assert away. Became a wrong value in n Handed over, a assertation terror exception is thrown.

Then we split the number in the hundreds, the tenant, the dialing digits and the one figures. An empty list S is created and filled with the numbers of the sound clips to be played.

    IF H == 1:
       S.append(100)
On the instruction Df.Play(0.100) the DF player plays the file 100-a hundred.mp3 in the 00 folder. He does that when the hundred digit is 1.
    IF 10 <= rest < 20:
       S.append(rest)

The numbers between 10 included and 20 exclusive. The tenant is the name component of the corresponding files and is therefore on the sound list S attached.

Further special cases are the whole ten, ten, twenty and so on. Here the remnant of the tens is larger or equal to 20 and the one -digit is 0. All other remains of the rule of the rule "and" Zehnerziffer, in the case of 1 as a 1, not "one" "and" thirty ", but" a "" and "" thirty ".

    elif rest >= 20:
       IF E == 0:
           S.append(10*Z)
       Else:
           E= E IF E != 1 Else 0
           S.append(E)
           S.append(102)
           S.append(10*Z)
The Else branch treats cases 101 to 109 and 1 to 9. We have the list for control S output in the terminal. This instruction can be omitted later.
    Else:
       S.append(E)
   print(S)

The for loop now reads us the individual components of the list S before. If the player is not exactly when playing a file, it starts with the track T to offer in the 00 folder. Then the ESP32 waits until the player is ready. This is the case when the Bussy line goes to 0. The method is playing() checks that.

    for T in S:
       IF need DF.is playing():
           DF.play(0,T)
           while DF.is playing():
               passport
   return S
The function Getsize() determines the body size of the person who goes under the sensor. The assembly height Height The same must be known. The sensor records the distance spacer Between him and the person of the person. Body height size then results from the difference from Height and distance. We carry out several individual measurements for more precise results, the number of which we in the parameter n hand over. The VL53L0X delivers its measured values ​​in millimeters. Because we prefer centimeters, we also divide by 10 when calculating the average. The values ​​go into the advertisement. The value of the body size, which is rounded up to a full number, is returned.

Before entering the main loop, we put the volume of the player at 80%.

DF.volume(80)
while 1:
   size=Getsize(10)
   IF size >= 50:
       try:
           game(size)
       except Assertoreror AS E:
           D.clearall()
           D.writer("Error",4,0,False)
           D.writer("Range",4,1,False)
           D.writer("Overrun",4,2)            
   IF button.value()==0:
       D.clearall()
       D.writer("Body Size",2,0,False)
       D.writer("Program",2,1,False)
       D.writer("Termined",2,2)
       sys.exit()
We call for the height with ten individual measurements. So that the ESP32 does not exist loudly every time the kitty's cat passes the sensor, the player should only chat if the object is larger than 50 cm. Should from Getsize() Incorrect values ​​above 199 are delivered, we start the exception with Try and issue an error message on the display. Otherwise the value will be played.

In order to get out of the program during development, you can press the flash button on the ESP32. The modules are then still active. So you can handle some experiments manually. For example, discover the methods of the DF player module, or take up a welcome text in addition to the numbers and digits, which you can read reading out when starting the program. It is a special gag to separate sensor and intake part of the circuit, then no speakers hang around on the door. An ESP32 does the measurement job, a second announcement. The measurement value can be transmitted via WLAN via UDP. In the further expansion, a measuring value ad with a large display could 8x8_Led ads arise. An integrated passerby counter would also be conceivable ...

Have fun tinkering and programming!

DisplaysEsp-32Projekte für anfängerSensoren

3 comments

jr

jr

Der obige Link zur PDF geht nicht , bitte korrigieren.

Armin

Armin

Besteht auch die Möglichkeit das Ganze auf den ähnlichen Baustein VL6180X übertragen lässt? Ich brauch den „kleineren“ Bruder VL53L0X , da auf kurze Distanz eine genauere Messung damit möglich ist. Gibt es eine kompatible Bibliothek und wie sieht es mit der Firmware aus?

Thomas

Thomas

Einfach C++ und die Arduino-IDE oder Visual Studio Code nehmen und schon geht es mit einen ESP8266, da dann auch SoftwareSerial zur Ansteuerung des DFPlayer mini zur Verfügung steht. Wobei ich aber vermute, dass es das auch in Python geben wird.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery