The new Raspberry Pi B Model B+ is here - Pick one up in the store and check our detailed guide!
Forum rules
Talk about Adafruit Raspberry Pi® accessories! Please do not ask for Linux support, this is for Adafruit products only! For Raspberry Pi help please visit: http://www.raspberrypi.org/phpBB3/

LSM303 breakout board

by shigeru on Sat Jan 19, 2013 3:41 am

Hello!

I have started on a Python class for LSM303 studying from Adafruit's BMP085 code, but there seems something not quite right that readings sometimes produces outrageous figures. Could you help me?

Code: Select all | TOGGLE FULL SIZE
#!/usr/bin/python

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# LSM303DLHC Class
# by Shigeru KAWAGUCHI
# ===========================================================================

class LSM303DLHC :
  i2c_accel = None
  i2c_mag = None

  # Device Addresses
  __LSM303DLHC_ADDRESS_ACCEL      = 0x32
  __LSM303DLHC_ADDRESS_MAG         = 0x3C
  __LSM303DLHC_ID               = 0b11010100

  # LSM303DLHC Registers                        Default      Type
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG1_A      = 0x20   # 00000111   rw
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG2_A      = 0x21   # 00000000   rw
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG3_A      = 0x22   # 00000000   rw
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG4_A      = 0x23   # 00000000   rw
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG5_A      = 0x24   # 00000000   rw
  __LSM303DLHC_REGISTER_ACCEL_CTRL_REG6_A      = 0x25   # 00000000   rw
  __LSM303DLHC_REGISTER_ACCEL_REFERENCE_A      = 0x26   # 00000000   r
  __LSM303DLHC_REGISTER_ACCEL_STATUS_REG_A      = 0x27   # 00000000   r
  __LSM303DLHC_REGISTER_ACCEL_OUT_X_L_A         = 0x28
  __LSM303DLHC_REGISTER_ACCEL_OUT_X_H_A         = 0x29
  __LSM303DLHC_REGISTER_ACCEL_OUT_Y_L_A         = 0x2A
  __LSM303DLHC_REGISTER_ACCEL_OUT_Y_H_A         = 0x2B
  __LSM303DLHC_REGISTER_ACCEL_OUT_Z_L_A         = 0x2C
  __LSM303DLHC_REGISTER_ACCEL_OUT_Z_H_A         = 0x2D
  __LSM303DLHC_REGISTER_ACCEL_FIFO_CTRL_REG_A   = 0x2E
  __LSM303DLHC_REGISTER_ACCEL_FIFO_SRC_REG_A   = 0x2F
  __LSM303DLHC_REGISTER_ACCEL_INT1_CFG_A      = 0x30
  __LSM303DLHC_REGISTER_ACCEL_INT1_SOURCE_A      = 0x31
  __LSM303DLHC_REGISTER_ACCEL_INT1_THS_A      = 0x32
  __LSM303DLHC_REGISTER_ACCEL_INT1_DURATION_A   = 0x33
  __LSM303DLHC_REGISTER_ACCEL_INT2_CFG_A      = 0x34
  __LSM303DLHC_REGISTER_ACCEL_INT2_SOURCE_A      = 0x35
  __LSM303DLHC_REGISTER_ACCEL_INT2_THS_A      = 0x36
  __LSM303DLHC_REGISTER_ACCEL_INT2_DURATION_A   = 0x37
  __LSM303DLHC_REGISTER_ACCEL_CLICK_CFG_A      = 0x38
  __LSM303DLHC_REGISTER_ACCEL_CLICK_SRC_A      = 0x39
  __LSM303DLHC_REGISTER_ACCEL_CLICK_THS_A      = 0x3A
  __LSM303DLHC_REGISTER_ACCEL_TIME_LIMIT_A      = 0x3B
  __LSM303DLHC_REGISTER_ACCEL_TIME_LATENCY_A   = 0x3C
  __LSM303DLHC_REGISTER_ACCEL_TIME_WINDOW_A      = 0x3D

  __LSM303DLHC_REGISTER_MAG_CRA_REG_M         = 0x00
  __LSM303DLHC_REGISTER_MAG_CRB_REG_M         = 0x01
  __LSM303DLHC_REGISTER_MAG_MR_REG_M         = 0x02
  __LSM303DLHC_REGISTER_MAG_OUT_X_H_M         = 0x03
  __LSM303DLHC_REGISTER_MAG_OUT_X_L_M         = 0x04
  __LSM303DLHC_REGISTER_MAG_OUT_Z_H_M         = 0x05
  __LSM303DLHC_REGISTER_MAG_OUT_Z_L_M         = 0x06
  __LSM303DLHC_REGISTER_MAG_OUT_Y_H_M         = 0x07
  __LSM303DLHC_REGISTER_MAG_OUT_Y_L_M         = 0x08
  __LSM303DLHC_REGISTER_MAG_SR_REG_Mg         = 0x09
  __LSM303DLHC_REGISTER_MAG_IRA_REG_M         = 0x0A
  __LSM303DLHC_REGISTER_MAG_IRB_REG_M         = 0x0B
  __LSM303DLHC_REGISTER_MAG_IRC_REG_M         = 0x0C
  __LSM303DLHC_REGISTER_MAG_TEMP_OUT_H_M      = 0x31
  __LSM303DLHC_REGISTER_MAG_TEMP_OUT_L_M      = 0x32

  # Constructor
  def __init__(self, address_accel=0x19, address_mag=0x1E, debug=False):
    self.i2c_accel = Adafruit_I2C(address_accel)
    self.i2c_mag = Adafruit_I2C(address_mag)

    self.address_accel = address_accel
    self.address_mag = address_mag
    self.debug = debug

    # Enable the accelerometer
    # 10Hz measurement, normal mode, XYZ enabled
    self.i2c_accel.write8(self.__LSM303DLHC_REGISTER_ACCEL_CTRL_REG1_A, 0x27)
    # continuous update, little endian, +-4G, high resolution disable, 4 wire serial
    self.i2c_accel.write8(self.__LSM303DLHC_REGISTER_ACCEL_CTRL_REG4_A, 0x10)

    # Enable the magnetometer
    # continuous conversion mode
    self.i2c_mag.write8(self.__LSM303DLHC_REGISTER_MAG_MR_REG_M, 0x00)
    # sensor input field range +-1.9 gauss
    self.i2c_mag.write8(self.__LSM303DLHC_REGISTER_MAG_CRB_REG_M, 0x40)

  def readAccelerations(self):
    "Reads the accelerometer from the sensor"
    xlo = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_X_L_A)
    if (self.debug):
      print "DBG: accel X lo: 0x%04X (%d)" % (xlo & 0xFFFF, xlo)
    xhi = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_X_H_A)
    if (self.debug):
      print "DBG: accel X hi: 0x%04X (%d)" % (xhi & 0xFFFF, xhi)
    ylo = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_Y_L_A)
    if (self.debug):
      print "DBG: accel Y lo: 0x%04X (%d)" % (ylo & 0xFFFF, ylo)
    yhi = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_Y_H_A)
    if (self.debug):
      print "DBG: accel Y hi: 0x%04X (%d)" % (yhi & 0xFFFF, yhi)
    zlo = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_Z_L_A)
    if (self.debug):
      print "DBG: accel Z lo: 0x%04X (%d)" % (zlo & 0xFFFF, zlo)
    zhi = self.i2c_accel.readU8(self.__LSM303DLHC_REGISTER_ACCEL_OUT_Z_H_A)
    if (self.debug):
      print "DBG: accel Z hi: 0x%04X (%d)" % (zhi & 0xFFFF, zhi)

    accelData = Obj3D()
    accelData.x = ((xhi << 8) + xlo)
    accelData.y = ((yhi << 8) + ylo)
    accelData.z = ((zhi << 8) + zlo)

    return accelData

  def readMagnetics(self):
    "Reads the magmetometer from the sensor"
    xlo = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_X_L_M)
    if (self.debug):
      print "DBG: mag X lo: 0x%04X (%d)" % (xlo & 0xFFFF, xlo)
    xhi = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_X_H_M)
    if (self.debug):
      print "DBG: mag X hi: 0x%04X (%d)" % (xhi & 0xFFFF, xhi)
    ylo = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_Y_L_M)
    if (self.debug):
      print "DBG: mag Y lo: 0x%04X (%d)" % (ylo & 0xFFFF, ylo)
    yhi = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_Y_H_M)
    if (self.debug):
      print "DBG: mag Y hi: 0x%04X (%d)" % (yhi & 0xFFFF, yhi)
    zlo = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_Z_L_M)
    if (self.debug):
      print "DBG: mag Z lo: 0x%04X (%d)" % (zlo & 0xFFFF, zlo)
    zhi = self.i2c_mag.readU8(self.__LSM303DLHC_REGISTER_MAG_OUT_Z_H_M)
    if (self.debug):
      print "DBG: mag Z hi: 0x%04X (%d)" % (zhi & 0xFFFF, zhi)

    magData = Obj3D()
    magData.x = ((xhi << 8) + xlo)
    magData.y = ((yhi << 8) + ylo)
    magData.z = ((zhi << 8) + zlo)

    return magData

  def setMagGain(self, gain):
    self.i2c_mag.write8(self.__LSM303DLHC_REGISTER_MAG_CRB_REG_M, gain)

    return 0

