pythonimu

obtaining correct IMU values


I am reading data from an AHRS / IMU sensor via USB with Python 2.7. To obtain the acceleration the manufacturer specifies according to the image below:

supplier's description IMU

My code in python is this, but when the acceleration is negative the values are wrong. I believe I need to check the first bit of the MSB (In this case, the AxH field), if 1 is negative, if 0 is positive.

    #....
    #data = serial.read(size=11)
    #....
    #

    #Acceleration
    elif data[1] == b'\x51':
        AxL=int(data[2:3].encode('hex'), 16)
        AxH=int(data[3:4].encode('hex'), 16)
        AyL=int(data[4:5].encode('hex'), 16)
        AyH=int(data[5:6].encode('hex'), 16)
        AzL=int(data[6:7].encode('hex'), 16)
        AzH=int(data[7:8].encode('hex'), 16)

        x = (AxH<<8|AxL)/32768.0*16.0
        y = (AyH<<8|AyL)/32768.0*16.0
        z = (AzH<<8|AzL)/32768.0*16.0

Anyone have any suggestions?

The complete IMU sensor manual is this: http://wiki.wit-motion.com/english/lib/exe/fetch.php?media=module:wt901:docs:jy901usermanualv4.pdf


Solution

  • Using struct

    The axes data are stored as a little-endian signed short (2 byte) integers, so we can use struct to unpack the data. The struct module will take care of the correct interpretation of the bytes as short integers.

    import struct
    
    g = 9.81
    conv = 16.0 / 32768.0 * g
    
    # ...
    
        elif data[1] == b'\x51':
            axes = struct.unpack("<hhh", data[2:8])
            x, y, z = [a*conv for a in axes]
    

    Conversion by hand

    If you want to do the conversion yourself, I'd assume that the representation of the signed number is two's complement:

    def twos_complement(x, bytes=2):
        maxnum = 2**(bytes*8) - 1
        msb = 1 << (bytes*8 - 1) 
        return -((x^maxnum) + 1) if x&msb else x
    
    AxL = data[2]
    AxH = data[3]
    Ax_unsigned = AxH << 8 | AxL
    Ax = twos_complement(Ax_unsigned, 2)