Vl53l0 ToF sensor and haptic driver analog response

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
Hethacker
 
Posts: 86
Joined: Fri Apr 05, 2019 9:02 pm

Vl53l0 ToF sensor and haptic driver analog response

Post by Hethacker »

Hello,

I am using a Time of Flight sensor attached to a haptic driver attached to a RP2040 Feather. I am trying to have the haptic driver vary in vibration intensity based on the proximity of an object given by the ToF sensor, as the object comes closer, the vibration will increase. Currently, I am using an if/elif statement to make this work, but the code only seems to recognize one of the two arguments and seems to not register the other. I have 2 questions: is there a way to create an analog response through the haptic driver or can I only use the effect IDs given on the datasheet?
Is there a better way to solve this problem than with an if/elif argument?
thank you for the help

User avatar
Hethacker
 
Posts: 86
Joined: Fri Apr 05, 2019 9:02 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by Hethacker »

Code: Select all

# Write your code here :-)
import time

import board
import busio

import adafruit_drv2605
import adafruit_vl53l0x

# Initialize I2C bus and DRV2605 module.
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)
sensor = adafruit_vl53l0x.VL53L0X(i2c)

def scale_range(value):
    """Scale a value from 0-320 (light range) to 0-9 (NeoPixel range).
    Allows remapping light value to pixel position."""
    return round(value / 550 * 8)


while True:
    print("Distance: {0}mm".format(sensor.range))
    #vl53.start_continuous()
    peak = scale_range(sensor.distance)
    distance = (int(sensor.distance))
    if distance >= 450:
        drv.sequence[0] = adafruit_drv2605.Effect(47)
        drv.sequence[1] = adafruit_drv2605.Pause(0.1)# Set the effect on slot 0.
        drv.sequence[2] = adafruit_drv2605.Effect(10)
    # You can assign effects to up to 8 different slots to combine
    # them in interesting ways. Index the sequence property with a
    # slot number 0 to 7.
    # Optionally, you can assign a pause to a slot. E.g.
    # drv.sequence[1] = adafruit_drv2605.Pause(0.5)  # Pause for half a second
        drv.play()  # play the effect
        time.sleep(0.1)  # for 0.5 seconds
        drv.stop()  # and then stop (if it's still running)
    # Increment effect ID and wrap back around to 1.
    #effect_id += 1
    #if effect_id > 123:
    #    effect_id = 1
        time.sleep(0.05) 
    elif distance <= 100:
        drv.sequence[0] = adafruit_drv2605.Effect(10)
        drv.sequence[1] = adafruit_drv2605.Pause(0.1)
        drv.sequence[2] = adafruit_drv2605.Effect(118)
        drv.play()  # play the effect
        time.sleep(0.1)  # for 0.5 seconds
        drv.stop()  # and then stop (if it's still running)
        time.sleep(0.03)

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by adafruit_support_mike »

One rule of code is "anything that works is a 'correct' functional specification of the solution", but some versions are easier to work with than others.

For the kind of code you're using, there are a few techinques that can make life easier.

The first one is to encapsulate repeated code as a function. You have multiple copies of this basic pattern:

Code: Select all

        drv.sequence[0] = adafruit_drv2605.Effect( effect_1 )
        drv.sequence[1] = adafruit_drv2605.Pause( pause )
        drv.sequence[2] = adafruit_drv2605.Effect( effect_2 )
        drv.play()
        time.sleep( 0.1 )
        drv.stop()
where the only parts that change are the values you use for the effects and the delays. Wrapping that in a function makes your code more consistent and easier to read:

Code: Select all

def run_effects ( effect_1, pause, effect_2 ):
    [ . . . ]
The next step is to realize you always use those parameters together, so you can pack them up as tuples in a list:

Code: Select all

effects_table = (
	( 47, 0.1, 10 ),
	( 10, 0.1, 118 )
)
That reduces the problem of selecting parameters to choosing a single number for the group you want.

