Dynamic accelerometer calibration

Yet more musings about how to calibrate the accelerometer outputs without having to account for temperature shift by doing so each flight.

There are 3 lots of accelerometer readings:

  • rx, ry, and rz are the raw accelerometer readings along Phoebe’s axes – these each have gain and offset errors meaning they live in an non-centered ellipsoid space
  • qx, qy, and qz are the calibrated readings along Phoebe’s axes – i.e. with offset / gain calibration placing the readings in a centered spherical space
  • ex, ey, ez are the calibrated readings in the earth’s axes in the same spherical space but with earth’s axes.

With Phoebe sat still on a slightly sloping take-off platform (let’s call it “the ground”), there are a few assertions that can be made with the above due to the fact the only force in play is vertical gravity:

qx = (rx + rxoff) * rxgain
qy = (ry + ryoff) * rygain
qz = (rz + rzoff) * rzgain

qx2 + qy2 + qz2 = 1

ex = 0
ey = 0
ez = 1

The relationship between q* and e* is defined by the matrix converting between quad and earth axes based upon the angles of pitch and roll.

|ex|   |cos(pitch),         0,          -sin(pitch)||qx|
|ey| = |         0, cos(roll),           -sin(roll)||qy|
|ez|   |sin(pitch), sin(roll), cos(pitch).cos(roll)||qz|

where pitch and roll angles are defined by the accelerometers output also

pitch = atan(qx / qz)
roll = atan(qy / qz)

What I’m wondering is whether there’s enough information here to calculate the r* to q* mappings, perhaps by using some approximations such as the following

  • if the ‘ground’ is only a slight slope, then
pitch ≅ qx / qz
roll ≅ qy / qz
  • as the r* gains are all roughly one, can the r* space be assumed to be spherical and only the offsets need to be derived?  That gives 3 variables and more than 3 equations to derive them from.

I’m pretty certain this is possible as Gustavo pointed me at a calibration algorithm in a comment the other day; the trouble is the details are lost inside some numpy processing, and I’d rather understand those details rather than just use the magic incantations.  Help / guidance much appreciated please.

P.S. Having spent a few minutes looking at the numpy algorithm, it seems to be doing dynamically in Python what I did via my excel spreadsheet – essentially calculating a set of gain / offsets from a set of predefined data – essentially moving the raw data from the off-centre ellipsoidal space to a centred spherical space but applying gain / offsets, which is great from the point of view of reassuring me my approach is correct, but not helpful in getting mine any more accurate.

4 thoughts on “Dynamic accelerometer calibration

  1. So the aim is to work our rxoff and rxgain (etc.) with unknown roll/pitch, but knowing ex = ey = 0,ez = 1

    Combining the matrix and ex = ey = 0,ez = 1 yields (equation numbers in square brackets):

    [1]: cos(pitch)*qx – sin(pitch)*qz = 1
    [2]: cos(roll)*qy – sin(pitch)*qZ = 1
    [3]: sin(pitch)*qx + sin(roll)*qy + cos(pitch).cos(roll)*qZ = 0
    Also [4]: qx² + qy² + qz² = 1

    So we have four equations with five unknowns (qx, qy, qz, pitch, roll). This isn’t looking good….

    Now, you say pitch = atan(qx / qz) and roll = atan(qy / qz)… which means tan(pitch) = qx/qz => sin(pitch)/cos(pitch) = qx/qz => cos(pitch) = sin(pitch)*qz/qx. Similarly, cos(roll)=sin(roll)*qz/qy.

    This lets you rewrite [1],[2],[3] using only sin(pitch) and sin(roll) as follows:

    [1]=> sin(pitch)*qz/qx * qx – sin(pitch)*qz = 1 => 0 = 1 !!!
    [2]=> sin(roll)*qz/qy *qy – sin(pitch)*qZ = 1 => 0 = 1 !!!

    Something’s weird here…

    • Hi Tom,

      The right hand side of your equations 1 – 3 are the wrong way round:

      [1]: cos(pitch)*qx – sin(pitch)*qz = 0 (ex)
      [2]: cos(roll)*qy – sin(roll)*qz = 0 (ey)
      [3]: sin(pitch)*qx + sin(roll)*qy + cos(pitch).cos(roll)*qZ = 1 (ez)
      Also [4]: qx² + qy² + qz² = 1

      That’ll resolve the clash in the math(s)!

      With the typos corrected then

      [1]=> sin(pitch)*qz/qx * qx – sin(pitch)*qz = 0 [tick]
      [2]=> sin(roll)*qz/qy *qy – sin(roll)*qz = 0 [tick]
      [3]: sin(pitch)*qx + sin(roll)*qy + cos(pitch).cos(roll)*qz = 1

      So far, so good. The problem is that qx, qy and qz are ‘corrected’ values from the accelerometer:

      qx = (rx + rx_offset) * rx_gain

      It’s these 6 r* offset / gain values that are needed. Currently I know them by testing, but the fact commercial quads don’t require this level of pre-flight calibration by the user means there must be a better way.


  2. Not sure if it will help you but what I liked in this algorithm is that with it you can use a large data set. Taking in account all quadrants of each axes. Take a look at the real program (http://www.varesano.net/blog/fabio/freeimu-gui-now-making-nice-3d-spheres)… I’m still not sure what happens in that algorithm, but neither had time to look deeper at it. Checkout this video too, this is the recommended way to do the calibration (but using hands) http://www.youtube.com/watch?v=SNM6lB440Z8 or http://www.youtube.com/watch?v=rBe–jC_jUw (its a magnetometer, but I think the principle is the same)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.