No-fly drones

Zoe

Zoe is going to the Cotswold Jam next Saturday, and then is definitely being retired.  Her Pi0W is just not fast enough to process 680 x 680 pixel ground facing video frames required to fly on gravel / grass.  On the plus side, she’s going to be asset stripped for bigger things.

Hermione

Hermione broke her arm a while back, and the replacement has just been installed, but the weather is still too blustery.  She broke her arm in a free-fall landing; one of her CF legs took the bulk of the force, but punched a hole in her CF armpit.  As a result, in addition to the new arm, I’ve also got a new pelvis from quadframe.com for her legs which is thinner, lighter and prevents the legs from damaging the arms.  Also, because they are thinner, there’s space for larger props; When the need arises, I may well upgrade from the current T-motor 1240 CF props with the larger T-motor 1344s which are still within scope of her T-motor U3 motors.

Chloe

Chloe is back, and is Zoe’s asset stripper, primarily her Garmin LiDAR-Lite V3.  C’s only using an A+ and I don’t expect her to be any better than Zoe as a result; however, very speculatively, the only missing gap in the RPi clan is an A3.  That’s what she’s waiting for.  She’s build only from left-overs / spares / shelved pieces except for her new CF arms, again from quadframe.com – isn’t she pretty?

Chloe reborn

Chloe reborn

A3 speculation

Here’s my best guess / hope of an A3 spec, based realistically on the middle ground between a B3 and Pi0W:

  • single USB A port as per A+ to avoid power drain of ethernet / USB port chipset
  • built in WiFi as per B3* and Pi0W, freeing up the USB port for GPS
  • 4 core processor – ideally, the B2 version rather than B3, again for power consumption reasons.

No-fly Zones

The few times I’ve flown my Mavic, it’s always warned me I live in a class C ICAO airspace designation zone.  It doesn’t surprise me really with RAFs Fairford, Brize Norton, and Royal Wooten Basset all within easy cycling distance.  The Fairford Royal International Air Tattoo normally has squadrons of classic Spitfires, Hurricanes and Lancaster Bombers plus the Red Arrows flying over our back garden on my daughter’s Birthday weekend.  A couple of years back, Air Force One flew within a stone’s throw / spitting distance of our house.  I’m sure I saw ex-POTUS Barack Obama through the window eating his breakfast!  Should the POTUS Trump ever fly by, I’ll be sure to test the metaphorical distance literally.


* Ideally, the new A3 should also include a U.FL connector for a WiFi antenna allowing extended range, ideally switched between the inbuilt and external based upon the presence of an external antenna.  Worst case, I’ll add this myself.

piNet

At some point in the not too distant future, I’m going to need a much longer range WiFi connectivity between my piPAD and piDrones so that I can test the GPS tracking in the local field where the piDrone and piPad may be separated beyond the range of the current direct WiFi signal.  This is a problem because I need connectivity even though the piDrones are autonomous as I always need to be able to press the remote kill switch.

I considered for a second or two hunting down a longer range radio system, but then wondered whether this is doable by using multiple Zero-W’s instead: the concept of piNet was born.

The idea is that these Zero-W’s are all in their own private network (piNet) using their inbuilt WiFi.  The Zero-Ws are phone charger battery-bank powered, and are scattered  around the test field.  Each Zero-W also has a USB WiFi dongle configured to connect to the piDrone WAP network.  The piNet and iDrone networks are bridged together.  My piPad is also in the piDrone and piNet networks.  That means I should be able to access the piDrone network via piNet even if the piDrone is outside of the range of the piPad WiFi: I should be able to remote login to the iDrone from my piPad via piNet.

This feels like it could work with the piDrone clients bridged to the piNet, but there’s lots of details I have no idea about.  More thinking to do.

Stats analysis

From the same run as the last two posts, I’ve been analysing the stats.

First the integrated gyro showing the yaw it detected:

yaw

yaw

This shows the unintentional clockwise (negative) yaw of about -10° shortly after take-off followed by the intentional anticlockwise yaw of +90° as Hermione headed off left.  I still need to have a play with the yaw rate PID to try to kill that initial -10° yaw.

More interesting, to me at least, is the motion processing:

FIFO stats

FIFO stats

