Friday, August 29, 2014

Sparky 2.0 and TauLink

I love Sparky. It's not too surprising, since I designed it to be everything I want in a flight controller. Simple, easy to solder, small, extremely capable, reasonably expandable.

I also really like Freedom, the more powerful cousin. The overo allows logging all the data, which has been hugely powerful. It has more connectivity which is great for having an external mag, spektrum, gps and OSD. The integrated radio is very convenient for connecting to Android. The obvious thing to do was try and fuse them together and get the best of both worlds.

My main goal with this project is something that is really easy and effective for doing POI tracking, follow me, as well as still just flying really well and being great for navigation.

I present:

Sparky 2.0 

(better name coming - Firecracker?)





Features

  • Runs Tau Labs (of course ;-). Same great flight performance you've come to expect and standard features.
  • Open source hardware! (also of course) 
  • More powerful processor. Uses an STM32F4 running at 168 Mhz with increased memory and flash. This is useful for storing and flying longer waypoint sequences and running more complicated code like picoC scripting.
  • More connectivity. (RCVR, Flexi, Main, I2C Aux). This is really useful if you want to have an external mag, gps, and spektrum receiver or other things like OSD.
  • Flash chip which can be used to store flight plans, picoC code, or logging
  • RFM22b radio can be used for telemetry or with openlrng (not implemented yet). The receiver antenna uses the same U.Fl. connector that Freedom has. I really like this because it is very small and you can easily an SMA break out cable or a whip antenna. It also has just the right amount of tension - strong enough to hold together in flight but in a crash it will disconnect and not damage the board. There is a small hole at the front to provide strain release for a whip antenna that you can just pass through and solder straight to the RFM22b for minimal configurations.
  • Four buffered outputs to drive either LEDs (indicate flight status) or brushed motors. I'm really excited to have different colored LED strips turn on to indicate the direction it is facing relative to home.
  • DAC output for VTX audio telemetry. I'd like to be able to some prerecorded audio sounds so the headphones can provide useful information for FPV.
  • Dual analog input for voltage and current monitoring. The DAC output can also be used as an analog input.
  • CAN Bus which is very useful for talking to external devices like the brushless gimbal to coordinate POI tracking or control the gimbal pitch from transmitter. Also CAN enabled ESCs are coming out which will allow serious improvements in flight quality.
  • Full sensor suite of course. MS5611 baro and MPU-9250 combined gyro/accel/mag. I was really conflicted on switching from the MPU-9150 to the MPU-9250. However, being able to utilize an SPI bus which is much better handled on the processor side made it worthwhile.
  • Optional single sided assembly - the necessary things to fly are all on the top of the board. The bottom has the CAN bus connector, RFM22b, antenna, external LED drivers. So if you just want a more powerful flight controller with more memory and CPU over Sparky it's still single sided.

Ground modem - TauLink

I also needed a ground side modem. This uses the same RFM22b module used on openlsrg as well as on the flight controller and uses an STM32F1. It was inspired by the PipXtreme (which also inspired the OPLink) done by Pip when we were with OP a few years ago, but is a bit smaller and easier to assemble. It's running code written by Pip, Brian Webb and myself. 



The modem has a standard SMA connector so can accept a wide selection of 433 Mhz antennas.  It uses micro USB and can be powered by a phone or tablet and works with the Tau Labs Android GCS. There is also a port that can serve as a receiver port for relaying signals from a transmitter or taking in PPM for a transmitter module. Finally, there is a serial port for connecting to a GPS. This is important for any tracking applications like POI mode since the accuracy of the phone GPS is not sufficient in my experience.




I also want to break out a few pins to a housing with buttons so the modem can be used to relay a few simple commands like "land" or "follow".

And a quick little case to make it easier to stick to things.




GPS

I picked up this super cheap Ublox 8 GPS that ReadError recommended on IRC. Conveniently, Sparkfun have also started selling the JST-SH cables needed to connect it. So far the performance looks really quite good, although I haven't flight tested it yet. Our software picked it up right away and autoconfigured it, which was nice.

