9 years, 1 month ago.

LSM303DLH Compass Problems

I am working with the LSM303DLH tilt compass breakout board and having problems with my outputs.

I leave the compass at the same position and my heading values seem random along with my acceleration values. I don't know how to change the magnitude values either. I thought maybe shaking the compass would change these values but it does not. Or what to do with the calibration settings that are in the main file. I don't understand other post that I saw about this. How do I get consistent values for the heading of the compass?

Thank you so much for all the help!!!!

Here is the fork to my code that I used.

https://developer.mbed.org/users/cbelknap/code/LSM303DLHTest/

Log file from tera term of my values

/media/uploads/cbelknap/teraterm.log

Picture of my set up /media/uploads/cbelknap/fotbdc8_-1-.jpg

2 Answers

9 years, 1 month ago.

I had a similar issue with the sensor (as part of an IMU with a 3-axis gyroscope) in my code that seemed to be in the type conversions. The one that I have working is:

void readIMU(){
    char reg, address;
    address = L3GD20_ADDR;
    reg = L3GD20_OUT_X_L | 0x80; // set address auto-increment bit
    v2.write(address,&reg,1);  
    v2.read(address+1,rawdata,6); 
    rawvals[6] = (int16_t)((uint16_t)(rawdata[1]) <<8 | (uint16_t)(rawdata[0]))-GyroBiasX;   
    rawvals[7] = (int16_t)((uint16_t)(rawdata[3]) <<8 | (uint16_t)(rawdata[2]))-GyroBiasY;   
    rawvals[8] = (int16_t)((uint16_t)(rawdata[5]) <<8 | (uint16_t)(rawdata[4]))-GyroBiasZ;   
    address = LSM303_A_ADDR; 
    reg = LSM303_A_OUT_X_L | 0x80; // set address auto-increment bit
    v2.write(address,&reg,1);
    v2.read(address+1,rawdata,6); 
    rawvals[0] = (int16_t)((uint16_t)(rawdata[0]) <<8 | (uint16_t)(rawdata[1]));   
    rawvals[1] = (int16_t)((uint16_t)(rawdata[2]) <<8 | (uint16_t)(rawdata[3]));   
    rawvals[2] = (int16_t)((uint16_t)(rawdata[4]) <<8 | (uint16_t)(rawdata[5]));   
    address = LSM303_M_ADDR; 
    reg = LSM303_M_OUT_X_H | 0x80; // set address auto-increment bit
    v2.write(address,&reg,1);  
    v2.read(address+1,rawdata,6); 
    rawvals[3] = (int16_t)((uint16_t)(rawdata[0]) <<8 | (uint16_t)(rawdata[1]));   
    rawvals[4] = (int16_t)((uint16_t)(rawdata[2]) <<8 | (uint16_t)(rawdata[3]));   
    rawvals[5] = (int16_t)((uint16_t)(rawdata[4]) <<8 | (uint16_t)(rawdata[5]));   
    truevals[0] = float(rawvals[0])*acc_scale; //Acceleration in m/s²
    truevals[1] = float(rawvals[1])*acc_scale;
    truevals[2] = float(rawvals[2])*acc_scale;
    truevals[3] = float(rawvals[3])*mag_scale_x; //magnetometer values in microtesla
    truevals[4] = float(rawvals[4])*mag_scale_y;
    truevals[5] = float(rawvals[5])*mag_scale_z;
    truevals[6] = float(rawvals[6])*gyro_scale - GyroBiasX; //Rate gyros in deg/s
    truevals[7] = float(rawvals[7])*gyro_scale - GyroBiasY;
    truevals[8] = float(rawvals[8])*gyro_scale - GyroBiasZ;
}

