Close

Adding Audio Output and Other Stuff

A project log for A Halo For Lucy

It's not what you think.

bud-bennettBud Bennett 03/11/2019 at 22:470 Comments

My recent objective is to just get the piezo speakers to respond to changes in distance measured by the VL53L0X sensor. This is mainly a learning exercise for me -- to gain familiarity with the PWM capabilities of a digital output. I'm also attempting to streamline the code. Here's the latest code snippet:

# multiple sensors with PWM speaker outputs
import time
 
import board
from digitalio import DigitalInOut, Direction
import busio
import pulseio
import adafruit_vl53l0x

# assign pins to VL53L0X shutdown inputs
shutdown = []
shutdown.append(DigitalInOut(board.D5))
shutdown.append(DigitalInOut(board.D6))
shutdown.append(DigitalInOut(board.D9))
shutdown.append(DigitalInOut(board.D10))
shutdown.append(DigitalInOut(board.D11))
  
# assign PWM pins
piezoL = pulseio.PWMOut(board.D0, frequency=3000, duty_cycle=16000, variable_frequency=True)
piezoR = pulseio.PWMOut(board.D1, frequency=2000, duty_cycle=0, variable_frequency=True)

# turn off all sensors
for n in range(5):
    shutdown[n].direction = Direction.OUTPUT
    shutdown[n].value = False # low is off

# Initialize I2C bus and sensors.
i2c = busio.I2C(board.SCL, board.SDA)
 
# initialize led
led = DigitalInOut(board.D13)
led.direction = Direction.OUTPUT

# setup multiple VL53L0X sensors
VL53_address =[0x29, 0x2A, 0x2B, 0x2C, 0x2D]
for n in range(5):
    shutdown[n].value = True # turn on sensor
    time.sleep(0.1)
    print("Address = {}".format(VL53_address[n]))
    try:
        while not i2c.try_lock():
            pass
        result = bytearray(1)
        #set new address
        i2c.writeto(0x29, bytes([0x8A, VL53_address[n]]), stop=False)
        time.sleep(0.1)
        # verity new address
        i2c.writeto(VL53_address[n], bytes([0x8A]))
        i2c.readfrom_into(VL53_address[n],result)
        print("device address = {}".format(int.from_bytes(result,'big')))
    except:
        i2c.unlock()
    finally:
        i2c.unlock()

# instantiate all sensors and initialize distance array
VL53L0X = []
distance = []
for n in range(5):
    try:
        VL53L0X.append(adafruit_vl53l0x.VL53L0X(i2c=i2c,address=VL53_address[n], io_timeout_s=0))
        distance.append(1001)
    except:
        VL53L0X.append(None)
        distance.append(1000)
    
print("distance = {}".format(distance))

# Optionally adjust the measurement timing budget to change speed and accuracy.
# See the example here for more details:
#   https://github.com/pololu/vl53l0x-arduino/blob/master/examples/Single/Single.ino
# For example a higher speed but less accurate timing budget of 20ms:
#vl53.measurement_timing_budget = 20000
# Or a slower but more accurate timing budget of 200ms:
#vl53.measurement_timing_budget = 200000
# The default timing budget is 33ms, a good compromise of speed and accuracy.
 
def get_distances():
    global distance, VL53L0X
    for n in range(5):
        if VL53L0X[n]:
            distance[n] = VL53L0X[n].range
        else:
            distance[n] = 1000
# Main loop will read the range and print it. PWM Frequency increases with the inverse of distance.
while True:
    
    if (sum(distance) < 5000):
        print("distance1 = {}".format(distance[1]))
        if (distance[1] != 0):
            piezoL.frequency = int(1000/distance[1] * 300)
            piezoL.duty_cycle = 32768
            led.value = not led.value  # blink LED
        else:
            piezoL.duty_cycle = 0
        get_distances()
        piezoL.duty_cycle = 0
        time.sleep(0.01)
    else:
        led.value = False
        piezoL.duty_cycle = 0
        get_distances()
        time.sleep(0.25)

I still only have one VL53L0X sensor to play with.  The main loop just obtains the latest distance measurement from the sensor and changes the PWM output frequency in inverse proportion to the distance. So the piezo speaker frequency increases as the object distance decreases. It works.

Eventually, I'll mix the amplitude between the two piezo speakers to indicate a direction...

Other Stuff:

 The other stuff is related to automagically detecting VL53L0X sensors and assigning addresses, and then looping through the sensors to get distance measurements. I'm trying to keep the code relatively compact, so addressing the distance sensors as an array is pretty efficient. If a sensor is not responding, or not populated, the code doesn't care and simply skips it during the measurement process.

I think that I smoked the battery charger on the Feather M0 Express board. I connected a 260mAh HV LiPo battery to the JST connector on the Feather board and noticed magic smoke escaping.  I should have checked the pinout documents from Adafruit prior to connecting the battery. It seems that Adafruit decided to reverse the normal positive/negative leads from a battery and, "Did it My Way." I checked the markings on the battery charger IC -- it is a MCP73831. I have a few of these in inventory (doesn't everybody?). I might try to replace the smoked battery charger in the near future.

The misadventure with the battery/charger did not damage the rest of the Feather circuitry. I was able to measure the current drain of the system ( from the USB inputs) as roughly 40mA. If I use a 600mAh 14500 cell, the expected battery life would be about 15 hours. An 18650 cell with 2500mAh would last about 80 hours. Not too bad., but that is for a single sensor --- more sensors = more current.

Bottom Line:

I'm getting closer. Next steps are dependent upon receiving the ordered VL53L0X sensor modules from AliExpress. If they work as intended, then the multiple sensor data needs to be transformed into left and right audio information for direction and distance.

Discussions