About this project

Hello!

My name is Alec Myers and I’m an instrument-rated pilot who enjoys flying a single-engined Cessna around southern Ontario.

This blog is the project documentation for something I’ve been working on for the last few weeks, a solid-state open source Attitude/Heading Reference System (AHRS). That’s a small package of electronics that senses its orientation in space and sends the information to something like an iPad or iPhone which provides a display that you can use in an airplane cockpit.

If you have something like an iPhone you may have seen the cockpit-type display apps you can download. They give you an artificial horizon, and some kind of compass display and look pretty cute. Unfortunately the hardware that’s included with the average smart phone isn’t designed for this purpose and they don’t function very well. The horizon line isn’t very stable, it’s very susceptible to vibration and the compass can point pretty much anywhere.

To get accurate information to display needs something more specialized, and that’s what this AHRS project is about.

The idea isn’t new or original and in fact there’s a company called Levil Technology who make and sell exactly this kind of device, under the name G Mini. And that itself is a development of the bigger and more expensive hardware that sits in the avionics bays of all modern airliners and a lot of smaller aircraft too. But the kind of technology you need to do something useful in this field has become now quite cheap and is readily available to individuals.

Seeing the Levil webpage and reading the reviews of their very cool device inspired me to see if I could replicate – and maybe improve on – their product.

I have a technical background, including a degree in Mathematics, and in the 1990’s I spent a happy couple of years designing various electronic gadgets on a professional basis. That was all good experience for this project; now I’m writing up the details of what I’ve learned and discovered so anyone who’s interested can repeat what I’ve done, and maybe make their own adaptations and improvements. I certainly hope that will happen.

I want to add one final point: although the goal is to build something that you could use to pilot an aircraft, I’m certainly not suggesting that that is what you should do. Certified avionics for instrument flight are subjected to rigorous testing procedures and have fail-safe requirements way beyond this project. Even the G Mini is not certified for instrument flight, and that comes from a company with real resources to invest in testing and development. I certainly don’t have that at my disposal – my environmental testing facility is a domestic fridge-freezer and a hair dryer, and my kinematic test-bed doubles as the lettuce-spinner from the kitchen. I have a production run of one (maybe two) devices and no way to certify or vouch for anything involved. So if you do build anything based on what you read here – don’t imagine for one second that you should use it for any purpose in or around a real aircraft. You have been warned.

6 Comments

Filed under Background Information

Background

When I started looking online I found a huge amount of information about projects very similar to this.

Aside from the commercial product, a lot of very relevant work has been done in the modelling community. People who design, build, and fly model airplanes, helicopters, quadcopters and all kinds of other small aerial vehicles have been building similar devices as part of autopilots and autonomous flight guidance systems for probably the last five years. If you want your model aircraft to take off, fly a pre-programmed course, and then land again – without human intervention along the way – one of the things it needs is a system to tell it which way up it is and which way it’s facing.

What makes this AHRS project different is that is has different design parameters. If I’m flying on instruments I need a decent stable horizon reference, and I need confidence in it. Maybe more than if it were controlling a model aircraft. But I also know that small models can do things that big aircraft can’t: like fly tight circles, or roll side to side in a few seconds, for instance. That means there may be some ways I can relax the performance constraints for what my device needs to able to cope with.

The huge interest in this area in the modelling community has another big bonus for me. Not only is there a lot of information on other people’s projects but the hardware – the electronic components and circuit boards that we need – can be bought off-the-shelf. The hardware is basically a tiny microprocessor attached to some sensor chips. Then we need to add a wireless transmitter, and a battery of some kind.

Where we have to do some work is to write (or rewrite, or modify) the software that runs on the microprocessor. To do that we need a solid understanding of what we can measure and what we have to do with those measurements. I’ll leave the details of that until later, and describe the hardware in the next part.

Another great source of information has been various scientific papers published in the literature on topics that touch on what goes on inside the software we need. There’s basic maths help on Wikipedia but we’ll need to dig a little deeper.

I’ve also had some fruitful discussions with friends and others who are interested in the various topics this project has thrown up.

Leave a comment

Filed under Background Information

Hardware – Bill of Materials

The hardware involved in this project was actually suprisingly easy to put together. Everything is available as modules and you only need half a dozen bits of wire to string them together.

We’re going to use wifi to transmit the data we measure to our iPad/iPhone/display: we do that with an RN-XV WiFly module. I got mine from Sparkfun, amongst other places.

