0

VL53L0X TOF MicroPython/CircuitPython support.
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

VL53L0X TOF MicroPython/CircuitPython support.

by TropicalDragon on Tue Nov 14, 2017 11:36 am

Guys,

Are there plans to support the VL53L0X TOF with a MicroPython or CircuitPython library?. I'm aware of this unofficial Python Library (for Raspberry Pi):

https://github.com/johnbryanmoore/VL53L0X_rasp_python

...but I doubt it would work with devices such as the Feather Huzzah (ESP8266 based).

Your help will be greatly appreciated.

Thanks,

TropicalDragon
 
Posts: 6
Joined: Sat Jun 17, 2017 11:45 pm

Re: VL53L0X TOF MicroPython/CircuitPython support.

by jerryn on Tue Nov 14, 2017 12:12 pm

You may find this of interest: https://github.com/popunder/VL53L0X
I have been able to adapt this greatly simplified configuration to work under CircuitPython but I have not convinced myself I understand how or why it works ;-)

jerryn
 
Posts: 438
Joined: Sat Sep 14, 2013 9:05 am

Re: VL53L0X TOF MicroPython/CircuitPython support.

by jerryn on Tue Nov 14, 2017 12:46 pm

Against my better judgment, I am going to post the code I have been using for this here. Be warned this is crude test code that was developed quickly as a learning experience. I take no responsibilty and little credit for it - it was just an adaptation of https://github.com/popunder/VL53L0X - any credit goes there.
I have executed it under CircuitPython 2.1.0 on a Metro-M0_Express and under 3.0-alpha on a a Metro_M4 (prototype).
I also have an earlier version that ran on an esp8266.
I hope it is useful:
Code: Select all | TOGGLE FULL SIZE
from board import *
import busio
import struct
import time

import adafruit_bus_device.i2c_device as i2c_device

VL53L0X_I2CADDR_DEFAULT                         = const(0x29)
VL53L0X_REG_IDENTIFICATION_MODEL_ID             = const(0x00c0)
VL53L0X_REG_IDENTIFICATION_REVISION_ID          = const(0x00c2)
VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD       = const(0x0050)
VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD     = const(0x0070)
VL53L0X_REG_SYSRANGE_START                      = const(0x000)

VL53L0X_REG_RESULT_INTERRUPT_STATUS             = const(0x0013)
VL53L0X_REG_RESULT_RANGE_STATUS                 = const(0x0014)



class vl53l0x():


    def __init__(self, i2c, address=VL53L0X_I2CADDR_DEFAULT):
        self._i2c = i2c_device.I2CDevice(i2c, address)
        self._buffer = bytearray(20)
        self.init()

    def _write_register_byte(self, register, value):
        # Write a byte value to the specifier register address.
        with self._i2c:
            self._buffer[0]=register
            self._buffer[1]=value
            self._i2c.write(self._buffer,end=2)

    def _read_register_bytes(self, register, length=1):
        # Read the specified register address and fill the specified result byte
        # array with result bytes.  Make sure result buffer is the desired size
        # of data to read.
        with self._i2c:
            self._buffer[0]=register
            self._i2c.write(self._buffer,end=1,stop=False)
            self._i2c.read_into(self._buffer,start=1, end=length+1)
            return self._buffer[1:length+1]
    def _write_register_bytes(self, register, data, length=None):
        # Write the specified register address with contenst of data
        # Make sure data buffer is the desired size
        # of data to write.
        if length is None:
            length = len(data)
        with self._i2c:
            self._buffer[0]=register
            self._i2c.write(buffer,end=1, stop=False)
            self._i2c.write(bytes([data]),end=length,stop=False)

    def init(self):
        val=self._read_register_bytes(VL53L0X_REG_IDENTIFICATION_REVISION_ID,1)
        print ("Revision ID: ", val[0])
        val=self._read_register_bytes(VL53L0X_REG_IDENTIFICATION_MODEL_ID,1)
        print( "Device ID: " , val[0])
        val=self._read_register_bytes(VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,1)
        print( "PRE_RANGE_CONFIG_VCSEL_PERIOD=", (val[0]) , " decode: " , str(VL53L0X_decode_vcsel_period(val[0])))
        val=self._read_register_bytes(VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,1)
        print ("FINAL_RANGE_CONFIG_VCSEL_PERIOD=" , (val[0]) , " decode: " , str(VL53L0X_decode_vcsel_period(val[0])))

    def make_measurement(self):
        self._write_register_byte(VL53L0X_REG_SYSRANGE_START,0x01)
        cnt = 0
        while (cnt < 100): # 1 second waiting time max
            time.sleep(.001)
            response=bytearray(1)
            val=self._read_register_bytes(VL53L0X_REG_RESULT_RANGE_STATUS,1)
            if (val[0] & 0x01):
                break
            cnt += 1

        if (val[0] & 0x01):
            print( "ready")
        else:
            print( "not ready")

#   Status = VL53L0X_ReadMulti(Dev, 0x14, localBuffer, 12);
        return self._read_register_bytes(VL53L0X_REG_RESULT_RANGE_STATUS,12)


def makeuint16(lsb, msb):
    return ((msb & 0xFF) << 8)  | (lsb & 0xFF)
