LSM303DLM compass readings way off

I have the carrier board mounted upside down as in the picture on the MiniIMU-9 page, so I negate the Y value prior to the arctan calculation. I am getting consistent and repeatable readings, but when I rotate 90 degrees, the reading only rotates about 30 degrees. I am ignoring the Z value because the platform doesn’t tilt. I have maximum sensitivity (1.3 gauss) which is utilizing about 9 bits of dynamic range. Here are the readings I get:


actual calculated raw values (x, y, z)

North 136 (-356, 342, 513)
East 179 (-519, 14, 481)
South 215 (-169, -118, 559)
West 103 ( -46, 203, 556)

I also tried turning on the accelerometer to see if it needed to be enabled for the compass to work properly. No difference.


Hello, Jim.

It sounds like you might need to calibrate your compass. I am not sure what you are using to communicate with the MinIMU, but our LSM303 library has a Calibrate sketch for the Arduino that you might use. If you do not have an Arduino, you could still get a general idea of how to calibrate the compass by reading through the GitHub description and Calibrate example. If you have tried calibrating your compass and still do not get your data to work, can you post your code and a sample of your raw data?

By the way, you should not need to turn on the accelerometer to get the compass to work properly.


There are much more accurate procedures for calibrating these compass chips, which can take into account local distortions of the magnetic field. For example I’ve used both the methods described on this page with excellent results: … ation.html

The methods also work very well for accelerometers provided that you hold the carrier steady while each data point is taken. My approach was to write a little program that dumps the raw values over the serial port, and import these directly into a file suitable for input to Magcal.

Use of procedures like this are absolutely necessary if you want to get the best possible orientation data from accelerometers and magnetometers and should be performed after the carrier is installed in its final operating environment.


Section 5.1 of the LSM303DLM data sheet says this:
“The trimming values are stored inside the device in non-volatile memory. When the device is
turned on, the trimming parameters are downloaded into the registers to be used during
normal operation. This allows the use of the device without further calibration.”

Does that only pertain to the accelerometer? If not, are we doing additional calibration for local geographic differences? And if that is the case, does this need to be repeated every time I take my robot on the road?

I have the Arduino example code. Basically I should take lots of readings, determine the min and max possible values for each axis, then subtract the average of them from all readings. I will also read the paper suggested by Jim Remington. As my robot intends to stay perfectly horizontal at all times and moves very slowly, I hope I am safe in assuming I can ignore the Z axis altogether, as well as the accelerometer readings, and just do a simple arctan(y/x) calculation (with quadrant correction of course).

So why are the raw Z readings the highest? Is there a greater magnetic field toward the center of the earth than toward magnetic North?

Thanks for all your help, I’ll let you know how the calibration goes.

In the northern hemisphere the geomagnetic vector points magnetic north and rather strongly downward, so the Z value is far from negligible when the magnetometer X and Y axes are parallel to the earth’s surface.

In fact, ordinary compass needles have to be counterweighted so they remain level and those designed for the northern hemisphere usually don’t work well or at all in the southern hemisphere. You can look up the direction of the geomagnetic vector at your locale, or with your new instrument, measure it!

On a robot the local magnetic field can be strongly influenced by the robot frame, motor magnets or current-carrying wires, so the magnetometer should be located as far as possible from the motors and calibration should be performed after everything is constructed. Check for changes in the direction of magnetic north with the motors running, too!

Cheers, Jim

Using just the X/Y calibration gets me within 3 degrees accuracy in one location. Then I move the robot to another location a few meters away and suddenly there’s about 12 degrees error. I’ll look more into the Z compensation.

Thanks for all your help. I’m in much better shape than when I started.

You can expect large errors if you can’t keep a 2D compass level. Google “3D compass algorithms” or “3 axis compass algorithms” for more information. The Pololu engineers have provided a nice little sample program that uses the 6D capabilities of the LSM303DLM to create a 3D compass. Try it out, but for best accuracy you want to carefully calibrate both sensors using the Magcal approach.

I’m trying to use MagCal. I don’t have a good way to get a full sphere of data points, so they are mostly 2D, but there is some Z variance. I don’t know what to enter for Earth Magnetic field (Hm). The help has a link to the data to put there, but the link is broken.

You can just enter 1.0 for Hm.

Why can’t you get a full set of 3D data points? I just hold the LSM303 breakout board or whatever it is mounted on, in my hand and turn it in as many directions as possible. My program outputs a data point every second, flashing a red LED when making a measurement, so I know when to stop moving it. It is a bit painstaking.

The 1.0 for Hm assumes a certain normalization for the readings I input? I’ve tried the raw values from the sensor, as well as scaling them by 1/1000 (arbitrary scalefactor, to get them between 0 and 1). I suspect the right thing to do is to convert the readings to Gauss, which according to the register document at max gain, I should divide the X and Y values by 1100, and the Z values by 980. So I’ll try that.

FYI, I don’t see anywhere in the Arduino code that compensates for the different gain on the Z axis.

And I can’t get a full sphere of data collected because the sensor is soldered to a PCB in the middle layer of my robot. It’s a 40 lb. robot and I didn’t anticipate the need to calibrate the compass, so I don’t have an easy way to pull it out on a tether and rotate it around as you described.

If you input a supposedly correct value for Hm, the program outputs a matrix that scales the input measurements so that the output is in units of Hm. Usually, the actual value of the local magnetic field is of no interest and for the purpose of calculating a heading, will be normalized to 1.0 anyway.

The only other situation where it might be important to choose a particular value of Hm or to scale the input values is to retain significant figures in the correction matrix. If I recall correctly, the program from the Canadian research group outputs the correction matrix in fixed point with four digits past the decimal point. If the values of the matrix elements are very small, you lose a lot of precision in making the corrections.

The program from the author of the sailboat instruments web page outputs more significant digits, and is a bit easier to use anyway, because you don’t have to invert the correction matrix. I recommend it.