Search code examples
pythonbeagleboneblacki2cgyroscope

Read a gyroscope value with the I2c bus


Product : https://www.adafruit.com/product/2020

datasheet: https://cdn-shop.adafruit.com/datasheets/LSM9DS0.pdf

I'm student and it's the first time for me to use I2c bus. I am trying to read the basic gyroscope value. I wasted a part of my life to understand how the I2c work. But after reading the datasheet and made my own script. My values are stuck there. Nothing move and I don't know why.

Rotation in X-Axis : -1087
Rotation in Y-Axis : -28797
Rotation in Z-Axis : -15032

Here is my script. Someone can help me to solve it? I'm working with a beagle bone black.

import smbus
import time


bus = smbus.SMBus(1)

# 0x6b adress (found with i2cdetect), 0x20 register (found with the data sheet), CTRL_REG1_G(20h)
bus.write_byte_data(0x6b, 0x20, 0x0F)

bus.write_byte_data(0x6b, 0x23, 0x30)

time.sleep(0.5)


data0 = bus.read_byte_data(0x6b, 0x08)
data1 = bus.read_byte_data(0x6b, 0x09)


xGyro = data1 * 256 + data0
if xGyro > 32767 :
    xGyro -= 65536

data0 = bus.read_byte_data(0x6b, 0x0A)
data1 = bus.read_byte_data(0x6b, 0x0B)


yGyro = data1 * 256 + data0
if yGyro > 32767 :
    yGyro -= 65536


data0 = bus.read_byte_data(0x6b, 0x0C)
data1 = bus.read_byte_data(0x6b, 0x0D)

zGyro = data1 * 256 + data0
if zGyro > 32767 :
    zGyro -= 65536


print "Rotation in X-Axis : %d" %xGyro
print "Rotation in Y-Axis : %d" %yGyro
print "Rotation in Z-Axis : %d" %zGyro

Solution

  • According to the datasheet, the LSM9DS0 contains 2 submodules: one containing accelerometer and compass, the other containing the gyroscope. Each of the submodules is located at a different address, determined by the state of SA0_XM and SA0_G pins.

    Tables 15 and 16 from the datasheet

    On the Adafruit module those pins are pulled high, so according to tables 15 and 16 in the datasheet:

    • accelerometer and compass are at address 0x1d (00011101)
    • gyroscope is at address 0x6b (01101011)

    Based on this, it appears you're accessing the correct address. It also means that near the beginning of your script, you should define a few constants, such as

    ACCEL_ADDRESS = 0x1d
    GYRO_ADDRESS = 0x6b
    

    and use those instead of copying the magic number all around your code.


    Now the register addresses. Since there are two different devices, there's a good chance that each exposes a different set of registers. Indeed, table 17 shows this to be the case, albeit somewhat indirectly. The important part is the column titled "Slave Address", which refers either to table 15 (accelerometer an compass) or table 16 (gyro). (The symbolic names of the registers might help you tell the difference in some cases, since they often have suffix M (former) or G (latter), but not always).

    Table 17

    And herein lies your problem. For a gyroscope, the measurements are in registers at addresses 0x28..0x2d

    Gyroscope registers

    yet you are reading from 0x08..0x0d, which are reserved in the gyroscope module (getting some fixed nonsense as a result of reading that would not be unexpected).

    You seem to have gotten the control registers CTRL_REG1_G and CTRL_REG4_G correctly.

    Of course, just as with the addresses, you should have constants defined for all the registers you want to use:

    CTRL_REG1_G = 0x20
    CTRL_REG4_G = 0x23
    OUT_X_L_G = 0x28
    OUT_X_H_G = 0x29
    

    and so on...


    As an aside, the first thing I would try, before actually reading the measured values, would be reading the device identification register, in this case WHO_AM_I_G (0x0F).

    Device identification register

    Since this register returns a constant, it's a good way to validate you're talking with the right device, and that the communication works correctly.


    One more: don't copy-paste code around, use functions instead.

    For example the first step of refactoring could yield something like:

    def read_int16(bus, device, register):
        lsb = bus.read_byte_data(device, register)
        msb = bus.read_byte_data(device, register + 1)
    
        result = msb * 256 + lsb
        return (result - 65536) if (result > 32767) else result
    
    
    xGyro = read_int16(bus, GYRO_ADDRESS, OUT_X_L_G)
    yGyro = read_int16(bus, GYRO_ADDRESS, OUT_Y_L_G)
    zGyro = read_int16(bus, GYRO_ADDRESS, OUT_Z_L_G)