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
Vl53l0 ToF sensor and haptic driver analog response
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- Hethacker
- Posts: 86
- Joined: Fri Apr 05, 2019 9:02 pm
- Hethacker
- Posts: 86
- Joined: Fri Apr 05, 2019 9:02 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
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)
- adafruit_support_mike
- Posts: 67391
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
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:
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:
The next step is to realize you always use those parameters together, so you can pack them up as tuples in a list:
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:
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.
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()
Code: Select all
def run_effects ( effect_1, pause, effect_2 ):
[ . . . ]
Code: Select all
effects_table = (
( 47, 0.1, 10 ),
( 10, 0.1, 118 )
)
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
- Hethacker
- Posts: 86
- Joined: Fri Apr 05, 2019 9:02 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
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)
- Hethacker
- Posts: 86
- Joined: Fri Apr 05, 2019 9:02 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
I updated the code to create the tuple list, but I keep getting this error :
Here is the code: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
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)
- adafruit_support_mike
- Posts: 67391
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
The function run_effects() takes three arguments:
but when you call it with a line from the effects table:
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_1, pause, effect_2):
Code: Select all
run_effects(effects_table[2])
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)
- Hethacker
- Posts: 86
- Joined: Fri Apr 05, 2019 9:02 pm
Re: Vl53l0 ToF sensor and haptic driver analog response
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)
Please be positive and constructive with your questions and comments.