使⽤Python对IMU数据读取
使⽤Python对IMU数据读取
最近在做设备时需要⽤电脑对IMU的数据进⾏提取和分析,但发现⽬前该模块主要都是基于嵌⼊式给出的库函数,或者基于Linux系统的程序,⽬前在该⽅⾯的基于Windows系统和Python的解决⽅案⼏乎为空⽩,尝试弥补。
同时该.py程序移植⾄树莓派,测试良好
IMU的连接⽅式
我这⾥使⽤的是正点原⼦的ATK-IMU901型号,使⽤USB转串⼝进⾏数据传输。其中VCC接5V供电,GND接GND,RX接TX,TX接RX,接⼊电脑,可以使⽤串⼝调试助⼿进⾏端⼝号检测和IMU设置,具体的通信协议在⽤户⼿册⾥均有,⼤家可以去官⽹⾃⾏下载⽤户⼿册,且⼤部分IMU的通信协议是相同的,觉得⼀通百通。
传感器数据的读取
传感器是以字节流的形式进⾏数据的传输,通常数据是以16进制2字节的数字进⾏传输,但通过Python中serial的数据读取,还要再经过binascii进⾏转换才能得到我们想要的数据。
注:我使⽤的该型号IMU的波特率为115200,不同传感器的波特率不同,请注意。
ser = serial.Serial("com5",115200)
while True:
recv_data = adline()
data =str(binascii.b2a_adline()))
2字节16位补码的坑
传感器回传的数据为2字节补码形式,注意,是补码!!
⽽我查遍了百度发现Python的解码形式都是默认为原码进⾏解码
例如:
int(“number”,16)
如果number为"0x56",那么万事⼤吉,如果第⼀位的数字⼤于7,该函数返回的仍然为正数,但以补码格式读取该数字为负数,⽽⾮正数于是我⾃⼰写了⼀个补码转原码的函数才得以解决
def byte16ToInt(byte16):
# 补码转换为原码
if(byte16 &0x80)==0:
r = byte16
else:
byte16 = byte16 ^0xff
byte16 = byte16 +1
r =-byte16
return r
代码
模块讲解
1.分割模块
由于通过函数*binascii.b2a_hex()*得到的数据为16位⽆限长,所以通过该函数将数据以两字节长度进⾏分割:
def setChars(OData):
# 将字符串转换为字符组格式,并还原每⼀⾏
asd =[]
i =0
TLong =len(OData)
while OData[i +1] is not None:
asd.append(OData[i:i +2])
i = i +2
if i >= TLong:
break
return asd
2.转码模块
将反码转换为原码,具体原因前⽂有提:
def byte16ToInt(byte16):
# 补码转换为原码
if(byte16 &0x80)==0:
r = byte16
else:
byte16 = byte16 ^0xff
byte16 = byte16 +1
r =-byte16
return r
3.转位函数
IMU反馈的函数为16进制数字,需要转为10进制数据进⾏计算
def NumChange2(OData):
TLong =len(OData)
i =0
asd =[]
while TRUE:
a =0x00+16* dic[OData[i][0]]+ dic[OData[i][1]]
b =byte16ToInt(a)
asd.append(b)
i = i +1
if i == TLong:
break
return asd
完整代码
后续代码注释均有注解,就不⼀⼀讲解了。
该代码能成功读取IMU的x,y,z轴的⾓度、加速度、⾓加速度以及四元数,但系统还能返回磁⼒计和⽓压计数据,由于不需要,故没有添加相关的算法模块。
以下是程序的完整代码:
import serial
from tkinter import*
import binascii
import sys
dic ={
'0':0,'1':1,'2':2,
'3':3,'4':4,'5':5,
'6':6,'7':7,'8':8,
'9':9,'a':10,'b':11,
'c':12,'d':13,'e':14,
'f':15,
}
def setChars(OData):
# 将字符串转换为字符组格式,并还原每⼀⾏
asd =[]
i =0
TLong =len(OData)
while OData[i +1] is not None:
asd.append(OData[i:i +2])
i = i +2
if i >= TLong:
break
return asd
def byte16ToInt(byte16):
# 补码转换为原码
if(byte16 &0x80)==0:
r = byte16
else:
byte16 = byte16 ^0xff
byte16 = byte16 +1
r =-byte16
return r
def NumChange2(OData):python怎么读取串口数据
TLong =len(OData)
i =0
asd =[]
while TRUE:
a =0x00+16* dic[OData[i][0]]+ dic[OData[i][1]]
b =byte16ToInt(a)
asd.append(b)
i = i +1
if i == TLong:
break
return asd
def searchFF1(OData):
# 检索⾓度数据并反馈数据流
for i in range(len(OData)-12):
if OData[i:i +3]==["55","55","01"] and i +11<=len(OData):
Slop = OData[i +4:i +10]
for m in range(len(Slop)):
Slop[m]=byte16ToInt(0x00+16* dic[Slop[m][0]]+ dic[Slop[m][1]])
getSloop(setSloop(Slop))
OData[:i]=[]
def setSloop(OData):
# ⾓度算法,数组有三个模块,分别为x,y,z⽅向的⾓度
return[round((byte16ToInt(OData[1])<<8|byte16ToInt(OData[0]))/32768*180,3),
round((byte16ToInt(OData[3])<<8|byte16ToInt(OData[2]))/32768*180,3),
round((byte16ToInt(OData[5])<<8|byte16ToInt(OData[4]))/32768*180,3)]
def getSloop(OData):
# 得到⾓度度数
if OData:
sys.stdout.write(
"X轴的⾓度为:"+str(OData[0])+"\t"+"Y轴的⾓度为:"+str(OData[1])+"\t"+"Z轴的⾓度为:"+str(OData[2])+"\n")
if __name__ =='__main__':
print("开始测试:")
ser = serial.Serial("com3",115200)
print("获取句柄成功,进⼊循环:")
count =0
data =[]
while True:
Fdata =str(binascii.b2a_adline()))        Fdata = Fdata[2:-1]
Fdata =setChars(Fdata)
searchFF1(data)
# print(data)
count = count +1
if count ==100:
break

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。