Zoe resurrected

I’ve only just boxed up Zoe having reached her limit, but now the Raspberry Pi Zero W has been released with WiFi and Bluetooth built in, freeing up her one micro-USB socket and thus opening up the possibility of adding GPS tracking to her too.  I’ve just ordered one from The PiHut to try it out.

This isn’t going to affect her maximum camera video size of 480 x 480 pixels, so she’s never going to work as well on gravel like Hermione, but it’s a useful upgrade nonetheless.

Bodes well!

The new PCB arrived, and I’ve done a few indoor tests, and I’ve only seen one I²C error over a total of 60s testing.  Previously, the I²C problem would occur in a fraction of a second.  So my power spike / noise speculation was probably right but needs refining.  Next step is to take Hermione out to build up confidence and to check what video frame resolution she can handle – currently it’s 640 x 640 pixels.  Annoyingly there are gales blowing and forecast to stay for the next few days.

I’ve already been designing the layout for the next PCB revision before this one arrived.  The main change is that the PCB is fed 5V independently from the Raspberry Pi.  Obviously their grounds are connected.  The power comes from a dual port (2.5A each) LiPo Battery Bank – one of these already powers my piPad B3 and RPi touch screen independently and beautifully.

In addition, but unrelated to the PCB power solution, the new PCB design includes a button and LED.  These are for use in the next phase: setting up a series of points in the flight plan based upon GPS targets.

Essentially, prior to a flight, Hermione is set down in several places, and the button pressed; the LED flashes while a sufficient number of GPS satellites have been acquired, at which point the LED goes on for 1 second, the GPS position is saved to file and the LED goes off.  This can be repeated several times to construct a list of GPS positions saved to file as the flight plan.

At the start of a flight, the LED flash / on / off sequence is repeated to acquires enough satellites and record the take-off GPS position; Hermione then climbs to 1m height, and hovers there for a second, yawing to face the first GPS target point saved previously in the flight plan file.  Then she heads there at 1m/s.  Once at the first GPS point, she hovers again, yawing to point towards the second GPS target, and off she goes again, with the sequence repeated for all of the prerecorded GPS targets.  On reaching the final pre-recorded GPS point, once more she hovers for a second while she yaws to face the takeoff GPS point taken at the start of the flight, and back home she goes.  Simples!

End of the line?

Status:

  • Zoe works as best as she can, but she doesn’t have the performance to run the video above 480 x 480 pixels at 20 fps.  This means lateral motion over the IKEA play mat works, but not on the gravel on the drive, never mind the grass.  I have found a micro-USB GPS dongle which I may add but I’ve yet to find a micro-USB hub to allow power, WiFi and GPS to go into the single micro USB port (the other is blocked by the frame)
  • Hermione can process video macro-blocks at 640 x 640 pixels @ 20 fps (and perhaps higher) which may be enough for the gravel drive, but I’m completely out of ideas for the source of the I²C errors from the Garmin LiDAR-Lite V3 when it is connected even if it’s not run.

I’ll continue working on the I²C to the end of the month, but after that I’ll be downing drone development and move on to other things, probably still Pi related nonetheless.

Pure, unbridled fun!

While building Phoebe, Chloe, Zoe and Hermione over the last 4 years has been fascinating, frustrating, intellectually challenging, educational, satisfying, and critically, a brilliant-boredom-blocker, it’s never once been fun.

When I first started this project, there were many DIY quadcopter projects and very few commercial ones, and the commercial ones absolutely needed a skilled human with good hand-eye coordination in the feedback loop.  4 years later, the DIY market is shrinking because the commercial market has caught up and overtaken them; they now support vast amounts of autonomy to protect themselves from less-competent humans like me.

