minlMU-9 v3 magnetometer wildly inaccurate

I’m using a minlMU-9 interfaced with a Raspberry Pi via I2C. There is no problem interfacing, just with the compass readings. The compass is secured to a narrow board, allowing us to perform relatively accurate rotations (to within a few degrees). There is also no nearby magnetic interference which would skew our readings.

We’ve been benchmarking using an iPhone compass ap. At most, there should be a fixed offset between the two, but that hasn’t been the case. Also, when the minlMU-9 is rotated by 90 or 180 degrees, the amount of rotation (difference between the readings) is typically off from 90 or 180 by around 10 degrees. When slowly rotating the minlMU, sometimes the reading jumps by an offset which then sticks to all subsequent readings. I suspect a mechanical issue.

My lab partner is handling the coding (Python), which I think is stock code modified to calculate a heading from the raw data.


from __future__ import division
from smbus import SMBus
from time import sleep
import math

busNum = 1
b = SMBus(busNum)

LSM = 0x1d
LGD = 0x6b

LSM_WHOAMI = 0b01001001 #Compass/Accelerometer self-id

def twos_comp_combine(msb, lsb): #Function used to combine MSB & LSB
    twos_comp = 256*msb + lsb
    if twos_comp >= 32768:
        return twos_comp - 65536
    else:
        return twos_comp

#Control register addresses -- from LSM303D datasheet

CTRL_0 = 0x1F #General settings
CTRL_1 = 0x20 #Turns on accelerometer and configures data rate
CTRL_2 = 0x21 #Self test accelerometer, anti-aliasing accel filter
CTRL_3 = 0x22 #Interrupts
CTRL_4 = 0x23 #Interrupts
CTRL_5 = 0x24 #Turns on temperature sensor
CTRL_6 = 0x25 #Magnetic resolution selection, data rate config
CTRL_7 = 0x26 #Turns on magnetometer and adjusts mode

#Registers holding twos-complemented MSB and LSB of magnetometer readings -- from LSM303D datasheet
MAG_X_LSB = 0x08 # x
MAG_X_MSB = 0x09
MAG_Y_LSB = 0x0A # y
MAG_Y_MSB = 0x0B
MAG_Z_LSB = 0x0C # z
MAG_Z_MSB = 0x0D

#Registers holding twos-complemented MSB and LSB of accelerometer readings -- from LSM303D datasheet
ACC_X_LSB = 0x28 # x
ACC_X_MSB = 0x29
ACC_Y_LSB = 0x2A # y
ACC_Y_MSB = 0x2B
ACC_Z_LSB = 0x2C # z
ACC_Z_MSB = 0x2D

#Registers holding 12-bit right justified, twos-complemented temperature data -- from LSM303D datasheet
TEMP_MSB = 0x06
TEMP_LSB = 0x05


if b.read_byte_data(LSM, 0x0f) == LSM_WHOAMI: #testing compass/acc
        print 'LSM303D detected successfully.'
else:
        print 'No LSM303D detected on bus '+str(busNum)+'.'


b.write_byte_data(LSM, CTRL_1, 0b1010111) # enable accelerometer, 50 hz sampling
b.write_byte_data(LSM, CTRL_2, 0x00) #set +/- 2g full scale
b.write_byte_data(LSM, CTRL_5, 0b11100100) #high resolution mode, thermometer off, 6.25hz ODR
b.write_byte_data(LSM, CTRL_6, 0b00100000) # set +/- 4 gauss full scale
b.write_byte_data(LSM, CTRL_7, 0x00) #get magnetometer out of low power mode

while True:

    magx = twos_comp_combine(b.read_byte_data(LSM, MAG_X_MSB), b.read_byte_data(LSM, MAG_X_LSB)) #raw magnetometer value for x
    magy = twos_comp_combine(b.read_byte_data(LSM, MAG_Y_MSB), b.read_byte_data(LSM, MAG_Y_LSB)) #raw magnetometer value for y
 	magz = twos_comp_combine(b.read_byte_data(LSM, MAG_Z_MSB), b.read_byte_data(LSM, MAG_Z_LSB)) #raw magnetometer value for z

        #compass w/o pitch and roll
        if (magy > 0):
                com_deg2 = (90-(math.degrees(math.atan(magx/magy))))
        if (magy < 0):
                com_deg2 = (270-(math.degrees(math.atan(magx/magy))))
        if (magy ==  0 and magx < 0):
                com_deg2 = 180
        if (magy == 0 and magx > 0):
                com_deg2 = 0

        print "Raw Magnetic field (x, y, z):", magx, magy, magz
        print "Degree: %.2f" % com_deg2
        print "---"
        sleep(2.0)

Any help would be appreciated!

Magnetometers must be calibrated before use. Here are two procedures:
bot-thoughts.com/2011/04/qui … on-in.html (crude)
sailboatinstruments.blogspot.com … ation.html (much better).