The final piece is to choose that number. For situations where you want to match ranges of values, it's usually easiest to use a function with multiple exit points:

Code: Select all

def prime_steps ( value ):
	if value <= 3:
		return 1
	if value <= 7:
		return 2
	if value <= 11:
		return 4
	return 5
That kind of function gives you a lot of flexibility to handle complex conditions while keeping the rest of the code clean and easy to read.

User avatar
Hethacker
 
Posts: 86
Joined: Fri Apr 05, 2019 9:02 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by Hethacker »

thank you for the help, I was able to troubleshoot it to the ToF sensor only taking one reading when the program begins and not taking any more infrared readings. whatever the sensor senses first is the vibration sequence that it will play forever. I did what you said, I think, but I am still having some issues with the code. This version should at least be a little more legible.

Code: Select all

import time

import board
import busio

import adafruit_drv2605
import adafruit_vl53l0x

# Initialize I2C bus and DRV2605 module.
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)
sensor = adafruit_vl53l0x.VL53L0X(i2c)

#vibration effects
v118 = adafruit_drv2605.Effect(118)
v47 = adafruit_drv2605.Effect(47)
v10 = adafruit_drv2605.Effect(10)
v1 = adafruit_drv2605.Effect(1)
#change the pause number up to 1.25 to increase or decrease Pause length
pause = adafruit_drv2605.Pause(0.25)

#create a variable that grabs distance measurement
distance = (int(sensor.range))

# create a function that combines play/stop sequence
def vibrate_play():
    drv.play()
    time.sleep(0.1)
    drv.stop()
    time.sleep(0.03)

def far_away():
    drv.sequence[0] = v1
    drv.sequence[1] = pause
    drv.sequence[2] = v1
    vibrate_play()
    print("far away")

def medium_distance():
    drv.sequence[0] = v47
    drv.sequence[1] = pause
    drv.sequence[2] = v10
    vibrate_play()
    print("medium distance")

def close_distance():
    drv.sequence[0] = v47
    drv.sequence[1] = pause
    drv.sequence[2] = v47
    vibrate_play()
    print("close distance")

def very_close():
    drv.sequence[0] = v118
    vibrate_play()
    print("very close")
    
def prime_steps(distance):
    if distance <= 100:
        return very_close
    if distance <= 300:
        return close_distance
    if distance <= 450:
        return medium_distance
    if distance <= 600:
        return far_away

while True:
    prime_steps(distance)
    """if distance <= 100:
        very_close()
    elif distance < 449 and distance >= 201:
        close_distance()
    elif 600 > distance >= 450:
        medium_distance()
    elif distance >= 601:
        far_away()"""
    print("Distance: {0}mm".format(sensor.range))
    time.sleep(0.1)

User avatar
Hethacker
 
Posts: 86
Joined: Fri Apr 05, 2019 9:02 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by Hethacker »

I updated the code to create the tuple list, but I keep getting this error :
Traceback (most recent call last):
File "code.py", line 85, in <module>
File "code.py", line 74, in prime_steps
File "code.py", line 57, in close_distance
TypeError: function takes 3 positional arguments but 1 were given
Here is the code:

Code: Select all

import time

import board
import busio

import adafruit_drv2605
import adafruit_vl53l0x

# Initialize I2C bus and DRV2605 module.
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)
sensor = adafruit_vl53l0x.VL53L0X(i2c)

# create a variable that grabs distance measurement
distance = sensor.range
#create a variable to start continuous reading
def start():
    sensor.start_continuous()
#create a variable to stop continuous reading
def stop():
    sensor.stop_continuous()

# change the pause number up to 1.25 to increase or decrease Pause length
pause = adafruit_drv2605.Pause(0.25)

