A Halo For Lucy

It's not what you think.

Public Chat
Similar projects worth following
Lucy is slowly going blind. We bought a halo from Amazon -- it is heavy and clunky and could have been made 100 years ago. It's time for an upgrade to something lighter and better.

Lucy is our seven year-old border collie schipperke mix. We got her as a puppy. 18 months ago she was diagnosed with Progressive Retinal Atrophy -- she is not getting enough blood flow to her retinae and she is slowly going blind. There is no cure.

She can still see in bright light, but has difficulty seeing in dim light or at night. She memorized our house layout and normally doesn't have any difficulty getting around day or night unless something has moved. Occasionally she bumps into something left in the middle of the floor or a drawer left unclosed. 

We purchased a halo. It is a metal hoop that surrounds her head. If she inadvertently gets too close to an object the halo will collide with the object instead of her head. The halo is attached in two locations to her body -- a strap around her neck, and a strap around her chest. The contraption looks uncomfortable to me, but Lucy has tolerated it the few times we have burdened her with it. There must be a better way.

I have begun to investigate an alternative to the halo. Lucy still has all of her other senses. I think that I can design and manufacture an electronic equivalent to the halo that will be smaller, lighter, and function better that what is available now.

The criteria:

  1. Fit -- should be easily applied and removed. Location -- above the head. Lucy should be able to sleep with the halo attached.
  2. Light -- Lucy is a small dog, about 25 pounds. The entire unit should weigh just a few ounces.
  3. Range and direction -- should be able to detect object from about 10mm to 1000mm. It should be able to indicate the position and approximate distance of the nearest object within range. Additionally, it should be able to indicate position and range of multiple objects (a stretch goal).
  4. It should perform similarly in brightly lit and poorly lit environments.
  5. It should not degrade Lucy's other senses.
  6. Battery operated -- 170 hrs of operation from a rechargeable lithium battery cell.

  • The Second Pass Prototype

    Bud Bennett04/20/2019 at 19:09 0 comments

    A list of new features and/or changes after testing the first prototype:

    1. Only three VL53L0X distance sensors. Five sensors is confusing and not necessary. There will be dead zones because the outer two sensors will be 50° off of the front sensor. This was not a problem in the first prototype when two of the sensors were disabled.
    2. Exchanged the Arduino Feather for the Arduino ItsyBitsy -- its a lot smaller with nearly all of the same capabilities.
    3. Added a LIS3DH accelerometer for motion and tilt sensing. This will allow the system to mute when no motion is detected or the unit is tilted significantly off-axis (i.e. sleeping). It should also disable the forward sensor detection when Lucy is pointing her head at the ground.
    4. Added a battery charging function. 500mA when the USB is plugged into a 5V source. The charge indicator is a LED on the Itsy via the D12 pin.
    5. Added a separate PIC10F322 µC to monitor the battery voltage and put the system to sleep (<100µA) when the battery voltage drops below about 3.3V. The PIC will also monitor the accelerometer activity and put the system to sleep after TBD seconds of inactivity -- a battery saving measure.

    The Second Pass Schematic:

    The MCP73832 is the same as the MCP73831 but the STAT output is a pulldown only. The ItsyBitsy will present a weak pullup on its D12 input and only pull to 3.3V.

    There is a separate 3.3V LDO regulator providing power to the accelerometer and the PIC. The accelerometer is configured to latch the INT1 pin high when motion is detected above a certain threshold. The latch is reset when the Itsy reads the INT1_SRC register every TBD seconds. If INT1 doesn't go high after TBD seconds then the PIC will disable the Itsy by pulling down the En pin, which turns off the Itsy's 3.3V regulator. This puts the system to sleep with a relatively low current drain. If the accelerometer detects motion again it will assert INT1 and the PIC will re-enable the Itsy. 

    (Note: the connection from INT1 to D7 is not necessary since the Itsy can read the status of the accelerometer over the I2C interface, but I thought there might be some value to have be able to read the INT1 pin for debugging purposes. This brings up a sticky issue because the accelerometer and the Itsy are on two separate supplies. The Itsy's LDO is fed by two Schottky diodes to pick up power from either USB or BAT. When the battery voltage gets below about 3.5V the Itsy's supply voltage will fall below 3.3V because of the drop across the Schottky. But I measured the total voltage drop between BAT and the 3.3V supply as only 200mV, which should not cause a latchup problem.)

    The PIC has one other function besides monitoring INT1. It also measures its supply voltage and will shutdown the Itsy if the implied battery voltage drops below TBD. This PIC has an on-board 8-bit ADC using VDD2 as a reference. The ADC input will be an internal FVR(Fixed Voltage Reference) set to 2.048V. If the measured ADC value rises above TBD, then the Itsy will be put into a sleep mode by pulling the En pin low. This should save the battery from imminent damage.

    The Layout:

    It's smaller by quite a bit -- only 1.575" x 1.156" (40mm x 29.5mm). The PIC10F322 is a SOT26 and two pins are unused! The battery and USB connection are at the top -- I'm a bit worried that the right speaker might interfere with the USB connector access. Hopefully that will be solved by clever packaging.

    I'm waiting to see the results of a couple more training sessions before I order new PCBs.

  • Dog Trials (more like...travails)

    Bud Bennett04/16/2019 at 17:34 2 comments

    The days are not sequential. There were days between where nothing happened.

    Day 1:

    I started out by just securing the prototype to Lucy’s head with a long rubber band. She immediately shook it off and it went flying across the room. 

    The next approach was to run two short steel wires from her collar to the back of the unit. She shook it again and it would flop down sideways or backward. It would not remain on her head.

    Another version used a stiff nylon strap from her collar that ran under the prototype. Same problem as above.

    Clearly, I needed some help from from somebody with knowledge and skill in the physical Wife (who can sew).


    Whenever you have more than on person on a project progress slows to a crawl. The Wife’s priorities aren’t the same as mine and she has veto power over the activities upon which I depend. We both agreed that some sort of bonnet would be best. The first attempt was more like a hood than a bonnet. I had no input as to the color. It had two holes for Lucy’s ears, but quite a bit of material on the top, bottom and sides. Lucy had major issues with it when we put it on her without the electronics attached: she shook her head repeatedly, scratched it from the sides with the front paws and then sat down and used her rear paws to really do a job on it. The bonnet stayed put, but looked uncomfortable to me. I thought her issue with that particular bonnet was that it rubbed against her ears and that was annoying.


    I suggested to my Wife that a better approach might be an upside-down jock strap (but not in those terms.) Basically, two ribbons with a connecting piece of cloth to run between Lucy's ears where the electronics could attach. This was produced with a bit of grumbling. The ribbons connected under Lucy’s chin with pieces of mating Velcro. Again, I had no input for the color - Pink! I glued a softer piece of foam pad below the electronics to increase the comfort level.

    Lucy got used to this headdress pretty quickly, first without the attached electronics and later with, but still executed the obligatory shake rattle and roll. All of the abuse took its toll on the electronics. One of the speakers went flying across the room — the speakers have a great big gob of hot-melt glue as reinforcement now. I’m surprised that’s the only thing that broke so far.

    The first time that Lucy wore the complete package with battery and operating electronics was in a bright room. Every time she would shake her head the position of the sensors on her head would change — either sliding slightly backward or moving one half inch to one side. Many times the hair on her ears, or the ear itself, would block the outer sensor and the unit would be inhibited (objects less than 50mm inhibit the system.) 

    There was a five minute interval where everything worked and she followed me around the house. It was bright so she could see fairly well, but when she drifted too close to an object or wall the unit would flash a detection event and I could tell that she noticed the beep from the speaker.

    Later on in the evening when it became darker I put the powered prototype on her again. The same issues with alignment and head shaking persisted, but there was a short period when it seemed to be working correctly. I tried to inform her as to the function of the unit by bringing my hand toward her to activate the speaker and then touching her head from that side. Since it was dark, Lucy was moving much more slowly and appeared to respond to the audible feedback when she got too close to an object or wall....

    Read more »

  • Human Trials Begin

    Bud Bennett04/02/2019 at 00:07 0 comments

    The PCBs and parts have arrived. The near-term objective is to create a working prototype halo that will prove the concept using the Arduino Feather M0 Express along with a simple motherboard for the sensors.

    I removed the VL53L0X sensor ICs from the AliExpress boards and installed them on five daughterboards. This was more difficult than expected. The VL53L0X sensors seem to be sensitive to heat. I melted the first sensor that I removed from the AliExpress board while attempting to solder it to the daughterboard. The most satisfactory method was to heat the AliExpress board from the bottom, with a hot-air gun, until the sensor came loose. Then I turned the sensor over and added solder bumps to the pads with a soldering iron set to 300°C. I spread flux over the pads on the PCB and created solder bumps on those pads as well. I placed the sensor over the PCB pads and heated the PCB from below until the solder bumps melted and the sensor moved to align with the PCB pads. This method prevented the sensor from being damaged by the hot-air gun. The final result looks pretty good (compared to the huge Adafruit sensor board).

    I soldered the five daughterboards onto the prototype motherboard and the code worked! All five sensors were configured and report distances. (I was absolutely amazed that all five sensors were functional.)

    The next step is to attach the piezo speakers, and begin to evaluate the performance using humans (i.e me) as guinea pigs.

    Early Human Trial Feedback:

    Humans are different than dogs. I hooked up an 18650 Li-Ion battery and switch to power the prototype. I also added a pair of $1.00 earphones to be able to hear the audio feedback. The earphone wires are solid core ultra thin, so I had to glob hot-melt glue over the solder joints to provide a minimum amount of strain relief.
    The code needed some extra features to make it useable: the PWM output were generating spurious frequencies when set below about 800Hz — this was confusing, I increased the PWM frequency and added a low pass filter to slow the rate of change of the PWM frequency (noise in the distance measurement) that was causing a warbling of the tone. There were a few minor code changes to simplify and make it easier to make global changes like maximum detection distance and other parameters. It seems to be performing acceptably now.
    When I first tried to use the prototype it was immediately apparent that two sensors either side of the middle/front sensors weren’t making any discernible improvement. The audio mix did not indicate that the nearest object was slightly left or right of the mid point. I changed the code to just use three sensors (middle and two outer) with better results. When you are dependent upon these sensors you tend to sweep the area ahead slightly back-and-forth so having complete coverage is not a big advantage. When I stopped scanning those sensors the update rate improved and made a big difference in the speed of the feedback.
    I quickly found out that the vertical field of view of the sensor was too small to be very effective for tall humans. I kept bumping into things because: a) the response time was too slow with five sensors, b) the maximum sensor distance was set to 500mm which is too short for humans, and c) the sensor was too high off the ground. Things improved with only 3 sensors set to a max distance of 700mm. I’m considering modifying the code to increase the max distance sensitivity of the middle sensor and have the outer sensors have shorter detection distances. This would help when trying to navigate the opening to a room when the two side sensors are both reporting obstructions.

  • Five

    Bud Bennett03/20/2019 at 20:20 0 comments

    The AliExpress sensors arrived yesterday. They were not what I thought I ordered. Chalk it up to operator error. In any case I was able to assemble the sensors and plug them into another protoboard. It's not pretty, but it works.

    The Feather was able to assign new addresses and then extract distance data individually. The sensors came with a bit of Kapton tape affixed to the top. This caused some problems with crosstalk that manifested as a false detection. Once the Kapton was removed the artifacts disappeared. 

    There were a few problems with the code. I learned that the last sensor in the list should be assigned the 0x29 address. Otherwise the sensor will respond when the next sensor in the list is powered up.

    My iMac desktop machine had a lot of problems mounting the CircuitPython drive when all of the sensors were attached. i moved the development boards to my Raspberry Pi desktop (making my wife temporarily happier, since I was hogging the iMac). So far so good with the RPi. Time will tell. 

    Another interesting feature of the VL53L0X sensor is that the reported distance is *much* greater when the object is near the outer edges of the sensor's detection window. You can see this from a test that I performed by moving a white card from the left to right, keeping the distance to the sensors relatively constant.

    distance 0 = 215
    distance 0 = 178
    distance 2 = 420
    distance 0 = 168
    distance 2 = 286
    distance 0 = 158
    distance 2 = 232
    distance 0 = 155
    distance 2 = 227
    distance 0 = 149
    distance 2 = 205
    distance 0 = 149
    distance 2 = 192
    distance 3 = 460
    distance 0 = 150
    distance 2 = 186
    distance 3 = 348
    distance 0 = 141
    distance 2 = 183
    distance 3 = 295
    distance 0 = 146
    distance 2 = 170
    distance 3 = 255
    distance 0 = 140
    distance 2 = 167
    distance 3 = 235
    distance 0 = 143
    distance 2 = 169
    distance 3 = 228
    distance 0 = 136
    distance 2 = 160
    distance 3 = 210
    distance 0 = 144
    distance 2 = 156
    distance 3 = 199
    distance 4 = 402
    distance 0 = 138
    distance 2 = 160
    distance 3 = 203
    distance 4 = 309
    distance 0 = 144
    distance 2 = 158
    distance 3 = 191
    distance 4 = 242
    distance 0 = 148
    distance 2 = 154
    distance 3 = 175
    distance 4 = 205

    Notice that the sensor's first reported detection distance is significantly larger than subsequent distances. I don't think that this will be a problem in this application.

    Here's the latest code. i think it's good enough to use on dog trials. It includes methods to pick the shortest distance reported by the sensors and then apportion the audio amplitude between the left/right speakers to get a sense of location. I admit that I can't determine direction, but I have pretty bad Tinnitus, and the frequencies used by the speakers are right in my dead zone.

    # multiple sensor with PWM speaker outputs
    import time
    import board
    from digitalio import DigitalInOut, Direction
    import busio
    import pulseio
    import adafruit_vl53l0x
    # import adafruit_lis3dh
    # assign pins to VL53L0X shutdown inputs
    shutdown = []
    shutdown.append(DigitalInOut(board.D9)) # middle front
    shutdown.append(DigitalInOut(board.D1)) # inner right
    shutdown.append(DigitalInOut(board.D6)) # inner left
    shutdown.append(DigitalInOut(board.D0)) # outer right
    shutdown.append(DigitalInOut(board.D5)) # outer left
    # assign PWM pins
    piezoL = pulseio.PWMOut(board.D10, frequency=3000, duty_cycle=16000, variable_frequency=True)
    piezoR = pulseio.PWMOut(board.MISO, 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
    #initialize acceleromenter
    #lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=None)
    # setup multiple VL53L0X sensors
    VL53_address =[0x2A, 0x2B, 0x2C, 0x2D, 0x29]
    for n in range(5):
        shutdown[n].value = True # turn on sensor
        print("Address {0} = {1}".format(n, VL53_address[n])) 
    Read more »

  • Feature Creep

    Bud Bennett03/18/2019 at 04:07 0 comments

    I went to the Adafruit website to order another Arduino Feather M0 Express unit to have as a backup. While meandering around their site I stumbled upon a better, smaller, Arduino unit: the Itsy Bitsy M0 Express. The Itsy Bitsy is quite a bit smaller, and almost half the cost of the Feather (so I bought two of them.) It has nearly all of the functionality of the Feather -- even the CircuitPython stuff -- but lacks the battery charging feature. I'm hoping it draws a bit less current too.

    Getting it to Fit:

    The problem with the Itsy is that the power and battery pins are located at one end of the board and the I2C and digital pins are at the other end. This means that the entire board has to be accommodated within or under the halo motherboard.

    The best solution that I could imagine involved placing the Itsy on top of the motherboard with the USB connector accessible from the right side.

    Not all of the pins are needed -- the analog pins and a lot of other pins related to the battery management or ADC reference. Pins at the corners are required to securely mount the board. There are three mounting holes to secure the motherboard -- two of them underneath the Itsy. There are female headers (two 4-pin and one 14-pin) between the boards so that the Itsy can be removed to gain access to the mounting holes. The headers raise the Itsy about 0.5 inch -- slightly higher than the VL53L0X daughterboards. I'm also thinking that male pin headers could be used instead if the two holes under the Itsy were just alignment pins and the one hole outside the Itsy would have a screw. This approach would lower the height of the Itsy considerably.

    Since there is no jack for the battery on the Itsy there are now pads for the battery inputs on the motherboard at the right side. I also added a battery charger (U2 -- MCP73831) to the motherboard. The charge indicator LED is located near the BAT pad. There is not much room to accommodate a disconnect switch for when the battery becomes over discharged -- planning to use a protected cell and hope that it works.

    I let the layout guide the schematic.

    The ItsyBitsy is now included on the mother board schematic.

    Motion Sensing:

    The halo must turn off when Lucy is not moving or if it is tilted to an extreme position indicating that she is sleeping. Therefore I added a simple accelerometer to the system. The LIS3DH should do the job. I wanted to implement a 6-axis motion sensor, but the only one available in CircuitPython is a bit too expensive. This complicates the motherboard assembly since the accelerometer package is a 14-pin QFN. (At least it doesn't have an exposed pad.)

    Too Far Too Fast:

    I think I'm getting way way ahead of myself with this latest design. The AliExpress sensors are stuck in U.S. customs, so I haven't even been able to test the multiple-sensor capability yet. I will probably just sit on this while the rest of the project catches up to it.

  • Getting Physical

    Bud Bennett03/13/2019 at 22:27 3 comments

    While I'm waiting for the delivery of the VL53L0X sensor boards from AliExpress, I thought I'd take a whack at understanding the PCB requirements for a first prototype of the halo. The Arduino Feather M0 Express that I got from Adafruit has been working flawlessly. The current drain of the Feather coupled with a VL53L0X sensor board was about 40mA, <20mA for just the Feather, so I thought it worthwhile to explore using the Feather with some custom sensor PCBs as a simple solution (since I only need to make one of these systems).

    My first attempt was to just place the AliExpress PCBs into a motherboard that attaches to the Arduino Feather that I ordered from Adafruit. It was huge.  The board would be at least 3 inches in width, which might cause Lucy some problems with the fit. I can do better. Therefore, the AliExpress boards will only be used for prototype purposes -- whatever physical arrangement works to prove the concept. I'm planning on using six-pin dupont connectors and gluing the AliExpress boards to a substrate to get the first prototype working. (Or maybe just desoldering the sensors and migrating them to new PCBs.)

    Going My Own Way:

    By abandoning the AliExpress boards I need to make two sets of PCBs: a daughterboard to contain each VL53L0X sensor and any support circuitry, and a motherboard that attaches to the Feather M0 Express.

    After examining the space requirements of a 0.1" header vs. a 0.05" header, I decided to use the smaller headers to save a lot of space. I ordered a slew of 1.27mm pitch right angle male headers from eBay. Each VL53L0X sensor daughter board only needed the sensor and two capacitors:

    I also decided to use the Arduino 3V3 regulated power supply. This saved many resistors, level translator transistors, and a voltage regulator -- for each daughterboard and the motherboard. The VL53L0X data sheet claims that the part will function without issues with a 3.3V power supply. So be it. The preliminary daughterboard dimensions are 0.35" x 0.4". Pretty small, compared to the AliExpress boards (but not cheaper). The daughterboard attaches to the mother board with 6-pin right-angle headers.

    I'm not entirely convinced that all those resistors are necessary. There are placeholders for R8 and C1 -- CYA components. A lot of the pull-up resistors (R1-R5) may be depopulated after the first prototype. After creating the daughterboards I placed them into the motherboard PCB layout to see how big it would be and what challenges popped up. After a few iterations, I settled on the layout below.

    The motherboard plugs into the Arduino using the 6-pin headers spaced 0.8" apart. I also need the Arduino's 3.3V regulated output, which is not available in the first six pins of the header, but Adafruit did provide it as part of a small breadboard area on the Feather M0 Express. Lastly, the two piezo speakers are mounted at the left/right rear of the motherboard -- pretty close to Lucy's ears. (Here's where a couple of resistors in series with the piezo speakers might have been warranted.)

    I tested the assignment of the GPIO with the motherboard header pins -- no issues. Both the daughter boards and mother boards have been ordered. Awaiting delivery of PCBs fro JLCPCB -- check back in one week.

  • Adding Audio Output and Other Stuff

    Bud Bennett03/11/2019 at 22:47 0 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 = []
    # 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
        print("Address = {}".format(VL53_address[n]))
            while not i2c.try_lock():
            result = bytearray(1)
            #set new address
            i2c.writeto(0x29, bytes([0x8A, VL53_address[n]]), stop=False)
            # verity new address
            i2c.writeto(VL53_address[n], bytes([0x8A]))
            print("device address = {}".format(int.from_bytes(result,'big')))
    # instantiate all sensors and initialize distance array
    VL53L0X = []
    distance = []
    for n in range(5):
            VL53L0X.append(adafruit_vl53l0x.VL53L0X(i2c=i2c,address=VL53_address[n], io_timeout_s=0))
    print("distance = {}".format(distance))
    # Optionally adjust the measurement timing budget to change speed and accuracy.
    # See the example here for more details:
    # 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
                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
                piezoL.duty_cycle = 0
            piezoL.duty_cycle = 0
            led.value = False
            piezoL.duty_cycle = 0

    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...

    Read more »

  • CircuitPython Progress

    Bud Bennett02/28/2019 at 21:15 0 comments

    The coding is coming along faster than anticipated. In order to manage the input and output requirements of the sensors and transducers there has to be an understanding of the Arduino's basic I/O capabilities. At a minimum there has to be one I2C interface (2 pins), 5 digital outputs to allow changing of the VL53L0X I2C addresses -- enabling multiple sensors on a single I2C bus, and two PWM digital outputs to generate the audible feedback containing direction and distance.

    I tend to write large pieces of code and then get bogged down trying to comprehend what exactly went wrong. This time I just wrote code snippets to get familiar with CircuitPython and the Arduino hardware platform. I'm not using the Arduino IDE -- it is not compatible with CIrcuitPython.

    The first objective was to just wiggle the correct digital pins, so I wrote and debugged this code snippet:

    import time
    import board
    from digitalio import DigitalInOut, Direction
    # assign pins to VL53L0X shutdown inputs
    shutdown = []
    for n in range(5):
        shutdown[n].direction = Direction.OUTPUT
        shutdown[n].value = False
    while True:
        for n in range(5):
            shutdown[n].value = not shutdown[n].value

    All that this does is wiggle the digital I/O pin on/off every 5 seconds. I was able to put a DVM on the pin and verify that it was behaving correctly. 

    I then got the PWM outputs to function with this code the generates a 10 Hz square wave on D0 and D1:

    import board
    import pulseio
    # assign PWM pins
    oudio_l = pulseio.PWMOut(board.D0, frequency=10, duty_cycle=32768, variable_frequency=True)
    audio_r = pulseio.PWMOut(board.D1, frequency=10, duty_cycle=32768, variable_frequency=True)

    I got errors trying to assign the PWM outputs to D14 and D15. I took the path of least resistance with D0, and D1. I got correct DC and AC values on both pins with the DVM.

    Multiple Sensors

    After this initial success, I attempted to implement a method to assign a different I2C address to each VL53L0X sensor. I only have one VL53L0X at this point but that didn't stop me. 

    This is the algorithm in english:

    1. Assign pins to I/O.
    2. Assert the shutdown pins (active low) on all VL53L0X sensors to disable them from communicating on the I2C bus.
    3. instantiate a generic I2C interface just to assign new addresses to the sensors.
    4. for each sensor:
      1. de-assert its shutdown pin to activate the sensor
      2. send an I2C command over the generic interface to change the I2C address to a unique one.
      3. read back the I2C address of the sensor as a check.
      4. leave the sensor active at this point.
    5. Instantiate the five sensors with unique names and addresses. This will call the calibration procedure and initialize each sensor properly. I commented out all of these instances except the second one in the sequence -- since I have only one sensor.
    6. Run the main loop using the single sensor. This loop blinks an LED when the distance sensor detects an object. The blink rate starts at 0.5 Hz for distant objects increasing to 10Hz or so for near objects.

    Here's the final code that puts all of the above into place.

    # multiple sensor simple sensor 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 = []
    # assign...
    Read more »

  • A Working Sensor

    Bud Bennett02/27/2019 at 19:21 0 comments

    I ordered a VL51L0X sensor breakout board and an Arduino Feather M0 Express from Adafruit. The Feather is attractive to me because of its inherent CircuitPython capabilities. I probably paid the highest prices for these items, but -- considering the support and the initial development of the sensor interface -- it is worth it. Soldering the pins onto the two boards took no time at all. After that I just plugged them into a half proto-board:

    I got into trouble immediately by not being familiar with the Arduino IDE and methodology. I overwrote the existing CircuitPython data with some C code for the VL53L0X. It took me about an hour to get the Arduino to report distance from the sensor. But after that I would have to learn to program in C to go any further. (One of these days I'll learn C.)

    This morning I discovered that there was an existing VL53L0X python library that ran under CircuitPython. I then reinstalled the CircuitPython capabilities and spent an inordinate amount of trial and error time learning to get the simple sensor interface working. I finally got a stream of data out of a terminal program on the iMac.

    Anecdotal Data:

    The beam width is just as small as the data sheet says -- about ±12°. As the distance to the object increases, the size of the object must increase as well. It would not detect my hand at 800mm but would detect a sheet of 8.5x11 white paper. So it seems that five sensors will be a good starting number to get the required beam width.

    Next steps involve learning the sensor command interface, experimenting with time/accuracy tradeoffs, reassigning the sensor's I2C address, and getting familiar with the CircuitPython libraries for GPIO and PWM. I also need perform some experiments with detecting objects of different reflective properties and the sensors resistance to ambient light. Lots of work left.

  • Thinking Out Loud

    Bud Bennett02/19/2019 at 23:30 2 comments


    I've had a couple of days to think about this project. I've also been observing Lucy when she's out and about to determine the best location for the halo. Lucy tends to walk with her head lowered, so it seems the best place to put a smallish electronics package is on her forehead between her eyes and ears. She has about 50mm to work with. This location would not have any obstructions from Lucy's other body parts and could be secured with a simple strap around her head. I think that I'm being overly simplistic here, but my expertise is not with mechanical things. 

    Choosing a Sensor:

    There is a whole universe of distance sensors out there. I've ruled out certain types for size, power consumption, or aesthetic reasons. The favorite so far is ST's VL530X ToF (LIDAR?) distance sensor, for the following reasons:

    1. It's tiny. (4.4x2.4x1.0 mm)
    2. Low power drain: 20mW avg.
    3. Low component count.
    4. Good Range: 5-200cm
    5. More accuracy than needed: < 5mm.
    6. Fast: 33ms acquisition time.
    7. I2C interface. (This is both good and bad...details below.)

    What's not to like:

    1. Narrow field of view: 25°. (Multiple sensors required to cover adequate field of view.)
    2. The data sheet sucks. ST has decided not to include a table of registers addresses for the I2C interface. (Details below.)
    3. Extremely complicated to implement if you're not expert in C or compilers or the jargon of embedded processors.

    Field of view:

    The VL530X has a field of view, per the datasheet, of 25°. This is pretty narrow. I put together a simple diagram to aid in determining the number of sensors required for this application:

    I believe that the minimum number is 5. It's possible that 3 would work, given that Lucy is most likely to collide with something directly in front of her and her head is swiveling to match forward direction. Any comments on this? More sensors mean higher power requirements and shorter battery life (and higher cost -- the sensor is about $6).

    The Interface:

    I like the I2C interface. It's a standard. Some aspects difficult to implement and many components don't comply with all aspects. But the problem here is that ST has not properly documented how to use this sensor. There is not a word about the registers that can be addressed or what they do. ST requires the prospective customer to use their API (written in C) as the only method of communicating with the sensor. This sucks badly.

    I found that Pololu offers a reasonably priced breakout board for this sensor, and also provides a library of commands that work with the Arduino. I've never messed with Arduino, so this is still a bit intimidating. But this is probably the path I'll choose going forward. I've asked a friend who's familiar with Arduino for help.

    Other Features:

    1. Battery and charger. Probably a single cell Li-Ion battery. An 18650 cell contains quite a bit of energy. Charge from USB port.
    2. Power supply: 3.0V switcher. Or LDO with a 3.3V switch mode converter for efficiency.
    3. Accelerometer. To turn off the unit if Lucy is not moving or is laying on her side sleeping. A power saving feature.

    That's all I've got so far. I'm sure a lot of this will change as things progress.

View all 10 project logs

Enjoy this project?



VirtuallyVegan wrote 01/01/2021 at 21:16 point

We are not sure of how to do this ourselves but following along and supporting this endeavor! Question- would this give dogs a sense of depth perception for if they want to start trying to go down stairs, or off of the couch? Did Lucy stop these behaviors due to loss of vision, and do you think this has assisted? Also wondering if would help dogs have an idea of if there is a sudden drop like a curb or flight of stairs. Apologies if you have said this already. So grateful for your work in this field thank you, we agree that existing halos are mostly necessary but bulky and not the most efficient unfortunately.

  Are you sure? yes | no

Bud Bennett wrote 01/09/2021 at 02:55 point

I can't really answer your questions. We live in a house without steps of any kind (nice for her and me.) I have put the project on hold because Lucy seems to manage without assistance now -- her other acute senses (and memorization) have helped to avoid bumping into objects around the house. Occasionally, she does bump into something, but it is rare and doesn't tend to cause any injury. I am not using this device to help her now, but might employ it if things get worse. I am pretty sure that this device would not help her navigate steps/stairs. We must keep her on a short (<2m) leash when she is in unfamiliar surroundings and have trained her to respond to commands of "step up" or "step down" to accommodate those kinds of obstacles.

  Are you sure? yes | no

the_3d6 wrote 04/09/2019 at 21:46 point

Great project! How you are converting distances into sound? It looks interesting to experiment with different frequencies and/or shapes (like sine->overloaded sine->square), and also maybe emit sound only when distance changes?

  Are you sure? yes | no

Bud Bennett wrote 04/10/2019 at 01:11 point

My first attempt is to simply obtain the distance info from the sensor (in mm) and then convert that into a frequency sent to the corresponding speaker. The PWM outputs are obviously square waves, but the speaker's response rolls off at higher Hz. I have added a provision on the next pass for an additional 1-pole (RC) filter to reduce harmonics. The square wave harmonics decrease quickly anyway: X + X^3/3 + x^5/5...

Ideally, the signal fed to the speaker would be a sine wave, but there is only so much that can be accomplished with the existing hardware/software. I'm running out of code space, and the board is already complex. In the past I've relied upon triangle waveforms to reduce the harmonic content with some success.

The distance sensors have quite a bit of uncertainty, This makes it difficult to inhibit the sound output when the variation in distance is small -- it seems to be never small. I added a single-pole IIR digital filter to quiet the warbling due to the measurement variation. I think that is the best i can do for now.

  Are you sure? yes | no

the_3d6 wrote 04/10/2019 at 12:19 point

On the second thought yes, playing with overloaded sine would require quite advanced DAC and for many channels it just isn't reasonable.
But it's still possible to use pulses of the same tone and change repetition frequency - although that might be less intuitive that simple frequency change...

As for distance stability - I have one VL53 collecting dust on a shelf, if I'll get some time and finally write an interface for it - I'll see if I can come up with some filtering to get smooth readings

  Are you sure? yes | no

Bud Bennett wrote 04/10/2019 at 13:15 point

I’ve taken a different route to quiet the sound when things aren’t changing — an accelerometer is used to determine if she is not moving or tilted significantly off axis, then the output is muted. 

  Are you sure? yes | no

Jarrett wrote 04/02/2019 at 05:45 point

Is Lucy a good dog?

  Are you sure? yes | no

Xasin wrote 04/02/2019 at 16:55 point

What kind of question is that?
Just look at her!

I recommend gentle pats after letting her get comfy

  Are you sure? yes | no

Dave wrote 03/27/2019 at 17:08 point

Regardless of anything else, what a sweet dog :D

  Are you sure? yes | no

Bud Bennett wrote 03/28/2019 at 03:01 point

Yes, she is.

  Are you sure? yes | no

jeffgar2000 wrote 03/27/2019 at 16:07 point

I think this should work fine.  I'm an old control systems engineer working DOD right now.  We recently got a collar for our very high strung Brittany pup.  It gives him a buzz when he gets close to his boundary and a pop if he goes through it.  Yes I know, I tried it on myself first and the pop is more startling but doesn't really hurt.  Having said that, as far as I know he has only been popped once.  He learned in a day to only go till he heard the buzz.  I'm always thinking about robotics stuff or biomech stuff and my wife and I (she is an engineer too) discussed that the buzz feed back could be used to help dogs that can't see well.  And then I get my hackaday today and you guys are already doing it!.  Very cool.  The buzz I am speaking of is audible not shock so our pup is responding to the sound of it.  It's possible he is responding to some small vibration of the collar when it buzzes but my old fingers can't feel anything.  I bet Lucy learns the system very fast.  The only thing I see that might be a worry is that the 5 way sensing might overload her at first versus maybe just two slightly offset.  If she adapts to it, your design will be better for her though.  Nice Job!

  Are you sure? yes | no

Bud Bennett wrote 03/28/2019 at 03:00 point

The five-way sensing will hopefully be reduced to just picking out the nearest object and reporting its distance and direction via the speakers. I need five for coverage. I've decided to delay dog trials until after good results with the human trials. I have a hunch that three sensors might be enough if properly placed. Still waiting for parts.

  Are you sure? yes | no

Mike Szczys wrote 03/19/2019 at 01:02 point

I love it that we as individuals have the power to put together things like this. I hope you keep having success as you prototype the system and I really want to see Lucy with a system she feels comfortable using. Great project!

  Are you sure? yes | no

NSFW wrote 02/28/2019 at 04:01 point

This is really cool. I'm looking forward to the next update.

  Are you sure? yes | no

Starhawk wrote 02/20/2019 at 03:40 point

Good on you for doing right by your dog. Godspeed to both of you :)

  Are you sure? yes | no

Dan Maloney wrote 02/16/2019 at 19:18 point

Following with interest. I too know the love of a Border Collie - slightly weird, wonky hips, and possibly a touch deaf. But a sweet boy nonetheless. 

Hope you can find a way to help Lucy.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates