HMC5883L - what are we actually measuring ?


I got an Arduino for Christmas with the 10DOF GY-88 (the HMC5883L is part of it) and problems are coming ! So, this is my first big problem and my first post ! I hope you'll have the time to help me.

I'm re-coding a library to be able to use the magnetometer, in order to be sure to understand perfectly what I'm doing. Everything is fine with the code, but there is something I cannot explain : I'm assuming that the quantities I'm measuring in x, y and z are the magnetic intensity in those directions, so I would like to check that x²+y²+z² is constant when I move the sensor (if there are no disturbances of the earth's magnetic field), but it's not the case at all !!! this norm is varying a lot when the sensor moves. And it's not simply noise due to the movement : the norm stabilizes at another value. I get a norm varying between 500 and 1500 (computed with the raw value I get) which is quite a lot...

I've got two hypothesis : - The answer of the sensor is not linear, maybe affine ? - The basis (x,y,z) of the sensor is not orthogonal

I tried to measure the maximum and minimum value for each axis, and I supposed the answer linear between those values. It's a bit better: the norm is varying between 90% and 110% but I'm not satisfied.. and this is not robust at all.. and why such an answer ?

Well, I don't get it. Then what am I actually measuring in x y z ?

I tried with another library, same result.

Thank you guys (and girls !) for your help !

PS: I'm French, so please excuse me for the potential mistakes.

The reason that the magnetometer vector norm is varying as you turn the sensor around (assuming there are no nearby disturbing magnetic fields) is that the magnetometer needs calibration. The gains and offsets on each axis are different and need to be compensated by external corrections.

Here is my favorite procedure for calibrating magnetometers (it works very well for accelerometers as well, as long as the sensor is held still while each data point is taken).

If calibration is done properly then the measured magnetic field strength should have the same magnitude regardless of which direction the sensor is pointing (as it must). In turn this makes a huge difference in the accuracy of directional angles derived from those measurements. In fact, it is in many cases not possible to use inexpensive magnetometers for navigation unless they are properly calibrated.

Thank you !

I did not know I needed to do this, and I did not know how to do it. Looking for "magnetometer calibration", I found These curves are astonishing, it's actually quite precise. It gave me the idea to build a least squared method to find both the center of the sphere, and the coefficients to apply on each axis in order to get a sphere, and not an ellipse. I'll let you know if this work !

bye bye, and thanks again !

It gave me the idea to build a least squared method to find both the center of the sphere, and the coefficients to apply on each axis in order to get a sphere, and not an ellipse.
I’ll let you know if this work !

It will work. That is exactly how the two programs I linked function. However, if you wish to do it all over again, enjoy!

it "should work", you're too confident on me ;) Thank you, It confirms that it's a good method. Yes, I'll do it again because I might be interested to code it in the arduino itself, to be able to calibrate it "on the field". And after all, it will be good to dust those all courses I took about optimization haha Thanks

There is not enough memory in the Arduino , either RAM or program space, to do the least squares fit that is required by the ellipse-fitting method. I doubt if you could do it in 2D either, but here is a MATLAB approach for that:


I did it ! haha.
Ok, so I used a python script to acquire the data, and to run the optimization algorithm : I put the code below, if anyone might one day be interested…

Here’s the points I got :
It’s really an ellispsoid.

At the beginning it did not work, because 30 cm from the laptop was not enough, there are plenty of disturbances. I understood that when I plotted the points, it was not a sphere ! so please, newbies, be careful when you do this manipulation.

I checked if the norm was constant, and it’s almost perfect !

Thank you guys, bye bye

import serial
import numpy as np
import time
from scipy.optimize import leastsq
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt



print("acquiring data, move the sensor please")
while time.time()-start<delay:
	coords+=[map(float,line.split(" "))]

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')


def fitfunc(p,coords):
	return np.sqrt(((x-x0)/a)**2+((y-y0)/b)**2+((z-z0)/c)**2)

errfunc = lambda p,x: fitfunc(p,x)-1

print p1
print flag