The best ‘affordable’ one currently is the DJI Mavic Pro.  It has 24-core, GPS, several URF  and video sensors for object avoidance and vertical / horizontal tracking, return to home, tracking a target and a stable gimbal for great photos and videos.  It folds up tiny and so portable.  And it costs £1k; I’ve spent many multiples of this on the development of Phoebe, Chloe, Zoe and Hermione.  So I’ve bought one and it arrived today.  After two hours charging, setting up etc, it was dusk, so I only took it out for 5 minutes.  And came back in beaming from ear to ear!

DJI Mavic Pro

DJI Mavic Pro

P.S. Development of Hermione with compass and GPS, and ultimately Scanse Sweep, will continue in the background, but currently, that’s blocked by the fact the I2C errors came back last week, despite there being no code nor hardware changes between the day she worked and the day she didn’t. Blind paralysed sterile stag (still no-fecking eye deer) why 🙁

 

The GPS + compass plan

My intent with GPS and compass it that Hermione flies from an arbitrary take-off location to a predetermined target GPS location, oriented in the direction she’s flying.

Breaking that down into a little more detail.

  • Turn Hermione on and calibrate the compass, and wait for enough GPS satellites to be acquired.
  • Carry her to the destination landing point and capture the GPS coordinated, saving them to file.
  • Move to a random place in the open flying area and kick off the flight.
  • Before take-off, acquire the GPS coordinates of the starting point, and from that and the target coordinates, get the 3D flight direction vector
  • On takeoff, climb to 1m, and while hovering, yaw to point in the direction of the destination target vector using the compass as the only tool to give a N(X), W(Y), Up(Z) orientation vector – some account needs to be taken for magnetic north (compass) vs. true north (GPS)
  • Once done, fly towards the target, always pointing in the way she’s flying (i.e. yaw target is linked to velocity sensor input), current GPS position changing during the flight always realigning the direction target vector to the destination position.
  • On arrival at the target GPS location, she hovers for a second (i.e. braking) and decends.

There’s a lot of detail hidden in the summary above, not least the fact that GPS provides yet another feed for 3D distance and velocity vectors to be fused with the accelerometer / PiCamera / LiDAR, so I’m going to have to go through it step by step

The first is to fly a square again, but with her oriented to the next direction at the hover, and once moving to the next corner, have yaw follow the direction of movement.  Next comes compass calibration, and flight plan based upon magnetic north west and up.

However, someone’s invoked Murphy’s / Sod’s law on me again: Hermione is seeing the I2C errors again despite no hardware or software changes in this area.  Zoe is behaving better, and I’m trying to double the motion tracking by doubling the video frame rate / sampling rate for the Garmin LiDAR-Lite; the rate change is working for both, but the LiDAR readings see to be duff, reading 60cm when the flight height is less than 10cm.  Grr 🙁

Hermione’s proof of the pudding

Here finally is her flying in a stable hover for a long time without rocketing off into space.  Yes, she’s wobbly, but that’s a simple pitch / roll rotation rate PID tune much like I had to do with Zoe.  She’s running the video at 560 x 560 pixels at 10 fps, hence no need for the IKEA play mat.

Finally I can move on to adding the compass and GPS into the mix.

Hermione’s progress

I’ve upgraded Hermione to a B2, and installed the very latest level of the Raspian Lite OS from scratch, and her electronics is now driven from a 2.4A battery bank.  She’s running the video at 560 x 560 pixels at 10 fps with the B2 overclocked to 1GHz, and has 1GB memory.  With these changes, she’s working without error, at least in passive mode: she didn’t do this with the A+ and lower current power supply.

Hermione refit

Hermione refit

I’ve tidied up the WiFi wiring by hacking open an antenna base station, removing the magnet (so it doesn’t mess up the nearby compass), and replacing the wiring with a shorter version RP-SMA connector which is now routed through the frame thus keeping it nicely tucked away.

I’ve just bought a USB GPS module; it’s currently being tested, but soon, it’ll be on the same arm as the WiFi, with the WiFi antenna attached to the underside pointing down, and the GPS on top.  Ultimately, I’ll do the same with the GPS as I’ve done with the WiFi: strip the cable down to exactly the right length.

