pimoroni / vl53l1x-python

Python library for the VL53L1X Laser Ranger
https://shop.pimoroni.com/products/vl53l1x-breakout
93 stars 53 forks source link

Changing the address #14

Open lepocube opened 5 years ago

lepocube commented 5 years ago

I'm working on detecting the distance of the placed object using VL53L1X, for the enhancement of the angle of coverage, I'm using two sensors as show in the image Rpi-VL53L1X, but if I run i2cdetect -y 0 it shows as shown in the picture, Screenshot from 2019-03-19 12-52-34 for the both sensors.

After the usage details from pololu (https://forum.pololu.com/t/using-multiple-vl53l1x-with-raspberry-pi/16651/7) I have tried to change the address of the single sensor using the python script address_change_new.txt attached but the error occurred as Screenshot from 2019-03-19 12-58-39 shown in the picture

Kindly help me to get rid of it. Or suggest me a way to change the address of VL53L1X using python script.

Gadgetoid commented 5 years ago

You should look over the examples to see how to interface with the VL53L1X.

You must always create an instance of the VL53L1X class and call .open() (the same way you do when you try to talk to the changed sensor) or the library will not be correctly set up.

I'm not sure change_address works properly yet because the C library mixes 7 and 8 bit addresses in a confusing way that I was unable to reconsile.

Better documentation/examples and improvements will come eventually.

lepocube commented 5 years ago

@Gadgetoid Thank you for you quick reply. With the guidance from pololu address_change_new_pololu.txt and with the minor modification, I've changed the address of the VL53L1X. Attached the code address_change_new_pololu.txt.

After changing the address: Screenshot from 2019-03-20 10-59-23

But the problem is the two instances tof1.start_ranging(3) tof2.start_ranging(3)

are reading the value from the single sensor. The data from the second sensor is not being captured. This is identified by the hand swing above the sensor

When I swang my hand above the first sensor: Screenshot from 2019-03-20 20-29-57 the second sensor is not disturbed

When I swang my hand above the second sensor: Screenshot from 2019-03-20 20-35-38

Kindly help me to fix it.

lepocube commented 5 years ago

Sorry for the wrong attachment. The right code is attached here. address_change_new_pololu.txt

Gadgetoid commented 5 years ago

Do you have success talking to one sensor with a changed address if you remove the other one?

This library was written primarily to support our own breakout - https://shop.pimoroni.com/products/vl53l1x-breakout - not Pololu's, so I've actually not tested multiple sensors together and currently have no idea what the problem might be.

lepocube commented 5 years ago

So If I buy https://shop.pimoroni.com/products/vl53l1x-breakout, it is possible to change address? and work on multiple devices on the same bus?

lepocube commented 5 years ago

No.. If I change the address of one sensor, I'm able to change the address but not able pull the data from it.

AntaresAdroit commented 5 years ago

Nathan from Pololu here. Should there be an extra line at the end of the change_address function here? https://github.com/pimoroni/vl53l1x-python/blob/master/python/VL53L1X.py#L155

self.i2c_address = new_address

It looks like the library is successfully changing the address of the sensor, but it is not storing the new address internally so that it can use it to communicate with the sensor after that.

The callbacks probably also need to be updated when the address changes, but it might be as simple as calling _configure_i2c_library_functions again.

lepocube commented 5 years ago

@AntaresAdroit Hi Nathan. I've added the self.i2c_address = new_address in the change_address function. But this time I can't able to change the address. IOError is occurred.

@Gadgetoid Awaiting your response in it.

Gadgetoid commented 5 years ago

@lepocube our breakout isn't that different to the Pololu one and certainly isn't the solution to your problems. My point was that it lacks the XSHUT pin so it's difficult for me to replicate your setup.

@AntaresAdroit thanks for dropping in- I'll give your suggestion a look and see if I can get a single sensor working with a changed address.

Gadgetoid commented 5 years ago

This is proving just as tricky as my first attempt at getting address changing up and running. See this draft PR to track what I'm attempting and for a list of the issues I'm running into: https://github.com/pimoroni/vl53l1x-python/pull/15

Gadgetoid commented 5 years ago

Right I think I've cracked it. See https://github.com/pimoroni/vl53l1x-python/pull/15

Remove any current version of the library you have installed, then grab & install the code (python setup.py build && sudo python setup.py install).

Run change-address.py --current 0x29 --desired 0x66 and it should change the sensor address and resume communications, reading out the distance.

Turns out it needed a close and open. I haven't investigated exactly why yet, but this was causing some interesting frustrations in my tests where just calling change_address on its own was failing.

Gadgetoid commented 5 years ago

@lepocube were you able to get this working?

lepocube commented 5 years ago

This time to reduce the complexity, I've connected only one sensor and the wiring is as shown below.

2019-04-25

And I've downloaded the zip of the repository and extracted and installed the package by running the command python setup.py build && sudo python setup.py install and the installation is successfully completed. The installation is verified by running pip list and it gave the result as shown

Screenshot from 2019-04-26 11-45-49

Since I've utilised the i2c_bus 0 on raspberry pi, I've manually changed def __init__(self, i2c_bus=1, i2c_address=0x29, tca9548a_num=255, tca9548a_addr=0): to def __init__(self, i2c_bus=0, i2c_address=0x29, tca9548a_num=255, tca9548a_addr=0): in the file https://github.com/pimoroni/vl53l1x-python/blob/2323c0e1011fea0104454f5b521d00dade3bf27f/python/VL53L1X.py

as well as

tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29) to tof = VL53L1X.VL53L1X(i2c_bus=0, i2c_address=0x29) in the file https://github.com/pimoroni/vl53l1x-python/blob/f830f5305c2d256714f8e43fd3224da814b2fd85/examples/change-address.py

