Here are some pics of the Phantom FX-61 after today’s exciting day out. It took a few good hits. We actually just taped the nose back on for most of the day and it still flew like a champion.

IMG_4428 IMG_4429 IMG_4430 IMG_4431 IMG_4432 IMG_4433 IMG_4434 IMG_4435 IMG_4436 IMG_4437 IMG_4438 IMG_4439

It seems FlightGear doesn’t lie. It works in the sim and now we’ve flown it in real life. Pitch & roll stabilised mode worked brilliantly. Flying in this mode is very low stress and easy. We also tried heading & altitude control, but had some difficulties. This is mainly due to issues with the altimeter/barometer and magnetometers. The LPS331 altimeter is very noisy which makes it hard to derive vertical speed and the magnetometers . . I don’t know what happened there. But the heading was all over the place.

FLStation 0.5.0 is now available for download.


This release has a muchly improved flight display user interface. It also has vertical speed control, fuzzy PID control for auto-throttle and various other cool things.

One important note about the auto-throttle – it uses ground speed only. And since it’s quite possible that the aircraft could have a strong tail wind, it will never fully cut the throttle to slow down the ground speed. It will reduce the throttle, but it won’t ever cut it off (unless the aircraft is also commanded to descend). It should not cause the aircraft to approach a dangerously low air speed.

I’m also putting together a Phantom FX-61. I had ordered a Bixler2, but ended up getting this instead. It’s a much better craft for this type of thing.

Basic layout of the avionics gear.

Basic layout of the avionics gear.

The avionics is mounted onto a stiffened balsa board which is adhered on with lots of anti-vibration jelly. The actual firetail board and other components are also attached with anti-vibration jelly. Despite this, the LSM303 accelerometer still gets messed up when the motor is running. I’ve put an ADXL345 breakout board in this plane as well, and fusing the these two accelerometers seems to get rid of the vibration problems altogether. The mems sensors aren’t properly aligned with the airframe yet either. This photo shows how crooked they are.

The battery is also too small for this model. It’s a 3S 2200mAh battery. The recommended battery is 4500mAh, so that’s something I’ll need to upgrade soon too. Even with this battery I expect flight times of about 10mins. Maximum current draw is about 16 amps (nearly 200W).

This model is supposed to take a huge battery and stacks of gear. Even with the tiny little firetail board and 2200 mAh battery shoved all the way forward, it isn’t enough to get the C of G right. So I had to glue about 40g of lead into the nose.

Dipole antennas make it look like an insect. It's an unintentional, but awesome look I reckon.

Dipole antennas make it look like an insect. It’s an unintentional, but awesome look I reckon.

Calibrating magnetometers is critically important. Without a good mag cal, you’ll get rubbish out of your magnetometers. Fortunately it isn’t that hard to do a basic calibration.

First of all, here are some scatter plots of raw magnetometer data. The sensor I used to create these was an LSM303.

lsm303 magnetometer scatter plot xy axis lsm303 magnetometer scatter plot xz axis lsm303 magnetometer scatter plot yz axis  lsm303 magnetometer scatter plot 3d view

These scatter plots show both hard iron (or bias) and soft iron errors. An ideal plot is circular and is centred on the chart. Hard iron errors cause the measurements to be off centre. Soft iron errors cause the shape to be elliptical rather than circular.

To remove these errors, you need data. Lots of data. So get your magnetometer and move it around until you’ve got a few thousand samples in as many different orientations as possible.

Hard iron errors are the simplest to remove. Find the maximum and minimum measurements for each axis and average them. This gives the amount of offset for each axis. Every time you take a reading from your magnetometers, you should subtract this offset from each axis.

raw_values[i].x() -= (min_x + max_x)/2.0;
raw_values[i].y() -= (min_y + max_y)/2.0;
raw_values[i].z() -= (min_z + max_z)/2.0;


Soft iron errors are slightly harder to remove. There are some more advanced techniques that involve calculating rotation matrices and bla bla, but it’s computationally expensive (for my brain) and simply scaling each axis to remove the elliptical shape works quite well too.

First the hard iron errors are removed from the maximums and minimum magnetometer vectors. These minimum and maximum vectors are the same as the ones being used to correct for hard iron errors.