class Obj3D :
   x = None
   y = None
   z = None


Thanks.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by adafruit_support_bill on Sat Jan 19, 2013 7:28 am

I haven't connected one to a Pi yet. We do have an Arduino library for it. You might want to compare the steps in your read function with what we do there.
https://github.com/adafruit/Adafruit_LSM303
User avatar
adafruit_support_bill
 
Posts: 27989
Joined: Sat Feb 07, 2009 9:11 am

Re: LSM303 breakout board

by shigeru on Sun Jan 20, 2013 4:23 am

Hello!

I have figured out the issues. There was few bit manipulations and also proper datatype conversion were needed to be implemented. I think I can get few other configuration methods in place to the class. Then now, I am wondering if you are interested in distributing the class I am making.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by adafruit_support_bill on Sun Jan 20, 2013 8:53 am

Post it up and we'll check it out. Thanks! :D
User avatar
adafruit_support_bill
 
Posts: 27989
Joined: Sat Feb 07, 2009 9:11 am

Re: LSM303 breakout board

by shigeru on Sun Jan 20, 2013 6:08 pm

Hi!

I have posted the codes in here. Please take a look.
https://bitbucket.org/shigeru_kawaguchi/adafruit_lsm303_for_rpi

Still work in progress, though. Thanks.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by aufder on Wed Jan 30, 2013 8:32 pm