After the changes I've ran python change-address.py that results

Screenshot from 2019-04-26 11-31-06

After this, the address of the sensor is also not changed. Checked this via running i2cdetect -y 0 as it showed

Screenshot from 2019-04-26 11-30-09

@Gadgetoid Help me to understand what is happening?

Gadgetoid commented 5 years ago

Changing the i2c address on chip is a command sent over the existing i2c bus- IE: you need to establish a connection to change the address in the first place, which is where your setup is going wrong.

A change-address.py file is supplied as part of the proposed changes which serves as a utility for changign addresses (not suitable in your case since they will reset on power cycle) and also an example for how to accomplish the change: https://github.com/pimoroni/vl53l1x-python/blob/2323c0e1011fea0104454f5b521d00dade3bf27f/examples/change-address.py

lepocube commented 5 years ago

I've freshly brought VL53L1X from Pololu. Cloned this repo : https://github.com/lepocube/vl53l1x-python.git and installed the packages with ./install.sh.

Everything is successfully installed and got the distance data when I ran the script inside the example folder.

When I tried to change the address of the sensor with the provided script: https://github.com/pimoroni/vl53l1x-python/blob/address-change-fix/examples/change-address.py

It is clear that it changes the sensor's address. As shown below.

Screenshot from 2019-07-30 18-31-45

and also throws an IOError, so I just tried to comment the lines from 45 to 64. Which only allows the changes the address and not read the data.

After that I ran i2cdetect -y 1 to see the address change. It clearly shows the new address of the sensor as shown

Screenshot from 2019-07-30 19-16-20

But when the script tries to call the method open() inside the class VL53L1X in the VL53L1X.py file. It throws the IOError continuously as shown.

Screenshot from 2019-07-30 19-18-46

Kindly let me know what might be the issue?

Fanfwe commented 5 years ago

