Sensor Smoothing

A project log for Color Compass

Providing humans a sense of magnetoception through our visual field.

Andy OliverAndy Oliver 08/26/2018 at 19:490 Comments

Let's talk about how the program works to gather the heading information for later use to generate colors.

First off, the hard part was already taken care of by the kind people at Adafruit. The compass I used was their LSM303 breakout board. This device has a magnetometer to find heading, plus an accelerometer to find out which way is down (or whatever else you want to use them for). This is important because it allows us (really the Adafruit library I downloaded) to compensate for tilting of the device as it figures out where it is pointed.

By the way, there is no shame in using pre-made libraries. They are great for prototyping, and when you find yourself limited by them, you can then go program your own. There's usually no need to optimize to that level unless you are building something for production in the millions, where moving down to a thirty-cent cheaper microcontroller might save you big bucks.

OK, so given that we have read through the documentation and set up our Arduino to generate compass heading data from the magnetometer, that information can be pretty jittery. One relatively easy (if a little processor-intensive) way of doing this is with something called an infinite impulse response, or IIR, filter. This particular one is an exponential smoothing filter. In short, with this kind of filter, your new "answer" is your last answer and your new input data, blended with some sort of formula. You can imagine that, with each new data point, you still have some factor leftover from old data. That's more or less the "infinite" in IIR.

Here's how it looks in the code:

// Load up new heading components with smoothed values.
newHeadingX = ALPHA*event.magnetic.x + (1-ALPHA)*oldHeadingX;
newHeadingY = -ALPHA*event.magnetic.y + (1-ALPHA)*oldHeadingY;
// Store the new headings under the old headings for future smoothing.
oldHeadingX = newHeadingX;
oldHeadingY = newHeadingY;

You can see there that I'm generating X and Y components of the compass heading to convert to an angle later. I smooth each component as it comes in with the formula seen in the second and third line. ALPHA is a number between zero and one defined elsewhere that serves as our filter constant (a larger number here is less filtering).

Since ALPHA is a decimal, all these numbers are floats. We could do some integer math here -- basically like considering ALPHA as a percentage, or like talking about cents instead of fractions of a dollar -- but I'm not doing much else with the Arduino in this project, so floating point math is just fine for now.

That said, I hope to refactor this project to use the FastLED library to generate nicer colors, and FastLED uses the byte as its main data type, so I could likely write all or part of the program using integer math. I'll have to think on that one...