The graph shows how often the FIFO was emptied.  In an unhindered world, the FIFO is emptied every 10ms (0.01s) and the PWM to the ESCs update.  Peaks above that means something else was taking up the spare time.  The FIFO overflows at just above 84ms (512 bytes total FIFO size / 12 bytes per IMU sample / 500Hz IMU sampling rate =  85.333ms), and the highest shown here is 38ms, well within safety limits.  I’m particularly delighted that the majority of the spikes are within the 10 to 20ms range – that strongly suggests the split phases of macro-block processing is working like a dream.

The 20ms norm means the PWM is updated at 50Hz.  Were the PWM consistently updated at less than 50Hz, it would really start to show in the stability of the flight.  But luckily it isn’t, meaning there’s probably just enough room to finally squeeze in compass and GPS processing.

In passing, it’s worth saying that such levels of stats would be impossible if I was using a microcontroller (Arduino etc) – this 11s flight logged 1.46MB of data to shared memory, and ultimately to SD card.  It logs both initial hard coded constants, and every dynamic variable for every cycle of motion processing – that means nothing is missing and it’s possible to diagnose any problem as long as the reader knows the code intimately.  Without these logs, it would have made it nigh on impossible for the ignorant me 4+ years ago to achieve what I have now.


* I rate myself as experienced having spent over 4 years on this.

Chicken poo tracking

If you look at yesterday’s video full screen, from top left to right, you can see a muddy patch and two chicken poos, the second poo of which is close to Hermione’s front left prop on take-off.  I was back out in the dark last night, tracking them down.  Here’s why:

Lateral tracking

Lateral tracking

Although the graph of camera lateral tracking and the Mavic video are almost facsimiles in direction, the scale is out; the graph shows the distance from take-off to landing to be about 1.7m whereas a tape measure from chicken poo #2 to the cotoneaster shrubbery landing point measures about 4.2m.  Given how accurate the direction is, I don’t think there’s any improvement needed for the macro-block processing – simply a scale factor change of ≈ 2.5.  I wish I knew more about the video compression method for generating macro-blocks to understand what this 2.5 represents – I don’t like the idea of adding an arbitrary scale of 2.5.

One further point from yesterday’s video, you can see she yaws clockwise by a few degrees on takeoff – Hermione’s always done this, and I think the problem is with her yaw rate PID needing more P and less I gain.  Something else for me to try next.


I had tried Zoe first as she’s more indestructible. However, her Pi0W can only cope with 400 x 400 pixels video, whereas Hermione’s Pi B 2+ can cope with 680 x 680 pixel videos  (and perhaps higher with the 5 phase motion processing) which seem to work well with the chicken trashed lawn.

That’s better…

not perfect, but dramatically better.  The flight plan was:

  • take off to 1m
  • move left over 6s at 0.25m/s while simultaneously rotating ACW 90° to point in the direction of travel
  • land.

I’d spent yesterday’s wet weather rewriting the macro-block processing code, breaking it up into 5 phases:

  1. Upload the macro block vectors into a list
  2. For each macro-block vector in the list, undo yaw that had happened between this frame and the previous one
  3. Fill up a dictionary indexed with the un-yawed macro-block vectors
  4. Scan the directory, identifying clusters of vectors and assigned scores, building a list of highest scoring vector clusters
  5. Average the few, highest scoring clusters, redo the yaw of the result from step 2, and return the resultant vector

Although this is quite a lot more processing, splitting it into five phases compared to yesterday’s code’s two means that between each phase, the IMU FIFO can be checked, and processed if it’s filling up thus avoiding a FIFO overflow.

Two remaining more subtle problems remain:

  1. She should have stayed in frame
  2. She didn’t quite rotate the 90° to head left.

Nonetheless, I once more have a beaming success smile.

Weird yaw behaviour

I’ve implemented the yaw code such that Hermione points in the direction that she should be travelling based upon the flight plan velocity vector.  She should take-off, then move left at 0.25 m/s for 6 seconds, while also rotating anti-clockwise by 90° to face the way she’s supposed to be travelling.  However, here’s what my Mavic & I saw:

My best guess is the camera lateral tracking which simply looks for peaks in macro-block after stashing them all in a dictionary indexed by the vectors.  This ignores yaw, which was fine up to now, as I’d set the yaw target to zero.  I think I need to add an extra stage which un-yaws each macro-block vector before adding them to the dictionary and looking for peaks.  That’s relatively easy code, involving tracking yaw between video frame, but costly as it adds an extra phase to unraw each MB vector, before dictionarying them and checking for peaks.  Time will tell.

yaw control.