To use the GPS, I’ve installed the python gps package:

sudo apt-get install python-gps

This starts a GPS daemon, by default on /dev/ttyAMA01; this needs changing in /etc/default/gpsd to /dev/ttyUSB0.

Here’s the code – it’s almost a direct copy of an adafruit sample:

from __future__ import division
import gps
import os
import math

# Listen on port 2947 (gpsd) of localhost
session = gps.gps()
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

num_sats = 0
latitude = 0.0
longitude = 0.0
time = ""
epx = 0.0
epy = 0.0
epv = 0.0
ept = 0.0
eps = 0.0
climb = 0.0
altitude = 0.0
speed = 0.0
direction = 0.0

lat = 0.0
lon = 0.0
new_lat = False
new_lon = False
base_lon = 0.0
base_lat = 0.0

dx = 0.0
dy = 0.0

R = 6371000 # radius of the earth in meters

fp_name = "gpstrack.csv"
header = "time, latitude, longitude, satellites, climb, altitude, speed, direction, dx, dy, epx, epy"

os.system("clear")

print header

with open(fp_name, "wb") as fp:
    fp.write(header + "\n")

    #---------------------------------------------------------------------------------
    # With a based level longitude and latitude in degrees, we can be the current X and Y coordinates
    # relative to the takeoff position thus:
    # psi = latitude => p below
    # lambda = longitude => l below
    # Using equirectangular approximation:
    #
    # x = (l2 - l1) * cos ((p1 + p2) / 2)
    # y = (p2 - p1)
    # d = R * (x*x + y*y) ^ 0.5
    #
    # More at http://www.movable-type.co.uk/scripts/latlong.html
    #---------------------------------------------------------------------------------

    while True:
        try:
            report = session.next()
#            print report
#            os.system("clear")
            if report['class'] == 'TPV':
                if hasattr(report, 'time'):  # Time
                    time = report.time

                if hasattr(report, 'ept'):   # Estimated timestamp error - seconds
                    ept = report.ept

                if hasattr(report, 'lon'):   # Longitude in degrees
                    longitude = report.lon
                    new_lon = True

                if hasattr(report, 'epx'):   # Estimated longitude error - meters
                    epx = report.epx

                if hasattr(report, 'lat'):   # Latitude in degrees
                    latitude = report.lat
                    new_lat = True

                if hasattr(report, 'epy'):   # Estimated latitude error - meters
                    epy = report.epy

                if hasattr(report, 'alt'):   # Altitude - meters
                    altitude = report.alt
                if hasattr(report, 'epv'):   # Estimated altitude error - meters
                    epv = report.epv

                if hasattr(report, 'track'): # Direction - degrees from true north
                    direction = report.track
                if hasattr(report, 'epd'):   # Estimated direction error - degrees
                    epd = report.epd

                if hasattr(report, 'climb'): # Climb velocity - meters per second
                    climb = report.climb
                if hasattr(report, 'epc'):   # Estimated climb error - meters per seconds
                    epc = report.epc

                if hasattr(report, 'speed'): # Speed over ground - meters per second
                    speed = report.speed
                if hasattr(report, 'eps'):   # Estimated speed error - meters per second
                    eps = report.eps


            if report['class'] == 'SKY':
                if hasattr(report, 'satellites'):
                    num_sats = 0
                    for satellite in report.satellites:
                        if hasattr(satellite, 'used') and satellite.used:
                            num_sats += 1

            #-----------------------------------------------------------------------------
            # Calculate the X,Y coordinates in meters
            #-----------------------------------------------------------------------------
            if new_lon and new_lat:

                new_lon = False
                new_lat = False

                lat = latitude * math.pi / 180
                lon = longitude * math.pi / 180

                if base_lat == 0.0 and base_lon == 0.0:
                    base_lat = lat
                    base_lon = lon
                    continue

                dx = (lon - base_lon) * math.cos((lat + base_lat) / 2) * R
                dy = (lat - base_lat) * R

            else:
                continue


            output = "%s, %f, %f, %d, %f, %f, %f, %f, %f, %f, %f, %f" % (time,
                                                                 latitude,
                                                                 longitude,
                                                                 num_sats,
                                                                 climb,
                                                                 altitude,
                                                                 speed,
                                                                 direction,
                                                                 dx,
                                                                 dy,
                                                                 epx,
                                                                 epy)




            print output
            fp.write(output + "\n")
        except KeyError:
            pass
        except KeyboardInterrupt:
            quit()
        except StopIteration:
            session = None
            print "GPSD has terminated"

