Heading from magnetometer, bogus(?) data (with 3d plot)

Hi, new to the forums and it looks like a very active community!

I have been trying to get heading out of my LSM303DLHC magnetometer chip, playing around with output data and different tilt-compensated methods etc. etc. I continuously got heading data which would be semi-accurate (accurate to changes in heading, not absolute) for some portion of the 360 degree revolution then go completely nuts.

I started plotting the raw data to make sense of what why this was happening which I'll show in an image. First though: magnetic field information. Where I am from the declination is 8° (not really important at this stage) and inclination is 67° (this seems oddly high to me? Maybe this is why getting heading is so difficult where I am?). Anyway, here are the plots:

  • The first plot shows the RAW DATA output from the magnetometer in the x and y directions.
  • The second plot shows each channel of the raw data centred around its average point (simply shifted up or down). Eg. x max = 20000, x min = 10000, avg = 15000, so shift down 15000.
  • Third plot shows heading from the shifted channels.
    So you can see that my heading from these isnt too bad, calculated simply using the ATAN2 function. The problem arises when I apply the 'shift' value (15000 in the example) in the code. The shift value seems to be very very sensetive each time I run the arduino. Even in the example above you can see that some of the values are out (Eg. at approx 65 seconds in, we see a heading change of approx 200° when in reality it was only a 90° turn.
    This led me to plot the raw data on a 3d scatter plot which is shown below (this is the calibrated data now). You can clearly see that it is well calibrated, a nice sphere centred on the origin. The data points in the bottom right shows the progression of points when I sit the chip flat on the table and rotate it. (Black lines hand drawn to show rough path). Things to note are that it is not centred around the z axis, hence why the shift I did in the earlier graphs worked so well! I also noted that it is an awfully small circle (due to the inclination angle of hte magnetic field? but even that is 70 degrees which should result in a larger circle than the one shown...
    One thing this magnetometer does damn well though is NOT drift. you hold it steady and that red dot is not creeping anywhere!

You are on the right track! Without your code, it is impossible to know what you are actually doing, but the inclination doesn't matter as long as the magnetometer is held horizontal. A value of around 67 degrees is correct for mid latitudes in the North America.

All magnetometers need to be carefully calibrated to be useful. Most people use simple axial min/max scaling, but that doesn't work in many cases. See my recent post on the Pololu forum for a particularly difficult case (and some possibly useful programs).

For a general overview of magnetometer calibration, see this detailed blog article

Thanks jremington, it looks like you have a lot of experience with this!
My project is actually designed for university students learning to do autonomous code. Needing a heading is needed for this, and so I need to do the calibration for it so they can pick it up and run along. Obviously this wouldnt work because every chip needs to be calibrated differently, so I built a tool so that you could visualise the raw magnetometer data in real time (the 3d plot you see in that image, threaded). Its funny you should mention that article, because it mentions this blog:

which I actually grabbed the source code from (from magneto). And applied to the application so you could also see the calibration in real time (threaded). Generally the calibration values begin to stabilise with around 3000 data points from the magnetometer.

Anyway, just in case, here is my code for the tilt compensation as well as the heading calculation. I am certain the tilt compensation is correct (as I can visualise it on the 3d plot, when turning the chip, the magnetometer direction stays steady). accAverage holds the accelerometer data point (calibrated with weighted moving average for smoothness), similary for magAverage.

// tilt compensation
                double pitch = Math.Atan2(-accAverage.X, Math.Sqrt(accAverage.Y * accAverage.Y + accAverage.Z * accAverage.Z)); // y axis
                double roll = -1 * Math.Atan2(-accAverage.Y, Math.Sqrt(accAverage.X * accAverage.X + accAverage.Z * accAverage.Z)); // x axis

                Point3D magCompPitch = new Point3D();
                Point3D magCompPitchRoll = new Point3D();

                // due to pitch (rotate around y axis):
                magCompPitch.X = Math.Cos(pitch) * magAverage.X + Math.Sin(pitch) * magAverage.Z;
                magCompPitch.Y = magAverage.Y;
                magCompPitch.Z = -Math.Sin(pitch) * magAverage.X + Math.Cos(pitch) * magAverage.Z;

                // due to roll (rotate around x axis):
                magCompPitchRoll.X = magCompPitch.X;
                magCompPitchRoll.Y = Math.Cos(roll) * magCompPitch.Y - Math.Sin(roll) * magCompPitch.Z;
                magCompPitchRoll.Z = Math.Sin(roll) * magCompPitch.Y + Math.Cos(roll) * magCompPitch.Z;

                double heading = Math.Atan2(magCompPitchRoll.Y, magCompPitchRoll.X); // radians

The only thing I can think to improve anything is to get a proper gimball rig and accumulate more like 20,000 data points. Is this really what is necessary for any kind of accuracy out of a magnetometer? My chip is beside a microcontroller, would that have enough of an impact on the magnetic field? (is far away from computers and batteries though! :D)

I have realised basically what I want is for my tiny circle (bottom right picture of my image i posted, which is created when i revolve the magnetometer around on a flat surface) to be centred around the z axis. As for why the circle is so tiny...

  • it probably has an internal angle of 10 degrees to the origin, when in reality it should be [(90-67)*2]=46 degrees (from the angle of inclination) (WOW, if I had that it would be so much easier! haha)
    ... maybe the microcontroller (or laptop, or maybe its just the building?) next to it is almost pushing the magnetic field into a more vertical orientation. maybe turning this 90 degrees would try and push it to a more horizontal orientation and therefore give me more angle to work with, i dunno, just a thought.

The only thing I can think to improve anything is to get a proper gimball rig and accumulate more like 20,000 data points. Is this really what is necessary for any kind of accuracy out of a magnetometer?

Not at all. In my experience using magneto with 200 data points well distributed in 3D angle space is more than enough.

If you look at the noise level from the magnetometer, you will never be able to do better than about +/- 1 degree absolute accuracy in heading, and local environmental effects like hard and soft iron distortions will degrade that substantially.