Currently, yaw angle PID target stays set at zero throughout the flight; the piDrone always faces the same direction regardless of the way it’s travelling.  Next step on the way to ultimately tracking between GPS points is to have her point in the direction she’s travelling; it’s not actually necessary for my girls; the Mavic Pro does it as the forward facing camera video is streamed back to it’s remote control so I get an FPV (first-person view – i.e. as though I was a pilot sitting on it).

My intention is that the yaw angle tracks the earth frame flight plan velocity vector, so the piDrone points the way it _should_ be going.  This is roughly what the Mavic does.

I though it would be trivial, and added the one new line of code, and then I realised the gotchas which led to me blogging the details.  There are 3 problems.

  • Conversion of the lateral velocity vector to an angle.  tangent only covers ±90°; this means the 1/1 and -1/-1 vectors both come out as 45° angles.  Also 1/0 would throw a exception rather than 90°.  Luckily math.atan2(x, y) resolves this spitting out angles of ±180°.  Thats my yaw angle PID target resolved.
  • Alignment of the integrated gyro input in the same scale as above.  If the piDrone flies 2.25 clockwise loops around the circle, the integrated gyro will read 810° when it needs to read 90° – doing yaw = yaw % 180° should sort this out.  That’s the yaw angle PID input sorted
  • Finally if the yaw PID input is 179° and the yaw PID target is -179°, the PID (target – input) needs to come out at +2° not -358° i.e. the angle must always be <= |180°|.  I’ve sorted this out in the code by adding a custom subclass overriding the default error = (target – input):
    ####################################################################################################
    #
    # PID algorithm subclass to cope with the yaw angles error calculations.
    #
    ####################################################################################################
    class YAW_PID(PID):
    
        def Error(self, input, target):
            #-------------------------------------------------------------------------------------------
            # An example in degrees is the best way to explain this.  If the target is -179 degrees 
            # and the input is +179 degrees, the standard PID output would be -358 degrees leading to 
            # a very high yaw rotation rate to correct the -358 degrees error.  However, +2 degrees
            # achieves the same result, with a much lower rotation rate to fix the error.
            #-------------------------------------------------------------------------------------------
            error = target - input
            return (error if abs(error) < math.pi else (error - 2 * math.pi * error / abs(error)))
    

Now I just need the spring wind and torrential rain showers to ease up for an hour.

Precise, concise installation instructions

I ended up doing a complete reinstall from scratch to upgrade Zoe to my new Pi-Zero-W, so here’s my latest set of installation instructions.  I recommend printing these off so you can refer to them easily as you do the installation.

These work for any version of Raspberry Pi running the latest Raspian Jessie Lite.

I can confirm that the Pi-Zero-W inbuilt WiFi does support WAP / soft-AP.

Annoyingly, I messed up soldering the GPIO connection onto the Pi-Zero-W, so I have another one on the way.

Crash back down to earth.

Normality has returned.  I took Hermione out to test what video resolution she could process.  It turns out 640 x 640 pixels (40 x 40 macro-blocks) was yesterday’s video frame size.  800 x 800 pixels (50 x 50 macro-blocks) this morning was a lot less stable, and I think the 960 x 960 pixels (60 x 60 macro-blocks) explains why.

At 960 x 960, Hermione leapt up into the sky; the height breach protection killed the props at 1.5m but by then she was accelerating so hard she probably climbed to 3m before dropping back down like a brick onto the hard stone drive upside-down.  Luckily only 2 props got trashed as that’s an exact match for the spares I had left.

Rocketing into the sky appears to be Hermione’s symptom of a IMU FIFO overflow.  For some reason, Hermione doesn’t catch the FIFO overflow interrupt so she just carries on, but now with gravity reading much less than zero because the FIFO has shifted so in fact she’s reading gyro readings, and so had to accelerate hard to compromise.  The shift happens because the FIFO is 512 bytes and I’m filling it with 12 byte batches; 512 % 12 != 0.

How does this explain the 800 x 800 wobbles?  My best guess is that these 2500 macro-blocks (800² / 16²) are processed just fast enough to avoid the FIFO overflow shown by 900², but does have a big impact on the scheduling such than instead of the desired 100Hz updates to the motors, it’s a lot nearer the limit of 23Hz imposed by the code.  That means less frequent, larger changes.

So that mean I need to find the balance between video frame size and IMU sampling rate filling the FIFO to get the best of both.  Luckily with indestructible Zoe imminently back in the running, I can test with her instead.

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.