She cannae take any more, Captain!

Zoe is now maxed out;  any increased video frame size above the current 400 x 400 pixels at 10 fps leads to a IMU FIFO overflow i.e. the video processing simply takes too long.  She’s also run out of physical space on her frame for more sensors.

On the other hand, Hermione has loads of physical space, but is plagued with I2C problems on her A+.

To add GPS for flight plans, and Scanse Sweep for object avoidance, I need more cores.  For the moment that means a B2 or B3.  Currently I’m leaning towards a B2 as I don’t need the 64 bit kernel of the B3, nor the built in WiFi or Bluetooth – I’d rather continue to use a faster WiFi USB dongle.  With the extra cores, I can move the video processing out of the motion processing into a different process, and have it feed the latest values to the motion processing when available.  Hopefully that will mean support for higher video frame size and rate and perhaps also increase the IMU sampling rate back to the 1kHz – I’ve had to reduce it to 500Hz currently.  Having the extra cores and 4 USB ports means GPS and Scanse Sweep should be much easier to add – I doubt the A3 (if it ever appears) will support those extra USB ports.

So it’s a B2.  For the sake of up to date build instructions, I’ll be installing her from scratch and blogging the instructions once complete.

 

Hermione’s progress

Here’s Hermione with her new PCB.  It’s passed the passive tests; next step is to make sure each of the 8 motor ESCs are connected the right way to the respective PWM output on the PCB, and finally, I’ll do a quick flight with only the MPU-9250 as the sensors to tune the X8 PID gains.  Then she’s getting shelved.

Hermione's progress

Hermione’s progress

Zoe’s getting a new PCB so I can run the camera and Garmin LiDAR-Lite V3 on her too.  Hermione is huge compared to Zoe, and with the winter weather setting in, I’m going to need a system that’s small enough to test indoors.

Hermione will still be built – I need her extra size to incorporate the Scance Sweep and GPS, but I suspect only when an A3 arrives on the market – Hermione’s processing with a new 512MB A+ overclocked to 1GHz is nearly maxed out with the camera and diagnostics.  She’s probably just about got CPU space for the compass and Garmin LiDAR lite over I2C but I think that’s it until the A3 comes to market.  My hope for the A3 is that it uses the same 4 core CPU as the B2 with built in Bluetooth and WiFi as per the B3 but no USB / ethernet hub to save power.  Fingers crossed.

 

Say ‘Hi!’ to Hermione*

Hermione will be the mother of all that’s gone; she’s a bit heartless at the moment – her HoG will be an RPi A3 when it appears on the market.

Hermione flat-out (with banana for scale)

Hermione flat-out (with banana for scale)

Hermione flat-out (with banana for scale)

Hermione tip-toes (with banana for scale)

The main reason behind building yet another quadcopter is the frame:

  • loads more space for extra sensors
  • folding arms so it’s easily transportable
  • beautiful build – lots of CF and CNC machining
  • lots of extension platforms adding lots of options of where to put all the pieces – installed here are a power distribution board (in the plate sandwich), a plate for her HoG, and a GPS plate sticking out to the left.

