At O’Reilly’s Solid conference, I presented an introduction to using inertial sensors. In the talk, I passed around a hardware demonstration to illuminate accelerometers, angular rate sensors, and magnetometers.
The device is "hello world" for inertial sensors so I keep rebuilding the code for different processors and inertial measurement units (IMUs). The platform I want to show today is a Freescale Freedom KL05Z (FRDM-KL05Z) with a sensor toolbox shield (FRDM-STBC-AGM01). element14 member manjuprasadb came up with a nifty DreamBoard with his PC64, and I thought the combination of Freescale's Freedom board KL05Z and sensor toolbox would be a close match to the PC64 specs.
The KL05Z processor is a Cortex-M0+. The $13 dev board is laid out similarly to an Arduino (though as it runs 3V, not all shields are compatible without additional hardware). The system is mbed compatible so there is a free online compiler with lots of great examples.
Happily, the dev board comes with an accelerometer and RGB LED and already had the first part of the demo implemented in its power up code: accelerometer XYZ measurements show up on the RGB LED. When the accelerometer is sitting on the desk, it shows a steady light. If it is flat, the light is red (X-axis), green (Y-axis), or blue (Z-axis). Motionless, it provides a nightlight.
(Well, my code does. The onboard code was a little sensitive to vibration: it flickered more than I appreciated. Still, using Freescale’s demo code you get the idea: hello world for accelerometers.)
This nightlight is a great reminder about what accelerometers measure. Sure, obviously, accelerometers measure acceleration. In space, that's all they would measure. But I don't get to spend a lot of time in space. On Earth, accelerometers measure the constant pull of our planet: gravity!
If you were in one of those carnival spinning rides where you can walk on the walls, the accelerometer would measure the centrifugal force you feel, pulled against the wall. It would also measure gravity. Zooming around in your car, you can measure acceleration (cloverleaf onramps are a pretty fun place to gather data). But the sensor will also measure gravity. Most accelerometers spend 90% of their lives saying which way is down.
Turn on your Freedom board and see the glowy light for what it is: Newtonian mechanics at work.
To get beyond accelerometers, though, I added the sensor toolbox Freescale board. It has a 3-axis gyro (FXAS21002C) and a 3-axis accelerometer/magnetometer combo (FXOS8700CQR1). It has all the pieces needed for a nine degrees of freedom (9DOF) IMU. There is mbed example code to demonstrate the sensor output. It prints to the debug serial port.
Is it obvious from the serial output that I picked up the system and turned it over? If you'd seen the LED, it might have been clearer. Numbers are great but sometimes they are too detailed, making it hard to think about algorithms and big patterns. (Also, there was that time I had byte-swapped my magnetometer input and didn’t figure it out for an absurdly long time because I didn’t look closely at whether the result made sense, focusing too much on the output being repeatable.)
Now that I have drivers for the sensors (developing code using other people’s libraries makes it fast!), I made sure my accelerometer nightlight still worked as intended. I updated the onboard RGB LED code so it changed color more smoothly (using my SmartLed class from another project).
Finally, I added a button to the A5 (arduino pin number) so I could have different modes: I have plans beyond the accelerometer colored nightlight. I wanted to shed the same light on the gyros.
Wait, that's a misnomer. Gyros have spinning wheels that resist turning in the other axis (providing gyroscopic stabilization, the same thing that keeps a top spinning on a point). We can measure how much force the gyro is experiencing and relate that to how fast it is turning in its other axis.
MEMS gyros like the FXAS21002C on the sensor toolbox board aren't really gyros. We call them that because the also measure how fast an object turns. However, as they don't resist the motion (they don't provide gyroscopic stabilization), these sensors are more properly called angular rate sensors. Most people don’t bother with the distinction anymore but pedants care a lot.
Like the accelerometer nightlight, my code maps the rate sensor readings in X to red, Y to green, and Z to blue. In gyro mode, when I put the device on my desk, it is dark.
See, gyros are boring unless you move them. If I spin the device around, it turns blue. It’s more interesting if I wave hello: moving my forearm back and forth at my elbow, it glows red (X). And if I wave my hand up and down (like a baby), it glows green (Y). It is easy to think of turns and angular rate in terms of circles, thinking about spinning around in your desk chair. However, any turning motion, such as around any joint, causes the rate sensor to report the motion.
Gyros (rate sensors) are great for gesture recognition. If you build this device, give it to your designers, then ask them what colors they want for the gestures, the conversation becomes much simpler.
The last mode is the North Star mode to show off the magnetometer. Where accelerometers give you the Z direction of down (and you can figure out up from down), magnetometers give you another axis to orient yourself with.
Magnetometers are not only prone to temperature errors, they react to magnets, metal, and electromagnetic waves (such as that BLE radio you put on the same board). Some of these can be calibrated out. Have you ever done that figure eight thing with your phone? It shows the Earth’s magnetic field to all three axis of the magnetometer. Then the code can figure out how to match what it is reading with what it knows to be true. Voila: calibration! [Note: some steps left out.]
In magnetometer mode, my device shows white when north, green when east, off for south, and green for west. It is a light compass.
Finding heading is not exactly simple. With the accelerometer and gyro, I only had to scale the measurement to a range that made sense for my LED. Heading is more complicated, it isn’t a straightforward measurement from the magnetometer.
To that end, I highly recommend reading Adafruit’s Kevin Shaw’s 9DOF code to get a better sense of what is involved. One of the first things you’ll in the function magGetOrientation is a switch statement.
Before we get to the trigonometry, as this code shows with SENSOR_AXIS_X, you have to answer the question of what you measuring with respect to. The inertial sensor doesn’t read what the system is doing: it reads what the sensor is doing. Another way of saying this: the body frame is different from sensor frame. You can use matrix math (orientation matrices) to convert between them but you need to know the relationship between the sensor and the thing you want to sense. How you mount the sensor to the robot/car/drone matters.
When we get to the North Star (magnetometer) mode in my device, I like to emphasize that just because the light box is pointed north does not mean that you are pointed north. All of the sensors are like that (and it can cause problems if you forget it).
When I worked at Crossbow, making one of the first MEMS inertial measurement units on the market (circa 2000), we sent a unit out to a well-known auto testing magazine. They drove it around their track (closed course, professional driver, naturally). They sent back data that made no sense. I’d had the unit in my car for a while; I knew it had shipped in good condition. The data wasn’t indicating any breakage (other than the nonsense it spewed). Our head of QA flew out to see the customer and I was on standby for a flight the next morning. Just after he landed, he called and told me to cancel my flight. I was surprised as he’d been with the customer for mere minutes. On the other hand, he was right: once he bolted the unit down, it worked exactly as it should. Until then, the 1 pound device had been tumbling around the backseat, experiencing plenty of interesting forces.
Now, back to the math. The arctangent snippet above is the trig you need if you are calculating heading with only the magnetometers. However, that’s a terrible idea. It means you have to keep your magnetometer level to get a result. That’s difficult. Any mistake in levelness leaks errors into the heading calculation.
The Adafruit fusionGetOrientation code shows a different way to do the calculation, using the accelerometer readings to calculate the roll and pitch of the device. Then it uses these tilt values to calculate a heading that doesn’t depend on the device being level. Tilt-compensated magnetometers are much more accurate.
This is so common that magnetometer-accelerometer combination chips are becoming ubiquitous (such as the FXOS8700CQR1 used in this project). My light uses this tilt compensated heading to guide you.
That’s my demo unit: a hello world for inertial sensors. You can build it pretty easily. You’ll need:
- Freescale Freedom KL05Z (FRDM-KL05Z)
- Sensor toolbox shield (FRDM-STBC-AGM01)
- Connectors: stackable headers or you can use male board connectors
- Momentary button for mode changes
- Case (optional)
Solder the headers on to the Freedom board (note: this is easy soldering, just headers, don’t fear the soldering). You can use stackable headers so your Freedom board is more flexible in the future. Alternatively, you can use the male board connectors (Note: either way put the pointed pins away from RGB LED side of the board).
Next, install the sensor toolkit shield by fitting it on the connectors you soldered on.
Attach the button. I put mine on long wires so my button is easy to access from outside my enclosure. My enclosure is a frosted plastic box. I hot-glued the board in place inside the case and the button in place on the outside.
The container doesn’t matter. In other iterations of this device, I have used a tennis ball container (with paper taped to the outside to diffuse the LED) and a hard, clear plastic box (again with paper to diffuse the light).
To put the code on the board, connect the Freedom board to USB. This will enable you to create an mbed developer account and tell it what kind of processor you have. Import the hello world code. Compile the code, download the binary and drag it to the drive that represents the Freedom board. This programs the board with the new code and resets.
Initially, the system will have no LED running though it will be outputting IMU data on the serial port available from USB (115200, 8, None, 1).
Press the button to go into accelerometer demo mode.
The LED will come on and tell you upon which axis it feels gravity (red = X, green = Y, blue = Z). As you move it, the LED will change. If you jiggle it, you can see the light change in intensity. A gentle toss up might lead to a dark sensor at the top of the arc (free fall!). And if you tap on the device, you will likely see a brighter flare of the LED: accelerometers do really well with tap detection.
Press the button again to get into gyro demo mode. The LED will go off until you turn the unit. Spinning it around one axis is the obvious mechanism. But try swinging it back and forth in different direction. Look at the joints on your arm, what colors do you see when you move (and how consistently)?
Press the button again to go into the North Star mode. Remember, it might light your way home, but only if you and it are pointed in the same direction.
(Another button press will go back to no LED. Then it will cycle through again.)Inertial sensors aren’t magic. They aren’t as simple as toggling an IO pin but their complexity adds value to a device. Inertial sensors make movement an interface, giving users an intangible but understood force to work with, going far beyond keyboards and buttons.
We understand that printing hello world on a computer or blinking an LED on an embedded system is only a starting place. This light box is also only a starting place. There is so much more to do with inertial sensors.