Hello, For the record, I have just cloned your repo, and checked-out the address-change-fix branch and installed the library. examples/change_address.py works like a charm and I am able to do ranging on two sensors connected to the same bus, taking them out of shutdown with a GPIO connected to XSHDN (I'm using the Pololu breakouts) one by one and changing their address with your script. So, from my perspective, that code is good to be merged.

dfrEak commented 5 years ago

Actually I also have the same problems

In the past, I use 2 sensors and read it 1 by 1 as NagyAttila said in the other issue(https://github.com/pimoroni/vl53l1x-python/issues/6)

but the frame rate per seconds is becoming too small if we are going to use more sensors so I asked how to change the timing budget to increase the fps because last time it was hardcoded (https://github.com/pimoroni/vl53l1x-python/issues/16)

So if you want a temporary solution, maybe NagyAttila's can work until we can know what is the problem

I tried the new address fix, but still getting the remote I/O error like lepocube

still doing some investigation of this address problem edited: my error appeared when I open the sensor after I close it

""" Open and start the VL53L1X ranging sensor """ tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=addr_current) tof.open() # Initialise the i2c bus and configure the sensor tof.change_address(addr_desired) tof.close() tof.open() tof.start_ranging(1) # Start ranging, 1 = Short Range, 2 = Medium Range, 3 = Long Range

when I comment those open and close, getting the error that make the tof.get_distance= -1 because the address is not changed when I didn't close and open it again

Gadgetoid commented 4 years ago

I'm pretty rusty on this codebase due to how many things I juggle, but I've merged the address change feature to try and foster its continued improvement.

While address changing works, I can't seem to perform a "hot change", IE: connect to an existing sensor, change its address, re-open it and begin reading data. Something buried in the VL53L1X API is causing a wall of spurious reads to the old I2C address- presumably there's some threading buried in there that I've missed.

Michdo93 commented 4 years ago

I have solved it like this:

#!/usr/bin/env python

import VL53L1X
import RPi.GPIO as GPIO
import time

XSHUT1 = 25
XSHUT2 = 12

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(XSHUT1, GPIO.OUT)
GPIO.setup(XSHUT2, GPIO.OUT)
GPIO.output(XSHUT1, False)
GPIO.output(XSHUT2, False)

GPIO.output(XSHUT1, True)

tof1 = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof1.open()
tof1.change_address(new_address = 0x28)

tof1.open()

#GPIO.output(XSHUT1, False)
GPIO.output(XSHUT2, True)

tof2 = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof2.open()
tof2.change_address(new_address = 0x2a)

#GPIO.output(XSHUT1, True)
#GPIO.output(XSHUT2, True)

#tof1.open()
tof2.open()

GPIO.setup(XSHUT1, GPIO.IN)
GPIO.setup(XSHUT2, GPIO.IN)

You have to use on both ToF sensors the XSHUT to shut them down. Because if you try to change the address of one of them and the other one isn't shutdown, you would change on both ToF sensors the address and the second sensor can't be found. After changing the address of the first sensor you have to switch on the second sensor.

pdandis commented 4 years ago

Hi,

sounds great ... can you tell me what (exactly) vl53l1x sensors and what lib (Pimoroni, Sparkfun etc.) you are using? My thx

Peter

Michdo93 commented 4 years ago

Hi,

sounds great ... can you tell me what (exactly) vl53l1x sensors and what lib (Pimoroni, Sparkfun etc.) you are using? My thx

Peter

It shouldn't really matter. They should be identical. I bought this one on Amazon.

I am using it on a Raspberry Pi 4 Model B. And this code runs on startup because I have create a systemd file. After the addresses are changed I am using a class file and a ROS node to get the measured distance. So this code snippet are not ranging and only changes the address as you can see.

Gadgetoid commented 4 years ago

Our (Pimoroni's - https://shop.pimoroni.com/products/vl53l1x-breakout) breakouts do not break out the XSHUT pin since they can only have a 5-pin interface for breakout garden.

However we have a new version in progress that fixes this- adding an XSHUT pad on the back. I'd be happy to include an example of this procedure ( pretty much @Michdo93's code verbatim ), as long as we can clearly communicate that it requires an XSHUT-supporting breakout.

pdandis commented 4 years ago

Fine thx, when is the Pimoroni one available? Is the a delivery date available?

Michdo93 commented 4 years ago

I have solved it like this:

#!/usr/bin/env python

import VL53L1X
import RPi.GPIO as GPIO
import time

XSHUT1 = 25
XSHUT2 = 12

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(XSHUT1, GPIO.OUT)
GPIO.setup(XSHUT2, GPIO.OUT)
GPIO.output(XSHUT1, False)
GPIO.output(XSHUT2, False)

GPIO.output(XSHUT1, True)

tof1 = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof1.open()
tof1.change_address(new_address = 0x28)

tof1.open()

#GPIO.output(XSHUT1, False)
GPIO.output(XSHUT2, True)

tof2 = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof2.open()
tof2.change_address(new_address = 0x2a)

#GPIO.output(XSHUT1, True)
#GPIO.output(XSHUT2, True)

#tof1.open()
tof2.open()

GPIO.setup(XSHUT1, GPIO.IN)
GPIO.setup(XSHUT2, GPIO.IN)

You have to use on both ToF sensors the XSHUT to shut them down. Because if you try to change the address of one of them and the other one isn't shutdown, you would change on both ToF sensors the address and the second sensor can't be found. After changing the address of the first sensor you have to switch on the second sensor.

As completion:

You have to save this Python Script on your device and you have to install the Python Library for the sensor globally. You can call this on startup:

[Unit]
Description=<name of your service>
After=network.target

[Service]
ExecStart=/usr/bin/python3 -u <name of your python script>.py
WorkingDirectory=/home/pi/<path to your python script>
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

The example was give for a Raspberry Pi. Maybe you also have to change the User. Then you have to save the service file.

After that you have to copy it to the sysemd services like that sudo cp ~/<maybe folder name>/<name of your service file>.service /etc/systemd/system/<name of your service file>.service

And then you can start the service that it runs the Python script on every startup. sudo systemctl enable <name of your service file>.service

If you want to use this sensor you can create a Python Class like this:

import os
import sys
import time
import RPi.GPIO as GPIO
import VL53L1X

class ToFVL53L1X(object):

    def __init__(self, address, xshut):
        self.address = address

        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)

        self.xshut = xshut
        GPIO.setup(self.xshut, GPIO.IN)

        # 1 = Short Range, 2 = Medium Range, 3 = Long Range 
        self.range = 1

        if(self.address == 0x29):
            self.tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address = 0x29)
        else:
            self.tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address = self.address)
            self.tof.open()

    def start_sensor(self, pin):
        # The XSHUT pin is set HIGH to activate the sensor.
        GPIO.setup(pin, GPIO.OUT)
        GPIO.output(pin, True)
        time.sleep(0.2)

        self.tof.open()
        self.tof.start_ranging(self.range)

    def stop_sensor(self, pin):
        self.tof.stop_ranging()
        GPIO.output(pin, False)

    def set_range(self, range):
        if range == "short":
            self.range = 1
        elif range == "medium":
            self.range = 2
        else:
            self.range = 3

        self.tof.stop_ranging()
        self.tof.start_ranging(self.range)

    def get_range(self):
        if self.range == 1:
            currentRange = "short"
        elif self.range == 2:
            currentRange = "medium"
        else:
            currentRange = "long"

        return currentRange

    def get_distance(self):
        distance = 0.0
        distance = self.tof.get_distance() * 0.1 # mm to cm conversion

        return distance