Hi,
Thank you for posting your code! I'm having difficulty understanding the readings after hooking up my LSM303DLHC to my Pi, and wonder if there is an issue.

The temperature output looks mathematically correct from the data sheet, however, it indicates 3.75 degrees C, when in fact the temperature in the house is 22 C.

To arrive at 3.75, it finds temp hi is 0x01 and temp lo is 0xE0. So with 0x01E0 >> 4, you get 0x1E, which is 30. Then the code divides the 30 by 8 to get 3.75. This division is probably done because the data sheet says "8LSB/deg - 12 bit resolution"??
Either way, 3.75 and 30 are not close to 22.

I wonder if 8LSB/deg means something different from dividing the result by 8? If you consider that the 8 least sig bits per degree means you'd have to shift the 0x1E >> 8, which results in an even worse value.

Do you have better results with the temperature?

Thanks,
Alan
aufder
 
Posts: 13
Joined: Tue Jan 15, 2013 9:07 pm

Re: LSM303 breakout board

by shigeru on Thu Feb 07, 2013 8:49 pm

Hello!

Regarding to the temperature, I kind of gave up on it. It seems totally out and I just can not figure out what exactly the chip datasheet really meant.

Do you have any issue other than the temperature with the code?

Sorry that I cannot give any further input on the matter. Thank you for the feedback.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by adafruit_support_bill on Fri Feb 08, 2013 5:51 am