imu::Vector<3> vmax;
vmax.x() = max_x - ((min_x + max_x)/2.0);
vmax.y() = max_y - ((min_y + max_y)/2.0);
vmax.z() = max_z - ((min_z + max_z)/2.0);

imu::Vector<3> vmin;
vmin.x() = min_x - ((min_x + max_x)/2.0);
vmin.y() = min_y - ((min_y + max_y)/2.0);
vmin.z() = min_z - ((min_z + max_z)/2.0);

The average distance from the centre is now calculated. We want to know how far from the centre, so the negative values are inverted.

imu::Vector<3> avgs;
avgs = vmax + (vmin*-1); //multiply by -1 to make negative values positive
avgs = avgs / 2.0;

The components are now averaged out
float avg_rad = avgs.x() + avgs.y() + avgs.z();
avg_rad /= 3.0;

Finally calculate the scale factor by dividing average radius by average value for that axis.
float x_scale = (avg_rad/avgs.x());
float y_scale = (avg_rad/avgs.y());
float z_scale = (avg_rad/avgs.z());

With these scale values we can correct for soft iron errors by multiplying them with the relevant magnetometer axis reading. Here’s an example

imu::Vector<3> mag_reading =;

mag_reading.x() -= (min_x + max_x)/2.0;
mag_reading.y() -= (min_y + max_y)/2.0;
mag_reading.z() -= (min_z + max_z)/2.0;

mag_reading.x() *= x_scale;
mag_reading.y() *= y_scale;
mag_reading.z() *= z_scale;


Here are the results using this technique.

cal_3d cal_3d-2 cal_xy cal_xz cal_yz

It doesn’t use any matrix maths and the magnetometers are now quite accurate. In fact, using a map I can’t see any errors. Without any proper test equipment, I’d guess that it’s good to +/- 2 degrees.

I just did a side by side comparison for the LPS331 and BMP085 pressure sensors. I’ve also edited this post to add the new LPS25H. Scroll to the bottom to see that graph.

Here’s the LPS331 vs BMP085 graph.

LPS331 vs BMP085

LPS331 vs BMP085

This is 512 samples taken at 20ms intervals. This graph does not give any indication of long term accuracy. If the results above were put through a low pass filter, I have no idea which one would be more accurate.

I don’t believe accuracy is important for most uses. What IS important is having a reference point that doesn’t drift. Imagine flying up to 1000ft and then hitting the ground at +100ft on the way down – because the sensor has drifted -100ft. What is also very important is low signal noise. What this overwhelmingly demonstrates is that the LPS331 is very noisy. This makes it hard to get accurate altitude readings in a dynamic environment (ie. a model aircraft or rocket), where the altitude can change quite rapidly. The low pass filter required to get decent readings will cause so much lag that it’s basically useless. Imagine trying to derive vertical speed from that!

Unfortunately for me, I don’t have to image. Getting vertical speed information for Firetail using an LPS331 has been my nightmare for the past 24 hours how. I’ve tried using a Kalman filter to infuse some acceleration. This allows me to really filter out the noise whilst keeping it relatively responsive, but after hours of tweaking and simulations I’ve got it to the point where it’s ‘OK’. But it’s not great. Even the mighty Kalman filter can’t sort it out as well as I’d like.

So if you need a pressure sensor / altimeter, get a BMP085 or a MS5561. The LPS331 just doesn’t cut it.

edit* OR get an LPS25H. These new sensors from STMicro are supposed to be a higher quality alternative to the LPS331. Unsurprisingly, they are.

LPS25H is much less noisy than the LPS331, but it still doesn't beat the old BMP085.

LPS25H is much less noisy than the LPS331, but it still doesn’t beat the old BMP085.

By the looks, the signal noise is about +/- 3 feet max. That makes it about 3 times LESS noisy than the LPS331 and it’s now my new favourite pressure sensor. I prefer it over the BMP085 because temperature compensation is done internally in the IC, rather than in software as with the BMP085.

Firetail can plug into the FlightGear simulator. This is great because FlightGear can output simulated sensor data for the autopilot and you can simulate fully autonomous flights. The only downside to using FlightGear is that there isn’t a big range of RC models to choose from. Nearly all of the models are for full-scale manned aircraft. There is also no option (that I know of) to view the aircraft from the ground – like an RC pilot would. In other words, it’s a great tool for testing and tuning the autopilot but it’s not so great for practising RC flying.