Then you can test it with: (the order of tof1 and tof2 can be different then on the Startup File which changes the address. Also you have to make sure, that you import the right class file an not the library.)

from tof_vl53l1x import ToFVL53L1X

tof1 = ToFVL53L1X(0x28, 25)
tof2 = ToFVL53L1X(0x2a, 12)

tof1.start_sensor(25)
tof2.start_sensor(12)

tof1.set_range("short")
tof2.set_range("medium")

while True:
    print(tof1.get_distance())
    print(tof2.get_distance())
pdandis commented 4 years ago

Hi,

my txh I just ordered the sensors .... perhaps I will get back to you after getting it from the vendor.

Popeye78 commented 4 years ago

Hello, I think my experience might help some developers. I started in april my first project on raspberry : a theremin. Consulting newsgroups helped me a lot, and I want to thank all the contributors

My project : Raspberry PI4, Sonic-PI, PythonOSC, two Pimoroni VL53L1X. The two variables "Pitch" and "Volume" are transmitted by OSC.

No difficulty in defining two I2C buses and placing the sensors on them

1- Unfortunately, it would be necessary to clone the python code VL53L1X by changing all the variables. The clone would serve for the second sensor. I am not able to do this.

2- Impossible to put a sensor on standby with the INT pin !! (Pimoroni ?)

My solution : manage each TOF by a specific python and execute each python in a different process. For example, launch by shell : python3 task_one.py & python3 task_two.py &

To be more precise, my "Volume" task is in the background, unlike my "Pitch" task which will support a GUI allowing to influence the Pitch.

Currently everything is working fine, but I have a lot of difficulty finding the Sonic-pi solution to get a "Theremin" sound. But this is another story :o)

Gadgetoid commented 2 years ago

For posterity:

Support for address change is in > v0.0.4 - https://github.com/pimoroni/vl53l1x-python/releases/tag/v0.0.4

And facilitated via a Python script - https://github.com/pimoroni/vl53l1x-python/blob/master/examples/change-address.py