obtaining correct IMU values
Question:
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
Answers:
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)
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)
.
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
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)
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)
.