CRRCSim is a flight sim for model aircraft flying. It has a range (not exactly a BIG range, but there options) of models including flying wings, gliders and sport models. It gives you the perspective of a model RC pilot which is great because it teaches you how to fly RC, rather than from a cockpit point of view.

As of the next release of FLStation, Firetail will be able to connect to CRRCSim and provide control inputs to it. It will not fly autonomously in CRRCSim, but it will allow you to use your normal RC transmitter (rather than the keyboard, mouse or a joystick) to get some practice in manual mode. All you’ve got to do is plug in the autopilot via USB and turn your RC transmitter on. In CRRCSim, it’s just a matter of selecting the input method to FMSPIC and selecting the correct serial port. You’ve also got to configure the controller, which is really easy and takes a total of about 5 seconds.

One thing did catch me out to start with. I couldn’t get the throttle control to calibrate. You’ve got to disarm the motor using FLStation, as you would when you are normally flying (facepalm). Just remember to disconnect the motor before you do that. Your plane will try to fly!

Tuning PID controllers can be an addictive waste of time. Constant tweaking and tuning can take time away from making actual constructive improvements to the controller. PID controllers can work very well, but getting them to work perfectly in a very complex environment requires lots of knowledge of the system (to provide feed-forward), as well as trial and error tuning. An imperfectly tuned controller can produce terrible results. If it doesn’t ‘come good’, then you’ve got to take a step back and have a think.

This is the point I got to with using PID control for autothrottle, so I decided to implement a fuzzy PD controller. I’ll refrain from going into detail about the operation of fuzzy logic controllers (I’ll probably get it wrong). There are good tutorials and documents about it online.

This autothrottle system (like most others) accounts for the energy requirements of the aircraft. Here is the video

Log File

When the autothrottle is engaged, two fuzzy controllers compute required energy. In autopilot modes where an altitude is selected, a fuzzy controller uses the altitude error to determine energy requirements for climb/decent. In other modes, the fuzzy controller uses pitch instead. Naturally speed is accounted for too. If the aircraft is above or below speed, a fuzzy controller determines a response. The output of these two controllers is averaged (actually, the pitch/altitude output is prioritised slightly) to determine the output. This output is then dampened by a derivative value to improve responsiveness and reduce overshoots. Finally an offset is applied to reference the output to the selected cruise power setting. The result is the throttle setting!

What this means is

  1. Pretty good throttle and speed control
  2. Zero PID tuning. There are only three very simple and intuitive settings.


The next release of FLStation will come with Firetail firmware that features this, as well as better altitude control, stall & overspeed protection and a few other goodies.

Like most things in life, getting your Teensy 3 to read and write to micro SD cards is easy IF you have access to good pin diagrams and information. Unfortunately, pin names for micro SD cards seem to vary. Some people prefer to use MISO/MOSI, others prefer Din/Dout. Some diagrams show Vdd and Vss, others say +3.3V and GND. It’s confusing! So here is an ultimate wiring/pinout chart to help explain how to connect a micro SD card to a Teensy.


uSD Card Pin Teensy Pin Names Description
1 - DNC Do not connect
2 Several pins can be used CS, SS Chip select or slave select
3 11 DI, Din, MOSI Master out, slave in.
4 3.3V Vdd, Vin Supply voltage
5 13 CLK, SCK Clock
6 GND Vss, GND Supply ground
7 12 DO, Dout, MISO Master in, slave out
8 - DNC, RSV Reserved, do not connect


I’ve been trying to get FLStation to play sounds for certain events. For example, on loss of data link it will play a beeping sound similar to a hung up phone line. Playing sound files shouldn’t be a difficult thing to do – and it’s not really, but it did take me all day to get it working. First I tried SFML (that’s the small, fast media library). It seems like a great library but it isn’t well suited for this task. It’s a whole media library. I just want to play some beeping sounds. So I knocked together my own little API using OpenAL and libsndfile. It’s a dead simple library that literally only plays sound files. Oh, and it can stop and pause them.

It will play sounds on any platform, pretty much. Mac, Windows, Linux, probably Android and everything else.

It’s available here.

Otherwise you can grab it out of the FLStation source code.

Posted in C++