For a power source I suggest a Lithium Polymer (LiPo) cell, also available from Sparkfun. In another post I’ll try to write up some suggestions of how you can include a charging circuit for the LiPo, but that’s icing on the cake. Or you can use AA or AAA dry cells, according to taste.

The interesting component is the microcontroller board and its associated sensors. I chose to use a Mongoose board from CK Devices, a company in Edmonton, Alberta. There are several similar boards available; Sparkfun make one they call the Razor, and I’ve also got one called ardIMU. All have the same basic idea: a microcontroller (from Atmel) connected to some gyroscopic sensors, some accelerometers, and some magnetometers. The sensors let you measure, in order, how fast you’re turning, how fast you’re accelerating, and which way the earth’s magnetic field goes. The processor will run software to combine the measurements into an indication about which direction is “up”, and which way is North.

Although all these boards fulfil the basic criteria, there are differences: the Mongoose includes a barometric pressure sensor so you can measure your altitude while the ardIMU has a built-in connector for a GPS device. The Mongoose runs at 3.3V and will run directly from a 3.6V LiPo cell, but the ardIMU runs at 5V so would need a step-up convertor. The mongoose also has a tiny power on-off switch. If you want to use the software I’ve written (rewritten) then you can use either the Mongoose or the ardIMU; I’ve made sure it works on both. But if you’re minded you can adapt it to run on anything similar.

At this point I need to say something about the Arduino project: one of the difficulties of starting a project that uses tiny “embedded” microcontrollers is the steep learning curve at the start. You need to install a lot of software on your computer, learn a lot of new programming skills, design a lot of hardware etc. before you get to do anything interesting. The Arduino project changes all that: by using their (free to download) software along with an Arduino-compatible circuit board you be doing interesting things with microcontrollers within a few minutes of starting out. The Mongoose, the ardIMU and the other similar platforms that I’ve seen are all Arduino-compatible.

The last thing that you’ll need is a small circuit-board to connect your computer to the microcontroller, via a USB port. It’s called an FTDI board and you can get a good one from CK devices again, or Sparkfun as well as lots of other places. Here’s a photograph:

Component boards for an AHRS

From left to right: the FTDI board (with USB onnector), a Mongoose board, the purple-coloured ardIMU and the RN-XV WiFly module. The coin is a (Canadian) quarter. I soldered the six-pin connector onto the ardIMU. Both it and the Mongoose come without a connector on the data pins so you have to solder one.

 

To summarize, the parts required are:

  • Inertial plaform, Arduino Compatible (Mongoose, ardIMU or similar)
  • RN-XV WiFly module
  • Power source like a LiPo cell
  • An FTDI board to connect to your laptop

I also recommend using a “breakout board” for the WiFly module, to make it easier to configure and connect. Something like this one from Adafruit, or this from Sparkfun. The WiFly unit must run on a 3.3V supply. The Adafruit breakout board has a power regulator and level translation so you can run it from 5V, which would be useful if you use the 5V ardIMU. If you’re using a Mongoose board at 3.3V then you can skip the components on the Adafruit board, but you’ll have to jumper a couple of connections with a wire link.

Leave a comment

Filed under Background Information

Displays

I haven’t said anything yet about how I plan to show the output of the AHRS. If you look at the Levil website you’ll see that there are a host of different apps for iPhone, iPad, Android etc all of which will take the data output from the G Mini and give you a cockpit-style display.

It makes a lot of sense to be able to use the same apps for our device too. That means making the output compatible. I exchanged a couple of emails with Levil, hoping that they’d tell me the data output format they use. That was a bit naive, looking back – they’ve no reason to want to help me. However, protocols are not protected (or protectable) in law, to encourage competition.

So I made some contacts with people who have the G Mini and had them log some sample output. It’s relatively straightforward to see what’s going on. The output from our device needs to consist of comma-separated values preceeded by a header string, each line terminated with a <CR>:

There are two sets of data strings, one for attitude information, and one for altitude. There’s also a way to transmit information about battery level, but I haven’t decoded that yet. So this is not comprehensive information but it’s sufficient for now:

$RPYL,{roll},{pitch},{heading},{slip},{rate_of_turn},{g-load},0,

$RPYL… <updated information>

$RPYL…

$RPYL…

$RPYL…

$APENV1,0,{altitude},0,0,0,{vertical_speed},0,

$RPYL…

$RYPL…

$APPOWER,{battery voltage},0,{battery level percent},

