Magnetometer Calibration in Robo4J

This article will explain how to calibrate your magnetometer in Robo4J. This will be required if you want to get as precise results as possible from your magnetometer.

Earth’s magnetic field can be distorted in various ways. If there is no distortion, rotating your magnetometer 360 degrees around the  Z-axis would result in a perfect circle (in the XY plane) centered around the origo. If there is distortion, the circle could be offset or even turned into a tilted ellipse.

There are two different type of distortions commonly discussed:

    1. Hard iron
    2. Soft iron

Hard iron effects are caused by a constant additive field, for example by a magnet. As long as the magnet stays put, relative to the magnetometer, the effect will be constant. This is what we call “bias” in Robo4J.

Soft iron effects are caused by materials that can influence the magnetic field, but which do not necessarily emit a magnetic field. For example iron and nickel. These effects are more complicated and typically turn that perfect circle (from the example above) into an ellipse.

Now, since we are dealing with a 3D magnetometer here, we are really talking about trying to turn an ellipsoid at an offset to origo, into a sphere centered around origo.

So, this is how to calibrate a magnetometer in Robo4J:

    1. Gather data from your magnetometer.
    2. Calculate the bias vector and transform matrix.
    3. Use the calculated bias vector and transformation matrix when instantiating your magnetometer.

Getting Data

If you have an Adafruit 10 DOF breakout board, or an LSM303 device, you are in luck. This is the first magnetometer we support in Robo4J, but we will add more devices as we go. This blog will talk about how to do the calibration given this device.

    1. First, clone robo4j from github
    2. Next build and install robo4j:
      ./gradlew install

    3. Next source the script with the environment variables:
      source /scripts/rpi/

    4. Then run the test program, with CSV as output format, and redirect the output to a file:
      java -cp $ROBO4J_PATH com.robo4j.hw.rpi.i2c.magnetometer.MagnetometerLSM303Test 20 1 CSV > /home/pi/magnetometer.csv

It is important that you try to hit as many points as possible, so rotate that thing like there is no tomorrow. I built a simple calibration tool that can help a little bit (but only with one axis). I have been thinking about building a massive one, using three slip rings and ball bearings, but since it would have to be large enough to accept a full sized robot to be truly useful, I know building one would put an unnecessary strain on my marriage. Smile with tongue out

Calculate the Bias Vector and Transform Matrix

This sounds hard, but is rather easy, as we’ve already added a very spiffy application to Robo4J for both visualizing your magnetometer data, and for calculating the bias vector and transform matrix. It is located in the robo4j-tools repo. Simply build and run it with your file as argument.

This is what it will look like when you start it:


If you have some spurious weird values, you may want to filter out the ones that stand out the most. Simply flip the Filter panel open, and click Filter Points. By default the values within 1.0 standard deviation (range from calculated center) will be kept. You can play with the Stddev value to get the result you want.

You can also show what the result would look like if corrected with the Bias Vector and Transformation Matrix, by clicking the “Corrected” checkbox in the Data Selection pane:


The visualization keep rotating so that the points will be shown alternatively from the XY and the ZY axis.

Using the Data When Instantiating the Magnetometer

In robo4j-hw-rpi the magnetometer can be instantiated with a Tuple3f, and a Matrix3f. Simply instantiate the tuple with the values from the bias vector, and the matrix with the values from the Transform Matrix:

Tuple3f bias = new Tuple3f(-44.689f, -2.0665f, -15.240f);
Matrix3f transform = new Matrix3f(1.887f, 5.987f, -5.709f, 5.987f, 1.528f, -2.960f, -5.709f, -2.960f, 9.761f);
MagnetometerLSM303Device magnetometer = new MagnetometerLSM303Device(I2CBus.BUS_1, 0x1e, Mode.CONTINUOUS_CONVERSION, Rate.RATE_7_5, false, bias, transform);


This blog explained how to use the Robo4J MagViz tool to calibrate a magnetometer.