VL53L1X ToF distance sensor - adapting to micropython
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: VL53L1X ToF distance sensor - adapting to micropython
Thanks, that is useful information. That's a substantial archive
AAMOI when you wrote your driver did you manage to track down a programming manual?
AAMOI when you wrote your driver did you manage to track down a programming manual?
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: VL53L1X ToF distance sensor - adapting to micropython
No, it's based on the Pololu Arduino library, if I remember correctly.
-
- Posts: 1
- Joined: Fri Oct 30, 2020 2:50 pm
Re: VL53L1X ToF distance sensor - adapting to micropython
For those with some difficults regarding how to actually get the .py file from the bitbucket archive, my small contribution:
1 - download the repository from https://bitbucket-archive.softwareherit ... 53l0x.html and extract it somewhere. You will end with folder with a .hg subfolder
2 - in a linux machine install mercurial (in Ubuntu: sudo apt install mercurial) (you may use Windows, but I only tested in Linux)
Using a terminal, do the following:
3 - create a temporary folder (for instance, "temp" ) and access it (cd temp)
4 - run the command "hg init ." (this will create a new mercurial repo in the local folder - dont forget the dot)
5- copy the .hg file from the folder created in step 1 to the new temp folder created in step 3
6 - form inside the temp folder, start a mercurial webserver with the command "hg serve".
7 - It will give you an error regarding some requirements (revlog-compression-zstd sparserevlog!). Its ok.
8 - edit the file .hg/requires and remove the entries related to the previous step (revlog-compression-zstd and sparserevlog)
9 - run "hg serve" again. It shoud give you a url (for instance, localhost:8000). Open that url with an web browser. You should see the repository
- Click in browse. The VL5310x.py is should be there
Hope it helps and sorry my english
1 - download the repository from https://bitbucket-archive.softwareherit ... 53l0x.html and extract it somewhere. You will end with folder with a .hg subfolder
2 - in a linux machine install mercurial (in Ubuntu: sudo apt install mercurial) (you may use Windows, but I only tested in Linux)
Using a terminal, do the following:
3 - create a temporary folder (for instance, "temp" ) and access it (cd temp)
4 - run the command "hg init ." (this will create a new mercurial repo in the local folder - dont forget the dot)
5- copy the .hg file from the folder created in step 1 to the new temp folder created in step 3
6 - form inside the temp folder, start a mercurial webserver with the command "hg serve".
7 - It will give you an error regarding some requirements (revlog-compression-zstd sparserevlog!). Its ok.
8 - edit the file .hg/requires and remove the entries related to the previous step (revlog-compression-zstd and sparserevlog)
9 - run "hg serve" again. It shoud give you a url (for instance, localhost:8000). Open that url with an web browser. You should see the repository
- Click in browse. The VL5310x.py is should be there
Hope it helps and sorry my english
Re: VL53L1X ToF distance sensor - adapting to micropython
You can just run "hg update" in the directory to which you unpacked the ".hg" directory.
- JonHylands
- Posts: 69
- Joined: Sun Dec 29, 2013 1:33 am
Re: VL53L1X ToF distance sensor - adapting to micropython
So I'm working on Roz, my bioloid quad walker, and I've built a new head with five VL53L1X sensors in it.
It turns out the OpenMV project has a perfectly functional VL53L1X library:
https://github.com/openmv/openmv/blob/m ... vl53l1x.py
That works for a single sensor. I added a new method to allow the user to change the id of the current sensor:
You need a lot of pauses in the right places to initialize 5 of the sensors, but it works, and I have it running.
It turns out the OpenMV project has a perfectly functional VL53L1X library:
https://github.com/openmv/openmv/blob/m ... vl53l1x.py
That works for a single sensor. I added a new method to allow the user to change the id of the current sensor:
Code: Select all
def change_id(self, new_id):
self.writeReg(0x0001, new_id & 0x7F)
pyb.delay(50)
self.address = new_id
Re: VL53L1X ToF distance sensor - adapting to micropython
Thanks for the link! I was looking for this driver for quite a while.
Also, would you provide an example for your change_ide method, say how to correctly initialize 5 sensors? What's the type of the variable new_id?
Thanks again.
Also, would you provide an example for your change_ide method, say how to correctly initialize 5 sensors? What's the type of the variable new_id?
Thanks again.
JonHylands wrote: ↑Fri Nov 27, 2020 9:59 pmSo I'm working on Roz, my bioloid quad walker, and I've built a new head with five VL53L1X sensors in it.
It turns out the OpenMV project has a perfectly functional VL53L1X library:
https://github.com/openmv/openmv/blob/m ... vl53l1x.py
That works for a single sensor. I added a new method to allow the user to change the id of the current sensor:
You need a lot of pauses in the right places to initialize 5 of the sensors, but it works, and I have it running.Code: Select all
def change_id(self, new_id): self.writeReg(0x0001, new_id & 0x7F) pyb.delay(50) self.address = new_id
- JonHylands
- Posts: 69
- Joined: Sun Dec 29, 2013 1:33 am
Re: VL53L1X ToF distance sensor - adapting to micropython
Okay, here's my code, which works pretty much 100% of the time. Note that the delays are absolutely required, but the times may need optimization. The values that I use work, but you might be able to get away with shorter delays. You will of course want to change out the shutdown pin definitions with the pins you have them hooked up to. Note also I assume that self.i2c is already set with something like this:
In my case, the HEAD_I2C_BUS is 1, since I am using I2C_1.
Note also that it is really critical to pull all five sensor shutdown pins low at the beginning - if you do a soft-reboot of your MIcroPython processor, and don't power cycle the sensors, you will try to initialize them from whatever state they are in, including their new addresses, so this routine wouldn't work. When you shut them down with the shutdown lines, you basically power cycle them, and when you start each one up, it comes up in a fresh state with the default address.
Let me know if this works for you.
Code: Select all
from machine import I2C
self.i2c = I2C(HEAD_I2C_BUS)
Note also that it is really critical to pull all five sensor shutdown pins low at the beginning - if you do a soft-reboot of your MIcroPython processor, and don't power cycle the sensors, you will try to initialize them from whatever state they are in, including their new addresses, so this routine wouldn't work. When you shut them down with the shutdown lines, you basically power cycle them, and when you start each one up, it comes up in a fresh state with the default address.
Code: Select all
HEAD_SHUTDOWN_LEFT = pyb.Pin.cpu.C3
HEAD_SHUTDOWN_FRONT_LEFT = pyb.Pin.cpu.B9
HEAD_SHUTDOWN_FRONT = pyb.Pin.cpu.B8
HEAD_SHUTDOWN_FRONT_RIGHT = pyb.Pin.cpu.C6
HEAD_SHUTDOWN_RIGHT = pyb.Pin.cpu.C7
HEAD_RANGE_DEFAULT_ADDRESS = 0x29
HEAD_RANGE_FRONT_ADDRESS = 0x30
HEAD_RANGE_FRONT_LEFT_ADDRESS = 0x31
HEAD_RANGE_FRONT_RIGHT_ADDRESS = 0x32
HEAD_RANGE_LEFT_ADDRESS = 0x33
HEAD_RANGE_RIGHT_ADDRESS = 0x34
def initializeRangeSensors(self):
shutdown_left_pin = pyb.Pin(HEAD_SHUTDOWN_LEFT, pyb.Pin.OUT_PP)
shutdown_front_left_pin = pyb.Pin(HEAD_SHUTDOWN_FRONT_LEFT, pyb.Pin.OUT_PP)
shutdown_front_pin = pyb.Pin(HEAD_SHUTDOWN_FRONT, pyb.Pin.OUT_PP)
shutdown_front_right_pin = pyb.Pin(HEAD_SHUTDOWN_FRONT_RIGHT, pyb.Pin.OUT_PP)
shutdown_right_pin = pyb.Pin(HEAD_SHUTDOWN_RIGHT, pyb.Pin.OUT_PP)
# Shut down all the sensors
shutdown_left_pin.value(0)
shutdown_front_left_pin.value(0)
shutdown_front_right_pin.value(0)
shutdown_right_pin.value(0)
shutdown_front_pin.value(0)
pyb.delay(250)
shutdown_front_pin.value(1)
pyb.delay(250)
self.front_lidar = VL53L1X(self.i2c, address=HEAD_RANGE_DEFAULT_ADDRESS)
pyb.delay(100)
self.front_lidar.change_id(HEAD_RANGE_FRONT_ADDRESS)
pyb.delay(100)
shutdown_front_left_pin.value(1)
pyb.delay(100)
self.front_left_lidar = VL53L1X(self.i2c, address=HEAD_RANGE_DEFAULT_ADDRESS)
pyb.delay(100)
self.front_left_lidar.change_id(HEAD_RANGE_FRONT_LEFT_ADDRESS)
pyb.delay(100)
shutdown_front_right_pin.value(1)
pyb.delay(100)
self.front_right_lidar = VL53L1X(self.i2c, address=HEAD_RANGE_DEFAULT_ADDRESS)
pyb.delay(100)
self.front_right_lidar.change_id(HEAD_RANGE_FRONT_RIGHT_ADDRESS)
pyb.delay(100)
shutdown_left_pin.value(1)
pyb.delay(100)
self.left_lidar = VL53L1X(self.i2c, address=HEAD_RANGE_DEFAULT_ADDRESS)
pyb.delay(100)
self.left_lidar.change_id(HEAD_RANGE_LEFT_ADDRESS)
pyb.delay(100)
shutdown_right_pin.value(1)
pyb.delay(100)
self.right_lidar = VL53L1X(self.i2c, address=HEAD_RANGE_DEFAULT_ADDRESS)
pyb.delay(100)
self.right_lidar.change_id(HEAD_RANGE_RIGHT_ADDRESS)
pyb.delay(100)
Re: VL53L1X ToF distance sensor - adapting to micropython
Thanks a lot. I ordered a few of them, and will test when I get them.
-
- Posts: 15
- Joined: Fri Feb 25, 2022 2:55 am
Re: VL53L1X ToF distance sensor - adapting to micropython
The following code works on my Raspberry Pi Pico running uPy v1.19. This code was adapted from the OpenMV file which available on their github. I added a few things and cut down on some of the sleep times.
Code: Select all
import rp2
from machine import Pin, I2C
import utime
VL51L1X_DEFAULT_CONFIGURATION = bytes([
0x00, # 0x2d : set bit 2 and 5 to 1 for fast plus mode (1MHz I2C), else don't touch */
0x00, # 0x2e : bit 0 if I2C pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD) */
0x00, # 0x2f : bit 0 if GPIO pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD) */
0x01, # 0x30 : set bit 4 to 0 for active high interrupt and 1 for active low (bits 3:0 must be 0x1), use SetInterruptPolarity() */
0x02, # 0x31 : bit 1 = interrupt depending on the polarity, use CheckForDataReady() */
0x00, # 0x32 : not user-modifiable */
0x02, # 0x33 : not user-modifiable */
0x08, # 0x34 : not user-modifiable */
0x00, # 0x35 : not user-modifiable */
0x08, # 0x36 : not user-modifiable */
0x10, # 0x37 : not user-modifiable */
0x01, # 0x38 : not user-modifiable */
0x01, # 0x39 : not user-modifiable */
0x00, # 0x3a : not user-modifiable */
0x00, # 0x3b : not user-modifiable */
0x00, # 0x3c : not user-modifiable */
0x00, # 0x3d : not user-modifiable */
0xff, # 0x3e : not user-modifiable */
0x00, # 0x3f : not user-modifiable */
0x0F, # 0x40 : not user-modifiable */
0x00, # 0x41 : not user-modifiable */
0x00, # 0x42 : not user-modifiable */
0x00, # 0x43 : not user-modifiable */
0x00, # 0x44 : not user-modifiable */
0x00, # 0x45 : not user-modifiable */
0x20, # 0x46 : interrupt configuration 0->level low detection, 1-> level high, 2-> Out of window, 3->In window, 0x20-> New sample ready , TBC */
0x0b, # 0x47 : not user-modifiable */
0x00, # 0x48 : not user-modifiable */
0x00, # 0x49 : not user-modifiable */
0x02, # 0x4a : not user-modifiable */
0x0a, # 0x4b : not user-modifiable */
0x21, # 0x4c : not user-modifiable */
0x00, # 0x4d : not user-modifiable */
0x00, # 0x4e : not user-modifiable */
0x05, # 0x4f : not user-modifiable */
0x00, # 0x50 : not user-modifiable */
0x00, # 0x51 : not user-modifiable */
0x00, # 0x52 : not user-modifiable */
0x00, # 0x53 : not user-modifiable */
0xc8, # 0x54 : not user-modifiable */
0x00, # 0x55 : not user-modifiable */
0x00, # 0x56 : not user-modifiable */
0x38, # 0x57 : not user-modifiable */
0xff, # 0x58 : not user-modifiable */
0x01, # 0x59 : not user-modifiable */
0x00, # 0x5a : not user-modifiable */
0x08, # 0x5b : not user-modifiable */
0x00, # 0x5c : not user-modifiable */
0x00, # 0x5d : not user-modifiable */
0x01, # 0x5e : not user-modifiable */
0xdb, # 0x5f : not user-modifiable */
0x0f, # 0x60 : not user-modifiable */
0x01, # 0x61 : not user-modifiable */
0xf1, # 0x62 : not user-modifiable */
0x0d, # 0x63 : not user-modifiable */
0x01, # 0x64 : Sigma threshold MSB (mm in 14.2 format for MSB+LSB), use SetSigmaThreshold(), default value 90 mm */
0x68, # 0x65 : Sigma threshold LSB */
0x00, # 0x66 : Min count Rate MSB (MCPS in 9.7 format for MSB+LSB), use SetSignalThreshold() */
0x80, # 0x67 : Min count Rate LSB */
0x08, # 0x68 : not user-modifiable */
0xb8, # 0x69 : not user-modifiable */
0x00, # 0x6a : not user-modifiable */
0x00, # 0x6b : not user-modifiable */
0x00, # 0x6c : Intermeasurement period MSB, 32 bits register, use SetIntermeasurementInMs() */
0x00, # 0x6d : Intermeasurement period */
0x0f, # 0x6e : Intermeasurement period */
0x89, # 0x6f : Intermeasurement period LSB */
0x00, # 0x70 : not user-modifiable */
0x00, # 0x71 : not user-modifiable */
0x00, # 0x72 : distance threshold high MSB (in mm, MSB+LSB), use SetD:tanceThreshold() */
0x00, # 0x73 : distance threshold high LSB */
0x00, # 0x74 : distance threshold low MSB ( in mm, MSB+LSB), use SetD:tanceThreshold() */
0x00, # 0x75 : distance threshold low LSB */
0x00, # 0x76 : not user-modifiable */
0x01, # 0x77 : not user-modifiable */
0x0f, # 0x78 : not user-modifiable */
0x0d, # 0x79 : not user-modifiable */
0x0e, # 0x7a : not user-modifiable */
0x0e, # 0x7b : not user-modifiable */
0x00, # 0x7c : not user-modifiable */
0x00, # 0x7d : not user-modifiable */
0x02, # 0x7e : not user-modifiable */
0xc7, # 0x7f : ROI center, use SetROI() */
0xff, # 0x80 : XY ROI (X=Width, Y=Height), use SetROI() */
0x9B, # 0x81 : not user-modifiable */
0x00, # 0x82 : not user-modifiable */
0x00, # 0x83 : not user-modifiable */
0x00, # 0x84 : not user-modifiable */
0x01, # 0x85 : not user-modifiable */
0x01, # 0x86 : clear interrupt, use ClearInterrupt() */
0x40 # 0x87 : start ranging, use StartRanging() or StopRanging(), If you want an automatic start after VL53L1X_init() call, put 0x40 in location 0x87 */
])
class VL53L1X:
def __init__(self, i2c):
self.i2c = i2c
self.address = 0x29
self.reset()
utime.sleep(1)
if self.read_model_id() != 0xEACC:
raise RuntimeError('Failed to find expected ID register values. Check wiring!')
# write default configuration
self.i2c.writeto_mem(self.address, 0x2D, VL51L1X_DEFAULT_CONFIGURATION, addrsize=16)
utime.sleep(1)
# the API triggers this change in VL53L1_init_and_start_range() once a
# measurement is started; assumes MM1 and MM2 are disabled
self.writeReg16Bit(0x001E, self.readReg16Bit(0x0022) * 4)
utime.sleep(1)
def writeReg(self, reg, value):
return self.i2c.writeto_mem(self.address, reg, bytes([value]), addrsize=16)
def writeReg16Bit(self, reg, value):
return self.i2c.writeto_mem(self.address, reg, bytes([(value >> 8) & 0xFF, value & 0xFF]), addrsize=16)
def readReg(self, reg):
return self.i2c.readfrom_mem(self.address, reg, 1, addrsize=16)[0]
def readReg16Bit(self, reg):
data = self.i2c.readfrom_mem(self.address, reg, 2, addrsize=16)
return (data[0]<<8) + data[1]
def read_model_id(self):
return self.readReg16Bit(0x010F)
def reset(self):
self.writeReg(0x0000, 0x00)
utime.sleep(1)
self.writeReg(0x0000, 0x01)
def read(self):
data = self.i2c.readfrom_mem(self.address, 0x0089, 17, addrsize=16) # RESULT__RANGE_STATUS
range_status = data[0]
# report_status = data[1]
stream_count = data[2]
dss_actual_effective_spads_sd0 = (data[3]<<8) + data[4]
# peak_signal_count_rate_mcps_sd0 = (data[5]<<8) + data[6]
ambient_count_rate_mcps_sd0 = (data[7]<<8) + data[8]
# sigma_sd0 = (data[9]<<8) + data[10]
# phase_sd0 = (data[11]<<8) + data[12]
final_crosstalk_corrected_range_mm_sd0 = (data[13]<<8) + data[14]
peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (data[15]<<8) + data[16]
#status = None
#if range_status in (17, 2, 1, 3):
#status = "HardwareFail"
#elif range_status == 13:
#status = "MinRangeFail"
#elif range_status == 18:
#status = "SynchronizationInt"
#elif range_status == 5:
#status = "OutOfBoundsFail"
#elif range_status == 4:
#status = "SignalFail"
#elif range_status == 6:
#status = "SignalFail"
#elif range_status == 7:
#status = "WrapTargetFail"
#elif range_status == 12:
#status = "XtalkSignalFail"
#elif range_status == 8:
#status = "RangeValidMinRangeClipped"
#elif range_status == 9:
#if stream_count == 0:
#status = "RangeValidNoWrapCheckFail"
#else:
#status = "OK"
return final_crosstalk_corrected_range_mm_sd0
def get_mm(self):
return test.read()
def get_in(self):
return test.read()*0.0393701
def get_ft(self):
return test.read()*0.0393701/12
i2c = I2C(0, freq=400000, sda=Pin(0), scl=Pin(1))
print(i2c.scan()[0])
test = VL53L1X(i2c)
print("OUTSIDE WHILE LOOP")
while(True):
print("Distance in mm: ", test.get_mm() )
print("Distance in in: ", test.get_in() )
print("Distance in feet: ", test.get_ft() )
utime.sleep(0.05)
Re: VL53L1X ToF distance sensor - adapting to micropython
FYI. I added forks of some of deshipu's archived repos up on my github: https://github.com/mcauser?tab=repositories&q=deshipu
Less mercurial, more git.
Less mercurial, more git.