1

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

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • There is no need to convert the data to a hex string, and then convert it back to an int. If you index a `bytes` object in Python3, you get the (unisgned) byte as an int directly, so you can just use `AxL = data[2]`. In Python2 you'd have to do `AxL = ord(data[2])`. – Jan Christoph Terasa Mar 28 '19 at 21:22
  • See my answer, the signed number representation of the shorts in the data is likely [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement), so just using the MSB as a sign bit is not correct. – Jan Christoph Terasa Mar 28 '19 at 21:37

2 Answers2

1

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)
Jan Christoph Terasa
  • 5,781
  • 24
  • 34
0

A little bit late, but still may help someone.

We also should check out the length of the data received and check if the sum is correct. It is a good practice to make sure that the signal is received entirely.

As it is mentioned in the documentation, Checksum: Sum=0x55+0x51+AxH+AxL+AyH+AyL+AzH+AzL+TH+TL. It should be equal to the last value in data. So, do not forget to check it: (sum(data) - data[10]) & 0xFF).

user12628549
  • 152
  • 1
  • 12