Accelerometer Calibration IV.1: Implementing Gauss-Newton on an ATMEGA

This is the third post in a series.  

  1. Introduction
  2. Simple Methods
  3. Least-Squares and Gauss Newton
  4. Implementing Gauss-Newton on an ATMEGA (this post)
  5. Error Analysis
  6. ?

Quick Summary

This post is short on explanations, I just wanted to something a bit more useful out. We can implement the Gauss-Newton method directly on an Arduino using this sketch to drive a circuit with an ADXL 335 and two pushbuttons like this:

Two button circuit used to calibrate an ADXL335

Once the circuit is wired and the sketch is uploaded, open the serial monitor and move the thing around to 6 or more distinct positions.  In each position push the button on pin 2, and hold it still for a second (or until you see the reading print out on the serial monitor.  After you’ve collected at least 6 readings, push the button on pin 3 — this will perform the optimization and print your parameters.

See how I do it in this very fuzzy video:

Some details

In the last post we saw how we could use the Gauss-Newton method to use any set of sample reading from a still accelerometer to get an accurate calibration.  The big problem was the tediousness.  We took measurements on an arduino, sent it over the serial connection to a computer, ran scripts on the computer to compute calibration parameters, then reprogrammed the Arduino with the new parameters.  Sure most of this could be automated, but it would still require a serial connection to a “real” computer with more than 1K of RAM.

To fix this, we need to implement Gauss-Newton directly on the arduino, but the ATMEGAs 1K to 2K memory limitation makes this challenging.  We simply cannot store the big matrices used in the intermediate calculations of the Gauss-Newton method.  To get around this, we do two things.

  1. To reduce the number of data samples we need to store without losing too much information about  the distribution of samples, we let the accelerometer sit in each position long enough to collect a few samples (I picked 32), then we average them and computed the variance.
  2. We never materialize the large matrices, instead just compute the smaller matrices on the fly when they are needed.
There are a few other tricks I use to improve the data quality, and I’ll go over all of the details in the next post where I plan to walk through the code.

Even though it is handheld and held by a hand that had too much coffee, this process gives highly repeatable results.  I performed this calibration 20 times and recorded the parameters produced.  You can see the data in this spreadsheet.  The summary is this: the zero-G parameters on each axis has standard deviations less than 0.03% and the sensitivity parameters all had standard deviations less than 0.2%.  Accurate?  Maybe 🙂 Repeatable? definitely.

On-Arduino Gauss-Newton Calibration Overall Grades:  Accuracy – Great  Easiness – Great 

In the next post I’ll explain the details behind all of this, then move on to error analysis, saving parameters in EEPROM, and more.

This entry was posted in Electronics, How To and tagged , , , , , , . Bookmark the permalink.

13 Responses to Accelerometer Calibration IV.1: Implementing Gauss-Newton on an ATMEGA

  1. Thanks! This saved my day. I got some way-off readings on the X- and Y-axes of my ADXL335 (almost 300 mV difference between 0 G on X and Y) but using this calibration scheme made everything work like a charm.
    I’ll buy you a beer if I see you on the slopes somewhere 🙂

    • Great, I’m glad it worked for you — especially with a 300 mV difference. I’ve seen a lot of variation in ADXL output, but never anything like that.

      One of these days I’ll make that code pretty and add a few more features (first on the list: I want to dispense with the button pressing and have it automatically determine when it is still in a new, “interesting” position.) But for now, the snow is falling so I think my free time is about to disappear 🙂

      I’ll look forward to that beer!

    • These are the calibration values I get – and they are correct. At least I now consistently get readings from -1 to 1 G in the appropriate orientations:

      399.9272155, 638.5637817, 517.5350341, 0.0095106, 0.0094931, 0.0096375

      The sensitivities look fine but the midpoints on the X and Y axes are waaay off. Maybe the unit is damaged. Anywho – it works now and we’ll see what the other ADXL units report when I get everything assembled.

      • Those X and Y values are pretty wild — per the datasheet they should be between 460 and 560 so technically it may be defective (I don’t know what else is going on in the circuit). But if you get consistent readings measuring gravity at 1G, it’s not broken too badly.

        With those sensitivities, you still have plenty of room to record more than 3.5G on each axis, should be plenty for the RGBTumbler.

        By the way, I think I’m going to mimic your buttonless calibration; it looks simpler and easier. I’m new to the electronics world so I only know how to do a few things and buttons are one of them.

      • You can find the code for the buttonless calibration I use here:

  2. Juan says:

    Thank you very much!!!

    • You’re welcome — a word of warning though. I’ve recently found the optimization routine can be numerically unstable for certain input streams (coming from ADXL 345 accelerometers and HMC 5843 magnetometers — I haven’t had trouble with the ADXL 335). I’m working on a more robust solution that I’ll put out as a C++ library. Hopefully I’ll have this in the next couple of weeks.

  3. ItsLeeOwen says:

    Rolfe, you are a sensei of sensors! Well, thank you for the fantastic & informative articles.

  4. Pingback: Implementing the Gauss-Newton Algorithm for Sphere Fitting (2 of 3) | Chionotech

  5. rmackay9 says:

    Thanks for the great work on building and explaining so clearly your calibration method. I’ve incorporated your accelerometer calibration routine into the DIYDrones ArduCopter and ArduPlane libraries (slightly modified). I’ve credited you a few times in the .h and .cpp code so people know for sure it’s originally from you. Is this ok?

    • That is great — I’m glad to see it getting used, thanks!

      As I’ve been playing with other devices, I’ve realized that there are a few improvements that should be made to this particular sketch to get it working better with other sensors (this was fairly ADXL335 specific). When I get a chance, I’ll look through what you have and point out the changes to make.

  6. Nyein Aye says:

    Thanks for your great post. Really appreciate your works.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s