The one thing that’s missing are legs – I’ve had the ones supplied before, and they crack and break with the down-falls my testing produces.  There are stronger ones I’ll be getting.  I’ve bought from quadframe.com previously for Chloe so I know the high quality of their frames; the previous frame I’d bought was premature, and sadly I ended up selling it.

But this time, I have a purpose for all the extra space: Hermione will be deployed with GPS, LiDAR x 2, PX4FLOW, a RPi Camera and anything else I can get onto her.  Also the frame supports an X8 layout as well as standard quad format; X8 is where each arm has 2 motors and props: the top motor prop is set up as normal; the lower one is upside down, and the prop is installed on the motor upside down.  The topside and underside props spin in opposite directions.  This format provides more power for heavy lifts and protection against motor / prop damage or failure.  Each prop has its own ESC and separate PWM feed.

Doing the above requires the A3 for its extra cores to do a lot more sensor processing and a new PCB to support the new GPIO pin requirements.

GPS, LiDAR and LEDDAR require UART connections; X8 requires another 4 GPIO pins for the 4 ESCs PWM feed.  One of the sensors – probably GPS – can use the USB port, assuming the A3 has built-in WiFi like the B3.  PXFLOW uses I2C.

My thinking is that LEDDAR and PXFLOW provide term fused inputs to the distance PIDs; GPS provides targets for the flight plan; compass is the yaw input with the the flight plan providing direction of travel so that a camera pointing forwards can always track her progress; Scance Sweep provides object detection overriding the GPS flight path short term to avoid objects.

Together, this means I could set a start and end position for a flight using GPS (either just start and finish or with intermediate check points), and then just set her loose autonomously to track against those points, whether this is simply flying from A to B or getting from the entrance to the centre of a maze, logging “where I’ve been” to ensure she always prioritises new paths through the maze.

Here’s the current PCB eagle layout for Phoebe and Chloe:

A+ PCB

A+ PCB

  • the right hand side 3 vertical PCB tracks are for the LiPo to 5V regulator – I’m planning on Hermione having a BEC on her PDB (power distribution board), so that opens up space for the rear X8 PWM pins.
  • the left hand side 4 vertical PCB track are I2C extensions in place for the URF, but the space is needed for the the front X8 PWM pins so the I2C extension is moved to the bottom edge and will be used for the PIX4FLOW.

Here’s the first draft of the revised PCB:

Hermione PCB beta

Hermione PCB beta

PIN usage:

  • pins 4, 6, 8, 10 and 12 are used for LEDDAR as now but extended outwards
  • the GPIO pins for PWM are completely reworked for X8 format as is the MPU9250 interrupt pin; I’ll probably end up adding X8 before I add Scanse Sweep simply to fill the gap between now and its delivery
  • I2C is extended on the lowerside for the PX4FLOW
  • That leaves a selection of pins and space on the topside for Scanse Sweep – I need to get wiring specs for this; and alternative is via USB using a UART to USB converter – I have one of these already for use configurating LEDDAR by my Windows PC.
  • GPS will also be via USB, assuming the WiFi is now build into the A3 board or I might use a mini USB hub like on of these that I used already for other projects.

Regarding WiFi, to extend the range, I’m going to replace the (hopefully) on board antenna with a HiRose U.FL connector, as per here.  That will then allow me to connect to a U.FL to RP-SMA cable, and place a higher gain antenna on the board.

I’ve still  left a few breadboard pins at the base as they may turn out to be useful for LEDs, buzzers etc.

As you can see, there’s a lot that needs to be done, but it breaks down into lots of separate blocks to keep me busy until the A3 and Scanse Sweep arrive.  The first step is simple: move Chloe’s HoG over to Hermione’s frame, and get her stable.


*Penelope (as in “Pitstop”) was a close runner up, but with my existing HoGWARTs WAP installation notes, Hermione (as in “Granger”) won the ballot outright.