Sunday, 17 November 2013

Connecting and calibrating a HMC5883L Compass on the Raspberry Pi

Here is how to connect a HMC5883L Compass to the Raspberry Pi, calibrate it and read the data. Connecting the compass is simple enough, follow the steps here which show how to connect a similar I2C device.

Simple Python Code

Some simple code to read the data, calculate a bearing and print it out
When you run the script you'll get something like
    Bearing:  70.0168934781

Calibrating the compass

Well that was easy wasn't it. Well not quite, if you start to rotate your device you might notice the values don't seem right. Start by rotating it until you get close to 0 degrees, then rotate it physically through four 90 degree steps, taking a reading at each step. Continue until you have gone through 360 degrees. Here is my output
    Bearing:  0.292322869229
    Bearing:  89.4543424066
    Bearing:  175.645778937
    Bearing:  266.66908262
    Bearing:  0.298412819995
So what's happening?  We can see the readings are off, but not by much.  Make a change to the code by replacing lines 35-43 with
re-run the program and direct the output to a file. While the program is running repeatedly rotate your compass backwards and forwards through 360 degrees, make sure you keep it flat otherwise you'll get some odd results.
    sudo ./ > compass-plot.dat
Now lets plots the data and look at what's going on, here is a gnuplot program and the command to run it
set terminal wxt persist size 800,800 background '#000000' 

    set style line 99 linecolor rgb "#ffffff" linetype 0 linewidth 2
    set key top right textcolor linestyle 99 
    set grid linestyle 99
    set border linestyle 99

    plot filename using 1:2 title "Raw compass values" linecolor rgb "green" 
Save this to gnuplot-compass.plg and then run the following command
    gnuplot -e "filename='compass-plot.dat'" gnuplot-compass.plg
You'll then be presented with a graph similar to this one

Scatter digram of the raw compass data
We can see that the circle isn't quite centered around the origin, although in this case it's not off by much. My previous compass was off by a much larger value. This plot shows the offset in Y to be about 150.

Scatter diagram of my old compass which had a much bigger offset value

Now we can use this data to calculate the standard offset that we apply to the compass readings to correct things. Replace the for loop in the Python program with

run the program again rotating the compass through 360 degrees. Once the program finishes it will print out the offsets you need to apply to your calculations, these are the values I got
    minx:  -216
    miny:  -193
    maxx:  197
    maxy:  213
    x offset:  -10
    y offset:  10
We are almost done, back to the first program and include the offset in the calculations, changes lines 35-37 to Then re-run the test by taking a reading every 90 degrees of rotation, here are my newly adjusted values
    Bearing:  0.278132667296
    Bearing:  90.0
    Bearing:  180.290839022
    Bearing:  272.501622814
    Bearing:  359.725859606
As you can see these values are much better, there will always be a small variance as the data is a bit noisy.


As you can see it's relatively easy to attached a compass module to your Raspberry Pi, calibrate it and start to get meaningful readings.  Oh and don't have any large metal objects or large bits of electrical equipment close to the compass when testing.