LEDDAR testing results

I’ve got the LEDDAR One prototype working well using the minimalmodbus python library and fantastic customer support from LEDDAR themselves.

I’ve had to put in a nasty hack to kill off the Raspberry Pi console tied to the UART pins; for some reason I couldn’t stop it across reboot.

The pin layout is nice and tidy: RPi pins 4,6,8,10,12 (5v, GND, TX, RX, GPIO 18) connect to Leddar Pins 3,1,4,5,2 respectively – that’s a convenient 5 consecutive pins on RPi side to attach a standard connector.  Unfortunately I do need to run another batch of PCBs as there’s no access to these pins on my current PCB.

Once the PCBs are done, I’ll be adding the LEDDAR to Phoebe; her motion processing happens at ≈100Hz; the default for LEDDAR is 8.8Hz (it can be increased if necessary).  Each LEDDAR distance measurement also comes with an accurate timestamp.  This means I can differentiate the LEDDAR readings to produce a Z-axis velocity which can then be fused with the integrated accelerometer readings to provide long term vertical stability.  A simple complementary filter (like the one I already have for angles) will do the job nicely.

The LEDDAR also provides a data ready interrupt which I’ve connected to GPIO 18.  This means I don’t have to poll the serial port every motion loop; instead I can use the GPIO edge detection code (like the one used for FIFO overflow on the IMU) to let the motion code know when there’s new data on the serial port.

Together, this means adding the new function to the HoG code is trivial – I’ve done all the tricky bits before in different contexts.  The only gating factor is the new PCB requirement, and (as always) my overdraft limit!

My one warning if you are in the UK and interested in using LEDDAR: its price is very reasonable given the technology and its support is excellent; sadly the UK import duties and UPS fees added another 40% to the costs!  Ouch!  My advice is to get a friend in Canada to buy it, and send it to you by normal international post!

Here’s the code in case you’re interested:

#!/usr/bin/env python

from __future__ import division
import serial
import minimalmodbus
import os
import time
import RPi.GPIO as GPIO

def main():
    minimalmodbus.BAUDRATE=115200
    mmb = minimalmodbus.Instrument("/dev/ttyAMA0", 1, 'rtu')
    mmb.BAUDRATE=115200

    temp = mmb.read_register(22, 0, 4, True)
    print "temp: %f" % (temp / 256)

    time.sleep(0.1) # ARBITRARY SLEEP REQUIRED WHY?

    num_detections = mmb.read_register(23, 0, 4)
    print "num_detections: %d" % num_detections

    time_lss = mmb.read_register(20, 0, 4)
    time_mss = mmb.read_register(21, 0, 4)
    start_time = (time_mss << 16) + time_lss
 
    #----------------------------------------------------------------------------------
    # Create GPIO 18 as input, pull down
    #----------------------------------------------------------------------------------
    GPIO_INT = 18
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(GPIO_INT, GPIO.IN, GPIO.PUD_UP)

    #----------------------------------------------------------------------------------
    # Clear the already existing interrupt by reading data from the modbus link
    #----------------------------------------------------------------------------------
    dist_leddar = mmb.read_register(24, 0, 4)

    for ii in range(10):

        #------------------------------------------------------------------------------
        # Add GPIO pin 18 rising edge interrupt and then get new data
        #------------------------------------------------------------------------------
        GPIO.wait_for_edge(GPIO_INT, GPIO.RISING)

        time_lss = mmb.read_register(20, 0, 4)
        time_mss = mmb.read_register(21, 0, 4)
        current_time = (time_mss << 16) + time_lss

        dist_leddar = mmb.read_register(24, 0, 4)

        print "Proximity @ %f: LEDDAR %f;" % ((current_time - start_time) / 1000, dist_leddar / 1000)

if __name__ == "__main__":
    os.system("systemctl stop serial-getty@ttyAMA0.service")
    main()

P.S. As expected above, I’ve pretty much coded the LEDDAR into Phoebe’s HoG in about half an hour. There is also a way to bodge the current PCB to get the LEDDAR wires connected to the 5V, TX, RX, GND and interrupt pins, so I could be installing the LEDDAR soon and start testing. I’ll let you know when the job’s done.

P.P.S. If you want to buy a LEDDAR One, it’s in stock at robotshop.

Fed up of Phoebe

I’m giving up on Phoebe and adding new sensors using the IMU FIFO code.  The final nail in the coffin was I spotted I2C errors while I was trying to diagnose the squid problems.  I2C errors rule out using the IMU FIFO as the code then gets out of sync with what data it’s getting from the FIFO.  That means Phoebe has to switch back to using the data ready interrupt code, which in turn means she can’t periodically do something else like read other sensors because she can’t afford to miss the next interrupt and hence the next batch of data.

I’ve never been able to find the source of these I2C errors but I guess it’s the PCB, and I’m not going to get a revised version designed any time soon based on speculation alone.

Zoe on the other hand is still working perfectly – no I2C errors with identical code perhaps because she’s the daughter of Johnny Ball, a science presenter from my era, who also has cartoon appearances on the Raspberry Pi site.  But more likely is that she’s a Zero not an A+ and running a different PCB design as result (both mine and A+/Zero).  Unfortunately Zoe would need a new PCB to add the URF for vertical motion tracking, and she could never have a camera for the horizontal motion tracking – PiZero’s don’t have the camera socket.  So Zoe’s is essentially finished other than fine tuning.

So this project is grinding to a terminal halt for the moment until either an A2 appears on the market allowing me to split the DRI code from the motion processing and connect them with an OS FIFO, or I get a new PCB done for an A+ where there’s no guarantee this will fix anything.

Running to stand still…

Just as my python code was nearly complete, GPIO interrupt support has been added. To me this is fantastic as I loathed the fact my drone remote control and the drone itself we’re having to periodically (every 0.1 seconds) check its inputs to update itself. Now I’ll be able to

  • add the joystick interrupts on the RC, for both the switches and the joystick movements, so the remote control can just sleep pending an interrupt. It’s not actually quite that simple as in fact, the remote control periodically sends a KEEPALIVE message to the drone so the drone knows it’s still in contact with the RC. If it finds it’s not, it switches to auto-landing mode, but it does at least reduce the work when there is no change on the joysticks.
  • add accelerometer interrupts to the drone itself, so if it’s running smoothly, there’s no need for it to poll the accelerometer; it can just sleep on select() waiting for the next RC commands.
  • Together this means lower battery usage on both, and faster reaction to critical events. A double plus!

    The only downside is the rewrite of the code scheduling and resultant testing. I think for the mo, I’ll add this to my todo list and concentrate on getting the drone airborne and stable first.