v2 is the I2C class (and I know that you strictly don't need to +1 in the read code)

I had a quick look at the class code but couldn't spot anything obvious, save for the filtering code - I tend to do my filtering in floating point, so I have no idea whether it works or not. It might be worth setting the shift to 0 and see if it all works normally before scratching your head further. I vaguely worry about shifting signed integers around and getting a sane answer.

I'm confused on the coding. I am not the most profienct programmer. I am trying to understand the coding of the compass and having a hard time. I have other components that I understand the coding, but I guess this piece is a little more in depth.

posted by Curtis Belknap 18 Mar 2015

I also set the shift to zero and still nothing. I also tried using another code for the compass and still getting random values for the magnitude.

https://developer.mbed.org/users/yamaguch/code/LSM303DLH_Example/

The code I was using before I can interpert better because I am not a strong programmer at all so I need coding very basic. I just tried implementing his code into mine and still random for the compass. Direction 2 is just the arctan of the acceleration values which seem to give me constant results but when I try to do the arctan(y.acceleration/x.acceleration) the values do not change as I move the compass in different directions on the table.

acc: (-0.003000, -0.041000, 1.003000), mag: (-0.000948, -0.000948, 0.000000) accel = (-0.0, -0.0, 1.0), compass = (-0.0, -0.0, 0.0) north = (-0.7, -0.7, -0.0), east = (-0.7, 0.7, 0.0) east.dot(base) = 0.7, north.dot(base) = -0.7 direction = 135 direction2 = -176

acc: (0.008000, -0.024000, 0.986000), mag: (0.000000, -0.000948, 0.000000) accel = (0.0, -0.0, 1.0), compass = (0.0, -0.0, 0.0) north = (-0.0, -1.0, -0.0), east = (-1.0, 0.0, 0.0) east.dot(base) = 0.0, north.dot(base) = -1.0 direction = 180 direction2 = 162

acc: (0.007000, -0.026000, 0.995000), mag: (0.000000, 0.000000, -0.001053) accel = (0.0, -0.0, 1.0), compass = (0.0, 0.0, -0.0) north = (0.3, -1.0, -0.0), east = (-1.0, -0.3, -0.0) east.dot(base) = -0.3, north.dot(base) = -1.0 direction = -165 direction2 = 165

acc: (0.001000, -0.016000, 1.004000), mag: (0.000000, 0.000000, 0.000000) accel = (0.0, -0.0, 1.0), compass = (0.0, 0.0, 0.0) north = (nan, nan, nan), east = (nan, nan, nan) east.dot(base) = nan, north.dot(base) = nan direction = nan direction2 = 176

acc: (0.012000, -0.024000, 1.012000), mag: (0.000000, 0.000000, 0.000000) accel = (0.0, -0.0, 1.0), compass = (0.0, 0.0, 0.0) north = (nan, nan, nan), east = (nan, nan, nan) east.dot(base) = nan, north.dot(base) = nan direction = nan direction2 = 153

acc: (-0.009000, -0.027000, 0.988000), mag: (0.000948, 0.000000, 0.000000) accel = (-0.0, -0.0, 1.0), compass = (0.0, 0.0, 0.0) north = (1.0, -0.0, 0.0), east = (0.0, -1.0, -0.0) east.dot(base) = -1.0, north.dot(base) = -0.0 direction = -90 direction2 = -162

acc: (0.011000, -0.015000, 0.967000), mag: (0.000000, 0.000000, 0.000000) accel = (0.0, -0.0, 1.0), compass = (0.0, 0.0, 0.0) north = (nan, nan, nan), east = (nan, nan, nan) east.dot(base) = nan, north.dot(base) = nan direction = nan direction2 = 144

acc: (-0.006000, -0.029000, 0.992000), mag: (-0.000948, 0.000000, 0.000000) accel = (-0.0, -0.0, 1.0), compass = (-0.0, 0.0, 0.0) north = (-1.0, 0.0, -0.0), east = (0.0, 1.0, 0.0) east.dot(base) = 1.0, north.dot(base) = 0.0 direction = 90 direction2 = -168

posted by Curtis Belknap 19 Mar 2015
9 years, 1 month ago.

Purely the acceleration values you thought random: Those look pretty normal to me, although unscaled. To pick one randomly:

ACC: -160.00 96.00 8224.00

So X and Y are pretty small, and will relatively vary alot between samples. Z is very large. Conclusion: Your IC is lying flat :)

The mag values are being weird though.

Okay, I didn't know it was normal for the x and y values to vary on a flat surface. I understand that the Z value is large and saw that when i would turn the board upside down I would get a large negative Z value.

My magnitude values just seem like they are just random values spit out. Do you think it is either the hardware or the coding?

posted by Curtis Belknap 18 Mar 2015

A couple of things...

Although you get a 16 bit value out of the accelerometer/compass, they aren't 16 bit data but 12 bit, so the conversion factors are slightly different.

I haven't got the datasheet to hand, but you need to check that the magnetometer is switched on, else you won't get values out of the thing.

posted by Dave Turner 19 Mar 2015

From what I have read on the data sheet, it is on and I am accessing data from it but still nothing.

Also can you explain what part of the coding you are talking about for "Although you get a 16 bit value out of the accelerometer/compass, they aren't 16 bit data but 12 bit, so the conversion factors are slightly different."

posted by Curtis Belknap 19 Mar 2015

The accelerometer is a left justified 12-bit value (last 4 bits are always 0), so you have to divide the answer by 64 to get the correct value. The magnetometer is right justified 12 bit (first 4 bits always 0) so you can either shift left and divide or look at the sign bit and subtract 4096 if the sign bit is zero.

Your magnetometer values look just plain wrong... Given that there's always a magnetic field acting you shouldn't be getting values near to zero. Try increasing the sensitivity and see what you get with raw numbers coming out of the chip. It'll probably be worth doing a max/min calibration (i.e. finding the offset of the magnetometer) just to check you've not got a huge offset.

FWIW it's undoubtedly worth writing a simple access program to check what ought to be working is rather than using someone else's library of unknown provenance.

posted by Dave Turner 19 Mar 2015