Empirically I found that if we send the attitude information at an update rate of about 20Hz and the altitude information at 2Hz it works well. The battery information can go every second or so.

Notes:

  • Angles are integer values, in tenths of a degree. In other words a roll of 20.3 degrees to the right is a value of 203, a roll of 15 degrees to the left is -150
  • Headings are between 0 and 3599
  • Rate of turn is in degrees per second
  • g-load is in mili-g’s so a load of 1g is a value of 1000, etc.
  • There are a lot of zero values in the data. They’re obviously placeholders for some other data but I’m not sure what.

So if we implement this form of data output we can expect to use our choice of software. My favourite App is iHud Remote, from Aero Visions International, Inc., but you can take your pick of several.

In order to transmit the data we can setup the WiFly module in a variety of different modes. The original G Mini features a serial port, and a USB port, as well as a WiFi connection. I’ve only implemented WiFi in my version but a serial port is a straightforward extension and as far as I know the FTDI board that you use for programming provides the right USB connection to connect to an Android tablet, too. When I get to talk about building your own display later I’ll argue against WiFi, but since I want to use an iPad for now – that’s what I’m using.

First generation G MInis required a WiFi-connected App to associate to the device in the WiFi settings, then open a TCP connection to port 2000 on the G Mini’s address of 169.254.1.1. That meant only one device could receive data at a time, as TCP is strictly a protocol between two endpoints. Latterly I see that you can broadcast data via a UDP connection to many receivers which is a much better idea. The RN-XV WiFly module can handle both incoming TCP connections as well as UDP broadcasts so we can use whichever we prefer. The difference is only in the WiFly configuration and we’ll cover that later.

Leave a comment

Filed under Background Information

Connecting the Hardware Together

Like I said, this is the easy part.

Clearly you can arrange the physical configuration any way you want. Here’s how the platform I’ve been working with was put together.

I’m using the bare board from the Adafun Xbee breakout parts kit to plug the WiFly module to. So I’ve soldered connectors to both that, and the Mongoose board. I prefer Molex KK connectors (they look like this) since I already have the hand tool to crimp wires to the pins that go in the matching sockets. However the Mongoose comes with a similar connector you can use, albeit a little smaller and less robust.

Now is a good time to mention the power arrangements I’m using. The Mongoose has an on-board 3.3V power regulator and comes with a JST socket that matches the tiny plug supplied on the end of the leads from most LiPo cells. So I chose to power the Mongoose directly from the LiPo and feed the WiFly at 3.3V by drawing power from the Mongoose’s voltage regulator. There’s enough capacity on the Mongoose regulator to do that, especially if you adjust the WiFly to reduce its WiFi broadcast power.

So my cable between the two boards needs three wires, +V, Gnd, and a data line. I’ve gone ahead and connected two data lines, one each way, so I could have the Mongoose receive data over the air interface. I might use that to send commands to it although at present I’ve not found a need for it nor programmed the facility.

I’m using the Adafruit breakout board for the WiFly so I had to solder the two 10-pin sockets that mate with the WiFly, and also (because I’m not using a 5V supply and therefore don’t need the level convertor chip for the data lines) jumper the Rx data line from the WiFly socket to the data connector. Because I knew you’d be looking I did that with a short length of signal wire. If you’re a classless bodge-merchant with no moral compass and skanky socks you could probably get away with a big blob of solder on the back of the board.

 

Adafruit Breakout Board Detail

Two pins connected together on the Adafruit WiFly breakout board

 

I also made up a cable loom to connect the Mongoose to the WiFly. Three wires only needed, but I’ve connected the Tx data line too, for future expansion I guess. The wires go:

  1. +V from the 3V3 pin at the Mongoose connector to the 3V3 pin on the WiFly breakout
  2. Gnd on the Mongoose to Gnd on the WiFly
  3. Tx (data) on the mongoose to Rx (data) on the WiFly

Sadly because of the way the pins are space there isn’t an easy way to do this with a 3 pin socket, so there’s a lot of white plastic involved for the number of connections. Hey-ho.

I discovered the plastic film on the outside of the LiPo cell is very fragile, so I wrapped it in some PVC electrical tape. I also taped the Mongoose to the cell and used a couple of wide elastic bands to secure the rest of the unit together. That means I can strip it apart (to take photographs of the bits, for instance) without too much trouble. Also I reinforced the cable from the LiPo at the point where it leaves the cell with some Sugru (in the manner of a strain relief gland) as I heard that’s a common failure point.

 