Unfortunately it didn't have any mounting holes, so I quickly designed a case in OpenSCAD that uses the standard 30.5 spaced holes:



Flight Testing

First test was to put all these pieces together. I'm using a modified UAP-1 frame for this. No particular care taken for wiring or spacing between cables and FC. Let's just see how it does.


I ran through the standard configuration aspects to make sure position hold would work: performed the six point calibration and leveling, got a rough PID tuning dialed in (haven't merged autotune in this branch yet), enabled the appropriate modules, checked the EKF variances, used complementary/INS mode, set one flight mode position switch to leveling and the other to position hold. Took it outside with my phone connected via the modem. 


This is super convenient and practically necessary for any navigation related things - navigation is too complicated and error prone to risk blind. With this I could verify the GPS lock quality, check on the map that things things look sensible, and get audio alerts of any error conditions (e.g. when the GPS loses a lock, which didn't happen today).

Position hold mode performed really well for a first try (and pretty much first flight of this board outside). Loiter also worked well, although sometimes it seems like it moves 10-15 degrees different than what I expect. I need to check into this. Still it was comfortably controllable, and in fact at one point someone was walking near me and I shifted it without thinking.




The graphs showing where the quad is were generated from the android logs and the python parsing code.

Future directions

Now the hardware is working, there are a few things to implement:
  1. LED outputs based on flight. This will probably use picoC to make it easy to change on the fly. I'm envisioning something where the color indicates the heading relative to home and brightness the distance.
  2. Audio alerts. Again, I envision having some prerecorded sounds stored in flash that it transmits over the VTX audio channel and you can hear on the headphones. Low RSSI, low battery, GPS satellites, distance from home every X m, etc. Also possibly just simple beeps encoding health.
More important is the cool things this will enable. Relaying the accurate GPS position of the pilot via TauLink and then having a chase mode. We already have follow me for the tablet (have for a year or two now), but for higher speed stuff a better control scheme that accounts for the target velocity should help.



If you are interested in testing this board and previously got a Sparky v1 from me, then send me an email.

Wednesday, August 27, 2014

Sparky brushless gimbal controller - version 2

I made an add on board for Sparky last year that added brushless gimbal drivers and found it worked quite well:


However, because the sensors were all on the main controller board that was a lot to mount on the gimbal. Weight wise, it wasn't a problem. For tuning the gimbal though, having all the cables running to the moving part was a pain. So I redesigned it with a main board with our standard mounting holes and a satellite board with an MPU-9150 to provide the sensing (and be useful as an external mag for navigation).






Assembly

And got the boards back. The sensor board is designed to break off to make it easier to populate the two of them together.


And some of the boards soldered up.



Flight testing

I went ahead and put it on my Iconic-X frame that had the previous BGC revision and was pleased with the results:



Next

Now I have to connect it up via CAN and get some of the functions working like controlling the pitch angle via the transmitter and repeating the POI tracking that I have done with Oso Grande in the past.



Saturday, July 5, 2014

Soldering while traveling?

I just want to comment on a trick I learnt last week.

Last week I went to Santorini and diligently packed two quads. My Flying Spark for LOS and video recording and my Hovership MHQ for FPV (or letting other people see the video stream). I thought I was pretty prepared with tons of spare parts, tools and screws:


Unfortunately when I got there, I had an issue with the MHQ:


Santorini isn't a huge island so my chances of finding an electronic repair shop were pretty slip. Luckily, one of my friends suggested a candle, so here was my soldering setup:



It turns out the trick is that because the flame has a low heat transfer efficiency compared to a normal iron things take a lot longer. Basically it took between 3-5 minutes to get the ESC wire hot enough for the solder to flow. This also resulted in warm fingers, but the results worked!




Friday, July 4, 2014

Flying Spark - 3D printed mini quad

I've been wanting to design a 3D printed frame since having so much fun with Steve's. To cut to the chase, here is what I finished with:
Without prop guards

Arms printed with prop guards
And here are some videos from it:


The ready to fly weight is 437g with 1500 mAh 3S batteries and mobius camera. It gets around 12 minutes of battery time with 5x3 motors although I haven't really pushed it.

You can find the design on Thingiverse

Design

I had a few requirements:
  • aerodynamic shape, fairly resilient to wind
  • center of gravity near center of thrust
  • keep component on the inside (mobius, battery, sparky)
  • pack up well for traveling
  • easy to replace broken parts
The main hardware components were:
  • Sparky flight controller (of course)
  • SunnySky X2204 2300kv motors (with 12A ESCs)
  • 1500 mAh 3S batteries
  • Mobius video recorder
I originally started with FreeCAD but found OpenSCAD worked better for me, and was a useful new tool to learn. I started by modeling the outer hull. To decide the shape I simply took the battery, sparky and mobius and figured out the smallest way to stack them together.


Then I modeled a nice smooth hull around that:


and the internal components, considering how to make sure the negative space would successfully print:


Giving the main chassis as the difference between the two:



As well as arms that can be plugged into the sockets, with a split in the middle to decrease resistance to airflow. You can also see in the above images that I made a variant with prop guards.


Printed model



Printed with 3 shells and 30% infill the printed parts weigh 122 g.







and it packs up pretty nicely for traveling (remove 4 screws and arms pull out of sockets) if you need to disassemble it (e.g. for going into checked luggage).



Flight performance

So of course, the first thing I did was run the latest version of autotuning: 


, which gave these properties and PID settings:


I was really pleased with the performance of the autotune algorithm actually, it was really windy where I was traveling and I tried manually tuning it and couldn't beat the performance for flying well but not twitching in response to the wind.

It responds quite symmetrically. It also has a ton of pop. In fact, when I first tested it indoors and gunned it, I had a nice collision with the roof. This was flying the prototype arms printed with 10% infill:


However, the 30% fill are a lot more robust and so far I haven't managed to break one. As I mentioned, the main purpose way to travel well, and I was really pleased with that. Using 65mm (from edge of frame to center of motor) arms it would drop in my small backpack with props on and had no issues. The problem with that length is it leaves a tiny bit of blade in the frame. The 75mm arm does not, but wouldn't quite fit in my backpack. I might try modifying the chassis to move the arm back 5 mm which should fix it.

Videos

As I mentioned, this quad was largely designed to be small, travel well, and behave in the wind. I took it to a conference in Santorini which really put those things to the test. I'm really quite pleased with the results. Here are some videos:




Sunday, March 23, 2014

Vertical control

Vertical control is still not at a state that I'm happy with. We recently took one very important step in the right direction by making the same code and settings be used for standalone altitude control and navigation altitude control. At least with this, there is only one thing that requires tuning. After a fair bit of work, I'm pretty happy with the result. If you just want to see the video here it is

f

Sixteen state INS

One issue I see is that the accelerometer bias is not reproducible enough flight to flight, and because this is integrated into velocity that creates a non-trivial amount of noise. In the review I linked above, the complementary filter that is used for the vertical axis (based on ardupilot, to give credit where it is due) estimates the accelerometer bias. However, when running navigation (and thus the INS algorithm) the bias is not tracked for the accelerometers. The most obvious consequence of this is when you enable position hold mode or something else you initially get a throttle surge or dip. After it drops enough, the outer position control kicks in and the you get about a reasonable behavior.

One solution to this, which has already been merged, is the zero accel button. This will let you correct this error, but because the bias changes flight to flight will only be a short term fix.

This is more of a problem, though, for landing when only the velocity is controlled. If the decent rate is 1 m/s and the velocity axis has a 0.5 m/s error you get quite a large error in landing rate and either a long wait or quite a bump.

We had previously played around with a 16 state INS that added the accelerometer bias but it did not work terribly well. One issue for this was that when the board is sitting still, there is essentially a manifold of valid states - the board could be upside down if the accel bias were set to 16 m/s^2, for example. Unobservable systems are very bad for control. There was a fairly simple way of fixing this: I made the state equation for X and Y accel biases have a drift towards zero. This allows it to get to non-zero values (when flying around and really accelerating there might be good evidence for it) but keeps those values fairly well grounded near zero. This is appropriate, too, because the accel bias does not get that far from zero with a reasonably calibrated system.

The second problem turned out to be some bugs in the automatically generated efficient version of the covariance prediction. Manually finding the five typos in this wall of code (and this is only about a third of it)

was not the most fun I've had in the last few weeks. However, after fixing that and a few other tweaks it seems to be working quite well. Manually miscalibrating the system with an accelerometer bias of even 1 m/s^2 is accounted for perfectly and after thirty seconds the error in the vertical velocity falls to less than 0.1 m/s.

Of course, going to a 16 state INS introduces a higher CPU and memory load. However, on Sparky the INS is still only less than 1/4 of the CPU utilization which seems reasonable if it results in a good state.

INS Testing and tuning


To test this version of the INS, I got some logs with the Overo on Freedom and visualized the output of the INS and the quad movement. It seems to track quite well:


Now one issue I'm running into is that when I tune the baro variance to make sure it does track the altitude well, that couples the noise from the baro into the velocity estimate. This seems to be limiting the tuning settings I can get away with.

Vibrations and Fourteen state INS


Since the main issue bias we have issue with is the vertical, at least for now, I wanted to try and not burn cycles on the horizontal biases (although it is quite possible we might go back on this eventually). With some help from Dale (the original INS author) I jumped in and modified it to a fourteen state estimator, with only the vertical bias term being tracked. This wasn't too hard in the end, and also does a great job of estimating the vertical velocity.

However, no matter what settings I used, the vertical hold was not as good as I wanted. Interestingly, it was much better on my micro-quad. I finally broke down and moved Freedom from my POS HT-FPV frame that shakes like crazy to my QAV500. I hadn't flown this much because the pancake motors on it were not playing nicely with my ESCs and I hadn't had the time to tune them up. However, I switched to some SimonK ESCs:



And now no motor failures in flight. With this frame, suddenly the altitude control was much better. This was true using both the complementary filter and the new 14 state INS.

Tuning

You can do all this tuning in the default StateEstimation (complementary, raw) which runs the simple inertial filter for vertical. Once the updated INS is merged you can also tune in INSIndoor mode, but for now I would avoid that with the 13 state since the velocity bias makes the next step a bad idea.

Next, the altitude control loop should be tuned. Ultimately I found the default values were pretty close to what I wanted but the exercise was interesting. Lux (in IRC) recommended a method from baseflight which is very analogous to how I recommended tuning the main control loop (see this video for a tutorial I did years ago).

Basically first you set the AltiudeHoldSettings.AltitudeKp to zero and fly altitude hold. In this condition it will drift up and down a bit randomly but should behave essentially well. Then you gradually increase the AltiudeHoldSettings.VelocityKp until the motors begin to hunt and sound really twitchy. Once you hit that point bring it back down a bit. I didn't feel the need to tune the Ki component since it seemed to be working fairly well and not overshooting.

Once that is done, then you can dial in the AltitudeHoldSettings.AltitudeKp again. If the altitude is wandering too much then increase that term. If the whole system is jumping up and down and hunting again, then reduce it. I found the default value of 1 or down to 0.5 seems to be a pretty good range.

TL;DR: set Velocity Ki to about 1/5 of Velocity Kp and increase that until you see fast twitches, then back off. Then increase the outer gain until you start seeing oscillations and back off.

Vertical Control


KipK in IRC also asked for more aggressive control of altitude when flying altitude hold mode. This has been on my TODO list for a while, and I kept putting it off.

The current scheme waits for the stick to move out and then into the middle range to enable vario mode, but most people have found this unintuitive. Instead I went ahead and added an exponential to the range outside the dead band. This allows more sensitive control in the middle and aggressive control for further stick movements.

Previously, moving the sticks only shifted the set point. Instead I wanted something more like AxisLock where in the middle range the setpoint stays the same and in the outer range you control rate instead of moving the setpoint. In control parlance this is called full state control where we pass the desired position and rate.

I thought I was pretty clever coming up with this scheme, but looking around it seems like everyone has converged on it for vario mode - which probably means it is a reasonable idea.

Here is a video of OsoGrande testing it out and then myself. I'm pretty happy with the response and he said it felt fairly natural to fly.


There was also a glitch with vertical control when doing position hold and RTH that caused it to have a brief dip when engaged. The integral wasn't being properly preloaded with the hover throttle, but this should be fixed now.

Conclusion


So with all these changes, I think we are set to have some really clean navigation. Some care needs to be taken of vibration if you want to get a really clean hover. This is much easier on smaller quads in my experience.

Saturday, March 22, 2014

Magnetometer handling in INS


The Tau Labs INS (written by Dale Schinstock) works really well and has been used for various navigation tasks for the last few years. However, one aspect that I have found problematic is the magnetometer handling. The way it works currently is that the Earth's 3D magnetic vector is rotated by the attitude to predict the 3D measurement we should get.

In principle that is a great idea, and on planes probably fine. However, on multirotors that generate a lot of local field distortions from the motors, it is rather problematic. The reason is that as the Z (down) component is altered, it creates a bias in the roll and pitch components of attitude to deal with this. We already know (from years of experience flying the complementary filter) that the gyros and accels are sufficient to stabilize those components. As a work around we generally have just used fairly high variances for the magnetometer. This isn't optimal though, as I've seen the INS bias estimate for the Z axis sometimes destabilize since it isn't sufficiently constrained by the mag when initially converging if things are fairly miscalibrated.

I have been wanting to alter the EKF for some time to only allow the magnetometer to influence the heading estimate, but the path wasn't obvious. Today I decided to sit down and implement this, and I'm fairly happy with the result.

Derivation


We want to measure just the heading aspect of the mag, in order to get rid of the mag influencing attitude. Currently the predicted measurement of the magnetometer is 

$\bar B_b = R_{be}(q) Be$

So we want a version that only depends on the heading component of $q$. That turns out to be less trivial that it sounds. To achieve this, we essentially want to only work with magnetic information projected into a plane parallel to the earth (called the $h$ plane). The rotation $R_{be}$ can be decomposed into two matricies, $R_{be}=R_{bh} R_{he}$, where $R_{bh}$ applies the pitch and roll transformation and $R_{he}$ applies the yaw transformation. We can rotate the raw mag measurements in order to undo the influence of just the roll and pitch by using the inverse (in this case transpose) of $R_{bh}$, $B_h = R_{bh}^T B$, and then only keep the components in x and y.

To calculate both $R_{bh}$ and $R_{he}$, we can get the equations from the code. I then used this code in matlab and the symbolic toolbox to get the matrix. It took a little bit of massaging afterwards to get an efficient implementation:

syms q1 q2 q3 q4 real
q = [q1 q2 q3 q4];

q0s = q(1) ^ 2;
q1s = q(2) ^ 2;
q2s = q(3) ^ 2;
q3s = q(4) ^ 2;

R13 = 2.0 * (q(:,2) .* q(:,4) - q(:,1) .* q(:,3));
R11 = q0s + q1s - q2s - q3s;
R12 = 2.0 * (q(:,2) .* q(:,3) + q(:,1) .* q(:,4));
R23 = 2.0 * (q(:,3) .* q(:,4) + q(:,1) .* q(:,2));
R33 = q0s - q1s - q2s + q3s;

roll = atan2(R23, R33)
pitch = asin(-R13)
yaw = atan2(R12, R11)

% compute the rotation matrix that is for the attitude component
% this is the matrix that will rotate from the earth frame to the
% current roll and pitch. The inverse will take the magnetometer
% reading back into a horizontal place
sF = sin(roll); cF = cos(roll);
sT = sin(pitch); cT = cos(pitch);

r = sqrt(R23^2 + R33^2)
sF = R23 / r;
cF = R33 / r;
sT = -R13;
cT = sqrt(1 - R13^2);
Rbe_bh = [cT, 0, -sT;
          sF*sT, cF, cT*sF;
   cF*sT, -sF, cT*cF]


Then we need to modify the EKF to predict a measurement in the horizontal plane. That aspect is pretty straighforward, it is the same equation but keeping the yaw component instead of pitch and roll

% direct equation
sP = sin(yaw); cP = cos(yaw);
Rbe_h = [cP, sP;
       -sP, cP];

% another expression that results in code that doesn't use imaginary
% numbers
x = R12;
y = R11;
r = sqrt(R12^2 + R11^2)
Rbe_h = [y/r x/r; -x/r y/r];

% calculate predicted B_h in the horizontal plane
B_h = Rbe_h * Be

% generate c code to compute this
ccode(B_h)

I ended up having to manually expand $cos(atan2(x,y))=\tfrac{y}{\sqrt{x^2+y^2}}$ for matlab because it kept trying to use imaginary numbers to calculate the norm. The last line of this actually generates C code for the two components of $B_h$. It needed a fair bit of massaging after that to factor out common terms and get an efficient implementation.

The other thing needed for the INS is the derivative of the measurements with regard to the state, or in this case $\tfrac{\delta B_h} {\delta \mathbf{q}}$.

% and compute the derivatives wrt to the attitude
ccode([diff(B_h,q0)'; diff(B_h,q1)'; diff(B_h,q2)'; diff(B_h,q3)'])

Again, Matlab symbolic toolbox to the rescue, saving me from a lot of tedious algebra, although again lots of massaging was required.

Testing


So again, Freedom Overo logs saved me tons of time, since I can replay previous flights through the new filter and see how it performs. It performs really nicely. The nice thing about this, is we can tighten up the variances on the mag and make sure the convergence behaves well, and not worry about the magnetic field biasing the attitude as we go.

Here is the raw magnetic heading and the INS output:


, which you can see is nicely tracking together.

I also loaded it up on my Freedom and power cycled it a bunch of times, as well as letting is sit for an hour. Rock solid - none of the oscillations I would sometimes see with the previous code - and now I can keep the gyro bias estimation on reliably. With a good accel calibration and board leveling, you get a perfect PFD:



This is with minimal tuning or tweaking, so that is great. I'll need to play around with a bit in flight but I'm pretty optimistic about this - and hopefully it will reduce the rare times we do see toilet bowling. I also now need to play around again with the mag compensation code, although hopefully it won't be necessary.

It was also a really fun day project. I've played with kalman filters before but never had to go quite as deeply into the extended kalman filter. I also learned some more about playing with quaternions and rotation matricies, so that was productive.

Saturday, March 15, 2014

Logging and Python parsing

Current state


One really common task for anything beyond normal LOS and FPV flying, is the need to analyze log files. We have a fairly nice facility for doing this - using Matlab to parse log files. Running build matlab generates LogConvert.m that will parse log files into .mat files for analysis. That works quite well, but there are a few problems:

  1. not everyone has matlab (although octave is free)
  2. you need a LogConvert.m that matches the git hash you have
  3. impossible to make standalone applications using this
  4. matlab is terribly slow for processing video or generating videos
  5. slow for parsing the high resolution overo logs, as well as lacking the CRC checks 
Luckily, Stac came to the rescue.

Getting logs


So the easiest way to get logs is through Android (it logs all connected flights) or with GCS. This is what I'd recommend for most people.

But what do you do if you want better data. My goto option is Freedom which logs everything and I think is awesome. However, since I haven't finished that or made more than 2 that doesn't help most people.

Another option is something I came up with a while ago, using OpenLog. It's limited but useful. 

Python parsing and plotting


He wrote a python version of the code for parsing log files, that detects the appropriate git hash from the log file, checks out the xml files defining those UAV objects and generates the needed classes on the fly. The sort of really cool run time class generation python can do. This was merged here.

To parse a log file that was generated from either Android or the GCS, simply run (from the Tau Labs repository directory):

$ python python/logview.py path/to/file.tll

This launches an IPython environment - an interactive python environment - where you can proceed with data analysis and visualization. It should give you a prompt like this:


There will be a few variables in your workspace at this point. The most important is uavo_list, which contains all of the parsed log entries of all the object types. To get the data from a particular UAVO, use the as_numpy_array method. You have to pass it the UAVO_ObjectName which is the class to cast the appropriate elements too. This will create a numpy.ndarray that can be indexed like a set. For example, to get the accelerometer data and plot the z component:



I won't delve further into the details of plotting in python since I'm sure that is covered better elsewhere.

However, a side note for processing either Overo logs or logs recorded with OpenLog and my Logging branch. In these files there are two differences: they enable the embedded timestamps in the UAVTalk message (described on the wiki) and do not write the githash into the file. The later is pretty annoying because you have to keep track of what version of the firmware your log files were created with, so hopefully I can fix that later. To parse these log files use this command

$ python -t -g GITHASH_OR_BRANCH_NAME python/logview.py path/to/file.tll

The -t switch tells it to use the internal timestamps (which are more accurate since they are when the FC sent the data) and the second part tells it what git hash to get the set of xml files from.

Generating videos


I've been developing a set of methods that take these log files and generate a video of graphs. Just for general analysis, I find overlaying data on top of the video of flight is really informative. I also think this could evolve into a cool set of overlays for FPV flights.

At the core of this is the matplotlib.animation library. You write a function that will plot (or manipulate a plot) to what you want at a given time stamp. For example I often shift plots to center at that time stamp and show a brief segment around it, with markers centered at the current time:

# Plot a segment of the path
def update_img(t, mark_0=mark_0, mark_1=mark_1, mark_2=mark_2, ax=ax):

 # convert to minutes
 t = t / 60

 import matplotlib.pyplot

 matplotlib.pyplot.xlim(t - 0.25, t + 0.25)

 mark_0[0].set_xdata([t,t])
 mark_1[0].set_xdata([t,t])
 mark_2[0].set_xdata([t,t])

Then you want to run this over a set of times and generate the video. To do this, I use this something like this:

fps = 30.0
dpi = 150
t = arange(t0_s, t1_s, 1/fps)

ani = animation.FuncAnimation(fig,update_img,t,init_func=init,interval=0,blit=False)
writer = animation.writers['ffmpeg'](fps=30)
ani.save(output_filename,dpi=dpi,fps=30,writer=writer,savefig_kwargs={'facecolor':'green'})

The blit=False and this set of codecs seems to work pretty well for OSX, but your mileage may vary. Now, because I'm typically wanting to use this to create an overlay, I use a green background everywhere. If I have multiple axes that I am plotting, this is what I use:

for a in ax:
 a.set_axis_bgcolor('green')
 a.xaxis.label.set_color('white')
 a.yaxis.label.set_color('white')
 a.spines['bottom'].set_color('white')
 a.spines['top'].set_color('green')
 a.spines['right'].set_color('green')
 a.spines['left'].set_color('white')
 a.tick_params(axis='x', colors='white')
 a.tick_params(axis='y', colors='white')

This will use white text and labels and set the background of the axis to green. Notice also the savefig_kwargs={'facecolor':'green'} section in the ani.save command which also is important.

Here are some of the results:


Finally, I combine this all in Premiere or IMovie (although that can only handle one overlay and doesn't allow positioning), and get something like this:


Here are some of the scripts I used to generate this:

  • https://gist.github.com/peabody124/9571409 - generates the altitude overlays
  • https://gist.github.com/peabody124/9571455 - generates the position overlays

Next steps


As is, this is a really powerful tool. However, what I think would be really awesome is to organize some scripts to generate a bunch of nice overlays, and then ideally write standalone python scripts that parse the log and spit out a video instead of going through IPython. The end goal would ideally be compiling to standalone applications, or alternatively integrating into the GCS and calling out to python (plausible?).