I've got a cmps10 compass module hooked up to my arduino due through a logic level converter. I am writing code to convert the raw magnetometer readings into a bearing that I can use but have run into a huge problem. My bearings are all funky for some reason. They are totally unrelated to the actual bearing of the robot. I know the sensor is fine because I am able to get the tilt compensated reading from it and it works great. One thing I noticed is that the magnetometer reading on the X-axis is always positive could this be the problem? The X-axis high byte generally between 0x00 and 0x03. My code is below (i2cBus = &Wire)


i2cBus->requestFrom(I2C_Address, 4);
xMagHighByte = i2cBus->read();           
xMagLowByte = i2cBus->read();
yMagHighByte = i2cBus->read();           
yMagLowByte = i2cBus->read();

xMag = short(xMagHighByte<<8);
xMag |= xMagLowByte;
yMag = short(yMagHighByte<<8);
yMag |= yMagLowByte;

  magBearing = (atan2(xMag,yMag)*180.0)/3.141592654;
else if(xMag>0) magBearing=0.0;
else if(xMag<0) magBearing=180.0;
else magBearing = 1000;
if(magBearing < 0) magBearing+=360;
return magBearing;

1 Answer 1


Compass modules are highly susceptible to interference from ferrous deposits underground and metals in or around your robot. To correct for them, you need to shift and scale both axis.

But first, test if the sensor's X axis is working by watching the value while moving a small magnet around the sensor. If should overpower any stationary field and bias in the sensor, if it can't then there may be a problem with the sensor.

To calibrate the compass, first find the min and max value for each axis. Do this by reading all the outputs of an axis when moving the sensor in a complete circle in the environment you will be using it in. Making the robot drive in a circle when first turned on to calibrate itself is not a bad idea. Anyway, the shift is the negative average and the scale is half the difference between maximums. what really matters is that this "distance" is the same on both axis, but normalizing both is easier. For example,

float Scale, Shift, Value;
Scale =  (max-min)/2;
Shift = -(max+min)/2;
Value = float(raw+Shift)/Scale;

Once both axis are corrected the atan2() function can work properly. If you were to plot the x and y points on a graph, they should trace a unit circle at the origin.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.