IMU Hardware Assembled

The IMU platform, assembled. The Mongoose is on the left, the WiFly at the top of the picture. The whole thing is strapped to a LiPo cell which powers the Mongoose via the red and black wires. The connection between the Mongoose and the WiFly is via the white connectors and the wire bundle visible at the front edge.

 

Finally I’m holding the thing together with some broad elastic bands, the kind that our local greengrocer uses to tie together heads of broccoli for sale. Pure class, this project.

Leave a comment

Filed under Hardware

Configuring the WiFly module

The RN-XV WiFly module is for the most part a TCP/IP to serial convertor. We use it to be able to stream data from the AHRS to the iPad or tablet. If you want a serial cable connection or a USB connection you don’t need the WiFly module at all. However all the sofware for the iPad that I want to use requires a WiFi connection, so that’s what I’m using.

Overall I found configuring the WiFly module the most unsatisfying part of the whole project. I found it very hard to get the right settings to “stick”, and have on occasion found it nearly impossible to connect to to see why it wasn’t working. The good news is that once it starts to go it seems to keep on going. So I’d give it 4 out of 10 for ease of configuration, but 9 or 10 out of 10 for reliability in the field. So far.

You can find the full instructions for what it can do and how to set it up via a link at the Sparkfun website; here I’ll give a summary of the commands you need to apply. To be able to connect to the XV in the first place I used the ad-hoc networking mode, which you can invoke by powering up with PIO9 pulled high. PIO9 is connected to pin 8, and 3.3V power is at pin 1 which is the pin with the square pad on top. Pin 8 is the one three from the end of the same row. Short those two together with something at power up and look at your list of WiFi networks for a device called something like WiFly-GSX-51. The last two digits will be different in your case.

Associate to it then wait a minute for your laptop to self-assign an IP address on this ad-hoc network. Eventually you should be able either to telnet to the device (address 169.254.1.1 port 2000), or I had more success with Netcat.

nc 169.254.1.1 2000

I’d like to provide you with a transcript of a session where the WiFly is configured but the WiFly I have seems to have a strange quirky mode where instead of acting on any configuration commands it simply echoes them back to the console in a dumb and insolent manner. So I’m recreating this list from memory, the entries after the # are my comments, you don’t need to type them; I hope you have better luck than me (I did say they were temperamental to configure!)

$$$     #enter command mode - should see a response CMD
set wlan join 4     #create an ad-hoc network
set wlan channel 1     #some channel no. required for ad-hoc mode
set wlan ssid Wifly-GSX-01     #can call it what you like, but existing sofware requires Wifly-GSX-xx format
set wlan tx 6     #reduce broadcast power to save battery and reduce regulator load
set uart baud 115200     #baud rate to match Mongoose etc.
set ip address 169.254.1.1     #required by software
set ip netmask 255.255.0.0
set ip dhcp 0     #don't try to use DHCP
set ip protocol 2     #expect incoming TCP connection. If you want to try UDP, set this to 1, or for either, use the value 3
save     #store configured values to NVRAM - don't forget this or you'll have to start over
reboot     #hope that it all worked.

Once you’ve correctly configured it you should be able to:

  • Power up the device from cold
  • Associate to it via the WiFi SSID Wifly-GSX-xx
  • After a few seconds telnet or nc to 169.254.1.1 on port 2000 (very much as you did when you pull pin 8 high at powerup)
  • Receive data from the Mongoose or ArdIMU

Leave a comment

Filed under Software

How does the code work?

Let’s move on to the more interesting parts of this project: turning a circuit board with some sensors and a microprocessor into a thing that can tell which way is up, and which way is North.

The sensors on the board tell us three things:

  1. The gyroscopic sensors tell us how fast we’re rotating about each of three different axes
  2. The accelerometers measure the local acceleration. That’s usually (but not always) the force of gravity
  3. The magnetometers measure the local magnetic field.

There are lots of ways to describe how we put this information together. The thirty-second explanation is this: we’ll integrate (mathematically) the rates-of-turn about the three axes to tell us the angles we’ve reached, we’ll assume that the local acceleration averages to “down” to correct errors in the integration, and finally we’ll use the magnetometer data to tell where North is.

At this stage I’m going to point you towards this document written by William Premerlani. Premerlani is a leading light amongst hobbyist designers and builders of autonomous aerial vehicles and he’s written a very clear explanation of the basis of how an AHRS works. You can find out more about what he does at his page on the DIYDrones website. If you follow it through you should get a good understanding of what the Direction Cosine Matrix is and how it connects to our problem. Building and maintaing an accurate DCM is the problem our software has to solve.

