One of the single most expensive components on the Module board is the BNO055 IMU. In single quantities it costs $12 (https://www.digikey.com/product-detail/en/bosch-sensortec/BNO055/828-1058-1-ND/6136309). I, like many others, chose this chip because it has two very appealing qualities - it self calibrates and outputs quaternions. This avoids lots and lots of math on the host CPU; math I mostly don't understand.

However, as I look at moving this module board towards production, the cost of this chip annoys me; especially when I'm designing various projects which don't immediately need an IMU. It increases the BOM costs substantially, while offering little immediate gain.

Because I do want an IMU on this board, I've begun to look at alternatives. In that process I realized the only way to decrease the cost is to do the math on the PI.

There are three sets of math that must be done for a good software fusion IMU:

- Calibration - which turns the raw noisy sensor data into something more repeatable.
- Cleaning - to eliminate poor sensor readings
- Operation - turning sensors readings into usable rotations/quaternions

**Calibration Math**

I've taken a stab at IMU calibration math a couple of times before and ended up abandoning the efforts as the results were not good. There are lots of algorithms which attempt this process, and many of them appear to assume IMUs are far better behaved than they actually are. I eventually found this calibration explanation (https://thecavepearlproject.org/2015/05/22/calibrating-any-compass-or-accelerometer-for-arduino/) by the Cave Pearl Project which uses this tool (http://sailboatinstruments.blogspot.com/2011/09/improved-magnetometer-calibration-part.html) by Sailboat Instruments. Essentially a set of raw datapoint are gather from the magnetometer and accelerometer (each set form an elliptical shape) and maps them into a sphere centered on an origin. The Sailboat tool (Magneto - https://sites.google.com/site/sailboatinstruments1/home) generates this as a vector translation and matrix transformation.

While the Cage Pearl article discusses doing this analysis offline (they're using Arduinos which are not up to the online math), they include a C implementation of their algorithm; one quite capable of running on a Pi.

**Calibration Cleaning**

Just feeding a large set of values to the calibration algorithm will not necessarily get the best results. Ideally you need many points from all orientation of the IMU in order to get the best transformation. Also, because IMUs are noisy devices, they generate outlier values which can confuse the calibration algorithm.

So it is necessary to clean the calibration data before using it to calibrate. To gather a "good" set of points, each point is translated from (x,y,z) form into spherical coordinates (inclination, azimuth); think of this as the longitude and latitude of the point on the surface of a sphere. We divide the surface of the sphere up into a number of "buckets" of approximately equal area, and place each point into the appropriate bucket. The goal for good calibration is to sample enough points and place a minimal number into each bucket.

One the buckets are full, we must eliminate any outliers before passing the points for calibration. Outliers are consider to be any point where an (x,y,z) value is outside 2 standard deviations of the mean. Once removed from out dataset, the resulting points generate excellent calibration data.

**Operation Math**

Using the calibration data, we can now adjust the IMU's raw values to make them usable. However, we still need to turn this data into a quaternion. A quaternion is a 4-dimensional vector which is used here to represent the rotation of an object (https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation).

The best algorithm I found to handle this process is by Sebastian Madgwick (http://x-io.co.uk/open-source-imu-and-ahrs-algorithms/). It takes (x,y,z) inputs from the three IMU sensors...

Read more »