To arrive at 3.75, it finds temp hi is 0x01 and temp lo is 0xE0. So with 0x01E0 >> 4, you get 0x1E, which is 30. Then the code divides the 30 by 8 to get 3.75. This division is probably done because the data sheet says "8LSB/deg - 12 bit resolution"??
Either way, 3.75 and 30 are not close to 22.


Typically a sensor spec would give you a slope (sensitivity) and an offset. Looking at the data sheet, I only see a sensitivity spec. I suspect there needs to be an offset added to that. Based on your measurements it is probably on the order of 18 degrees or so. If you add that offset, do the temperatures track with reality?

I'll try to hook one up and do some measurements here later.
User avatar
adafruit_support_bill
 
Posts: 27989
Joined: Sat Feb 07, 2009 9:11 am

Re: LSM303 breakout board

by aufder on Fri Feb 08, 2013 12:32 pm

Hi,
Regarding the temperature variance, I'll try putting it in different areas (fridge, freezer, garage, toaster oven) and see what the output is, to see if I can come up with a multiplier or offset.

Thanks
aufder
 
Posts: 13
Joined: Tue Jan 15, 2013 9:07 pm

Re: LSM303 breakout board

by aufder on Fri Feb 08, 2013 12:39 pm

Hi Shigeru,
The gyro output seemed fine as I tilt it each way, but I'm questioning the magnetic output. The heading output (I think that's a computed number based on the other inputs) from the code seems to vary between 0 and 89.99 but never gets higher. Is the heading intended to be 0-359.99? I don't have it in front of me right now, but I can post more details later. As I rotate the sensor all the way around on a flat surface, the heading doesn't seem to show consistent behavior. I'll try to summarize my findings, and ensure there's no magnets nearby.

Thanks
aufder
 
Posts: 13
Joined: Tue Jan 15, 2013 9:07 pm

Re: LSM303 breakout board

by aufder on Fri Feb 08, 2013 11:30 pm

I modified my copy of LSM303DLHC_test.py to output csv formatted data, and found that mag X and mag Y were tracking magnetic north beautifully. I attached a csv file here of my data. If you plot mag X and Y on a chart, you'll see two nice sine waves (90 deg off each other) as I rotated the sensor 360 degrees. However, note that 'heading' isn't computing what I hoped. I'll look further, but from what I have, I think there is a good solution at hand.
Thanks again for putting together a nice script.
Best regards
Attachments
LSM303out.csv
sampled data while rotating sensor 360 deg
(8.33 KiB) Downloaded 47 times
aufder
 
Posts: 13
Joined: Tue Jan 15, 2013 9:07 pm

Re: LSM303 breakout board

by shigeru on Sat Feb 09, 2013 9:38 pm

Hello aufder!

Regarding to the heading data, it is using Python's arctangent for X and Y and it supposed to give in range of -180 to 180. Since tangent becomes infinity at 90 degrees, may be it is causing division by zero error. I have not tested this part of the module much. I will investigate.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by aufder on Sun Feb 10, 2013 5:06 pm

Hi Shigeru,
I found a fix to the heading issue I think.
In the function readMagneticHeading, it does:
magData = self.readMagnetics()

Instead if I do:
magData = self.readMagneticsGauss()

It gives me a better reading from -180 to 180.

All set I think.
Thanks again!
aufder
 
Posts: 13
Joined: Tue Jan 15, 2013 9:07 pm

Re: LSM303 breakout board

by shigeru on Sun Feb 10, 2013 7:24 pm

Hello aufder!

Thank you. I have updated the bucket. I also put the temperature with 18 as offset for now.
shigeru
 
Posts: 11
Joined: Fri Nov 09, 2012 5:05 pm

Re: LSM303 breakout board

by codac on Mon Mar 03, 2014 6:33 am

Hi guys,

I'm desperately looking for a python script (not for c-code) that covers both sensors L3GD20 and LSM303DLHC as I'm using the minimu9-v2 breakout.
Furthermore, based on that code I'd like to understand how those sensors need to be properly calibrated.

Any help is highly appreciated.
codac
 
Posts: 3
Joined: Sun Sep 15, 2013 11:35 am