The software that I’ve worked on started with code that implements a version of what he (somewhat inaccurately) describes as the “Direction Cosine Matrix algorithm”, and itself is based on theory described in some academic work by Robert Mahony. If you’re interested in some of the theory I also recommend reading some of Sebastian Madgwick’s works, such as this one.

If you’re using the Mongoose board you can download some sample software that implements the “DCM algorithm”, and that’s in fact what I started with. Over the last month or so I’ve extensively rewritten and refactored the code to make it clearer and to implement some different algorithms, but it maintains the same flow structure.

Among the differences I’ve implemented are the following:

  • I’ve added some C++ classes to represent matrices and vectors, so matrix multiplications, rotations of vectors, dot- and cross- products and the like can be done in a single line. That reduces a lot (all?) of the clutter.
  • Mahony (and Premerlani, by extension) advocate a proportional & integral (PI) feedback mechanism for roll and pitch stability; Madgwick prefers a fixed feedback. I also prefer the fixed rate roll and pitch feedback, with some caveats, as it is more appropriate to our requirements (I can say more about why, later.) We can therefore talk about a fixed “slew rate” at which we reorient our vertical vector, rather than a rate that’s proportional to the error.
  • In order to minimise the sensitivity to lateral accelerations we want to reduce the slew rate as much as possible. Since the slew rate is what corrects for gyro drift we must make the gyro drift as low as possible. I choose to measure and store in EEPROM the null output from the gyros at startup time which requires the unit to be absolutely still. (In order to allow for warm-starts, if motion is detected then previously stored null output values are used instead.) I also model the temperature dependence of the null outputs as a linear function of the gyro chip die temperature and include correction for this. The gyro drift measured experimentally is reduced to a maximum of 7 degrees per minute over a range of temperatures from -10 to 50C, so the slew rate is set to double that, or 0.004 radians per second.
  • I include code that makes it straightforward to calibrate the gain of the gyroscopes, so that a real rotation of (say) 10 degrees is correctly measured as exactly 10 degrees.
  • Output is in a format comptible with the Levil G Mini, as well as an optional JSON format.
  • Since the Mongoose includes a barometric pressure sensor on the board the code calculates the pressure altitude and the rate of climb.
  • I’ve included a Kalman filter for the magnetic heading. This is a big topic, and I hope to write some comments on why, and how, later.
  • You have the option, by setting a compiler constant in the code, to choose one of two basic modes: in reorientation mode the unit calculates its orientation at startup time and measures everything relative to that. In other words, straight-and-level is defined as how the unit sat at startup. If it was on a 45 degree bank, or a 30 degree pitch – or some combination – that’s the “new straight”. So you don’t have to worry about how the AHRS is mounted. Alternatively, non-reorientation mode means measure angles relative to the circuit board where that is. (More accurately, it means measure the angles relative to the internals of the sensor chips – which might not lie quite flat on the PCB. That brings up another topic of sensor misalignments and their effects, something I also hope to cover later.)
  • Calibrating the magnetometers to get an accurate measurement of north is another big topic, which has been exercising me for the last couple of weeks. For now, I include code which gives you information from which you can externally calculate the correct values to insert into the code to get good measurements. That, too, is a topic for later.
  • Most of the code is functions which read the sensors. This is effectively library code and has been copied more-or-less complete from other similar projects under the terms of the various licences, such as the GPL. The bit that does the interesting work, is quite short – a couple of pages perhaps.

There is a question about the best way to represent rotations, in the code. Some say that quaternions are better than matrices, and some say that matrices are better than quaternions. If you’re not sure about what either of them are, don’t worry about it. If you know only matrices, quaternions are another way of representing a rotation in space with a set of numbers. A rotation matrix has 9 numbers (and six constraints), and a rotation quaternion has 4 numbers and one constraint. You can switch from matrix to quaternion and back with some trigonometrical formulae and anything you can do with one you can do equally with the other. The differences come down to speed (number of basic operations) and numerical accuracy. Wikipedia has a good comparison. It turns out that quaternions are faster for every operation except calculating rotations of a vector; matrices use half as many operations for that. Since most of the work with rotations we do in the code are rotations of vectors it makes sense to use matrices. Quaternions sound sexy and exotic but actually once you’ve worked through the algebra they’re just as dull as matrices.

3 Comments

Filed under Software