def run_effects(effect_1, pause, effect_2):
    drv.sequence[0] = adafruit_drv2605.Effect({}.format(effect_1))
    drv.sequence[1] = adafruit_drv2605.Effect({}.format(pause))
    drv.sequence[2] = adafruit_drv2605.Effect({}.format(effect_2))
    drv.play()
    time.sleep(0.1)
    drv.stop()
    time.sleep(0.03)
    
effects_table = [
(1, pause, 1),
(47, pause, 10),
(47, pause, 47),
(118, 118, 118)
]

def far_away():
    run_effects(effects_table[0])
    print("far away")
    stop()
    pass


def medium_distance():
    run_effects(effects_table[1])
    print("medium distance")
    stop()
    pass


def close_distance():
    run_effects(effects_table[2])
    print("close distance")
    stop()
    pass


def very_close():
    run_effects(effects_table[3])
    print("very close")
    stop()
    pass


def prime_steps():
    if distance <= 100:
        return very_close()
    if distance <= 300:
        return close_distance()
    if distance <= 450:
        return medium_distance()
    if distance <= 600:
        return far_away()
    else:
        pass


while True:
    start()
    prime_steps()
    print("Distance: {0}mm".format(sensor.range))
    time.sleep(0.1)

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by adafruit_support_mike »

The function run_effects() takes three arguments:

Code: Select all

def run_effects(effect_1, pause, effect_2):
but when you call it with a line from the effects table:

Code: Select all

    run_effects(effects_table[2])
Python treats effects_table[2] as a single 3-tuple. Then it complains because you aren't giving run_efects() one argument instead of three.

It's probably most convenient to modify run_effects() to accept the tuple:

Code: Select all

def run_effects( effect_list ):
    ( effect_1, pause, effect_2 ) = effect_list
    drv.sequence[0] = adafruit_drv2605.Effect({}.format(effect_1))
    drv.sequence[1] = adafruit_drv2605.Effect({}.format(pause))
    drv.sequence[2] = adafruit_drv2605.Effect({}.format(effect_2))
    drv.play()
    time.sleep(0.1)
    drv.stop()
    time.sleep(0.03)

User avatar
Hethacker
 
Posts: 86
Joined: Fri Apr 05, 2019 9:02 pm

Re: Vl53l0 ToF sensor and haptic driver analog response

Post by Hethacker »

thank you for the help, I got the code to work.

Code: Select all

import time

import board
import busio

import adafruit_drv2605
import adafruit_vl53l0x

# Initialize I2C bus and DRV2605 module.
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)
sensor = adafruit_vl53l0x.VL53L0X(i2c)

#create a variable to start continuous reading
def start():
    sensor.do_range_measurement()
#create a variable to stop continuous reading
def stop():
    sensor.stop_continuous()

effects_table = (
(1, 1 , 1),
(47, 1, 10),
(47, 118, 47),
(118, 118, 118)
)

def run_effects( effect_list ):
    ( effect_1, effect_0, effect_2 ) = effect_list
    drv.sequence[0] = adafruit_drv2605.Effect(effect_1)
    drv.sequence[1] = adafruit_drv2605.Effect(effect_0) 
    drv.sequence[2] = adafruit_drv2605.Effect(effect_2) 
    drv.play()
    time.sleep(0.1)
    drv.stop()
    time.sleep(0.03)

def far_away():
    run_effects(effects_table[0])
    print("far away")
    stop()
    pass


def medium_distance():
    run_effects(effects_table[1])
    print("medium distance")
    stop()
    pass


def close_distance():
    run_effects(effects_table[2])
    print("close distance")
    stop()
    pass


def very_close():
    run_effects(effects_table[3])
    print("very close")
    stop()
    pass


def prime_steps():
    if sensor.range <= 100:
        return very_close()
    if sensor.range <= 300:
        return close_distance()
    if sensor.range <= 450:
        return medium_distance()
    if sensor.range <= 600:
        return far_away()
    else:
        print("Too Far Away!")


while True:
    start()
    prime_steps()
    print("Distance: {0}mm".format(sensor.range))
    time.sleep(0.1)

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”