def VL53L0X_decode_vcsel_period(vcsel_period_reg):
# Converts the encoded VCSEL period register value into the real
# period in PLL clocks
    vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
    return vcsel_period_pclks;

with busio.I2C(SCL,SDA) as i2c:
    vl=vl53l0x(i2c,0x29)
    while(True):
        buff = vl.make_measurement()
#    print (buff)
#    print ("Range Status",buff[0])
        DeviceRangeStatusInternal = ((buff[0] & 0x78) >> 3)
        print ("Status ",DeviceRangeStatusInternal)
# from vl53l0x_api_core: VL53L0X_get_pal_range_status
# 11=good ,1,2,3 =HW Fail 6,9=Phase Fail 8,10=Min Range Fail 4=Signal Fail 0,5 not specified
        if(DeviceRangeStatusInternal == 11):
            print ("SPAD Rtn count " , str(makeuint16(buff[3], buff[2])))
            print ("signal count " , str(makeuint16(buff[7], buff[6])))
            print ("ambient count " , str(makeuint16(buff[9], buff[8])))
            print ("distance " , str(makeuint16(buff[11], buff[10])))

        time.sleep(.1)


jerryn
 
Posts: 438
Joined: Sat Sep 14, 2013 9:05 am

Re: VL53L0X TOF MicroPython/CircuitPython support.

by TropicalDragon on Tue Nov 14, 2017 2:58 pm

Jerryn, this is great!, thanks for sharing. I'll try it out shortly. Quick question: have you tried on a Feather Huzzah or a Trinket M0?

TropicalDragon
 
Posts: 6
Joined: Sat Jun 17, 2017 11:45 pm

Re: VL53L0X TOF MicroPython/CircuitPython support.

by jerryn on Tue Nov 14, 2017 3:21 pm

I had it working on a Feather Huzzah - have not tried it in awhile - I can try it again later today and post that version after I check it out. I have not tried it on a Tinket, but I can do that as well - not sure if there is enough space for it. Will update when I do.

jerryn
 
Posts: 438
Joined: Sat Sep 14, 2013 9:05 am

Re: VL53L0X TOF MicroPython/CircuitPython support.

by jerryn on Tue Nov 14, 2017 5:26 pm

The posted example runs on the feather_Huzzah ESP8266 and on the Trinket M0.
One thing to note is the for CircuitPython 2.x you will have to change:
Code: Select all | TOGGLE FULL SIZE
import struct
to
import ustruct as struct


It runs as is on the M0 for 3.0 since struct has been implemented there.

Good luck!
you also may find this guide interesting - It uses the VL6180X as an example of how to convert and Arduino library to a CP library. The VL53L0X should be similar, but I have not tried it....yet
https://learn.adafruit.com/porting-an-arduino-library-to-circuitpython-vl6180x-distance-sensor/template

I am still puzzled by the example from Popunder - It must be just allowing many of the default configurations to of the VL53L0X to remain set but it seems to work quite well. Tracing all the configurations and understanding why this example can get away with so little configuration has long been on my "todo" list. Any insights would be welcomed.

jerryn
 
Posts: 438
Joined: Sat Sep 14, 2013 9:05 am

Re: VL53L0X TOF MicroPython/CircuitPython support.

by TropicalDragon on Tue Nov 14, 2017 7:22 pm

That's great, thanks for reporting back, I really appreciate it !. I should get the TOF sensor in the mail shortly and will test it then. Ideally, I would love to use the sensor with the Huzzah32, but I don't think there is CircuitPython support for that one yet. I read it would run MicroPython ESP32, but I will have to try it first. If that works, your code should work on the Huzzah32 as well (I think...?).

I glanced at the tutorial on porting an Arduino library to CircuitPython, but I'm not sure if I'll be able to do it for the VL53L0X (some parts of the tutorial are not easy to grasp, at least for me). Additionally, I couldn't find the VL6180X Python library on Adafruit's GitHub repositories, which seems odd (perhaps that library is a work in process?).

TropicalDragon
 
Posts: 6
Joined: Sat Jun 17, 2017 11:45 pm

Re: VL53L0X TOF MicroPython/CircuitPython support.

by jerryn on Tue Nov 14, 2017 10:54 pm

The conversion of the library is certainly not an easy thing to do and now that I look at the code for the VL53L0X it is much different than that for the VL6180X. BTW, the code for the VL6180X is at: https://github.com/adafruit/Adafruit_VL6180X

I'm glad you asked put this. I had shelved this and this was a good excuse to take a fresh look at it, especially since you suggested run-in it on a Trinket_M0 - I have been playing with it this evening and it is working pretty well. The onboard DotStar is nice for indicating the distance measured by it.

Good luck with your projects. I have no experience with the ESP32 boards but if it runs Micropython it should support I2C and be able to communicate wit the board. When I first started playing with this it was under Micropython and someone else had done a port of the Pololu VL53L0X library https://github.com/pololu/vl53l0x-arduino but it was still pretty large. The Popunder code was much simpler to work with.

jerryn
 
Posts: 438
Joined: Sat Sep 14, 2013 9:05 am

Please be positive and constructive with your questions and comments.