相关知识介绍
陀螺仪是一种用来感测与维持方向的装置,基于角动量的理论设计出来的。陀螺仪主要是由一个位于轴心可以旋转的轮子构成,陀螺仪一旦开始旋转,由于轮子的「角动量」,陀螺仪有抗拒方向改变的趋向。陀螺仪多用于导航、定位等系统
JY901S是9轴姿态角度传感器,支持串口和 IIC 两种数字接口。串口速率2400bps~921600bps 可调, IIC 接口支持全速 400K 速率,本文均是使用串口。
9轴分别为加速度传感器(即加速计)、角速度传感器(即陀螺仪)、磁感应传感器(即电子罗盘)。
连接说明
我是用的USB转TTL电平串口模块与树莓派连接,用的型号是CH340。
在windows电脑上的端口号都是ComX,在Liunx系统下的端口号如果是直接插在树莓派USB接口上的话就是写
'/dev/ttyAMA0'否则就是'/dev/ttyAMA0',具体如下。
port = '/dev/ttyUSB0' # use '/dev/ttyAMA0' for USB or '/dev/ttyAMA0' for GPIO
注意:RX和TX是需要反着接的,无论是直接连在GPIO上还是用USB转TTL,否则会出现问题。
轴向说明
如上图所示,模块的轴向在上图的右上方,向右为 X 轴,向上 Y 轴,垂直模块向外为 Z 轴。旋转的方向按右手法则定义,即右手大拇指指向轴向,四指弯曲的方向即为绕该轴 旋转的方向。X 轴角度即为绕 X 轴旋转方向的角度,Y 轴角度即为绕 Y 轴旋转方向的角度, Z 轴角度即为绕 Z
测试结果
完整代码
#coding:UTF-8
import serialACCData=[0.0]*8
GYROData=[0.0]*8
AngleData=[0.0]*8
FrameState = 0 #通过0x后面的值判断属于哪一种情况
Bytenum = 0 #读取到这一段的第几位
CheckSum = 0 #求和校验位 a = [0.0]*3
w = [0.0]*3
Angle = [0.0]*3def DueData(inputdata): #新增的核心程序,对读取的数据进行划分,各自读到对应的数组里global FrameStateglobal Bytenumglobal CheckSumglobal aglobal wglobal Anglefor data in inputdata: #在输入的数据进行遍历# print(inputdata)# print(data, type(data))if FrameState==0: #当未确定状态的时候,进入以下判断if data ==0x55 and Bytenum==0: #0x55位于第一位时候,开始读取数据,增大bytenumCheckSum=dataBytenum=1continueelif data==0x51 and Bytenum==1:#在byte不为0 且 识别到 0x51 的时候,改变frameCheckSum+=dataFrameState=1Bytenum=2elif data==0x52 and Bytenum==1: #同理CheckSum+=dataFrameState=2Bytenum=2elif data==0x53 and Bytenum==1:CheckSum+=dataFrameState=3Bytenum=2elif FrameState==1: # acc #已确定数据代表加速度if Bytenum<10: # 读取8个数据ACCData[Bytenum-2]=data # 从0开始CheckSum+=dataBytenum+=1else:if data == (CheckSum&0xff): #假如校验位正确a = get_acc(ACCData)CheckSum=0 #各数据归零,进行新的循环判断Bytenum=0FrameState=0elif FrameState==2: # gyroif Bytenum<10:GYROData[Bytenum-2]=dataCheckSum+=dataBytenum+=1else:if data == (CheckSum&0xff):w = get_gyro(GYROData)CheckSum=0Bytenum=0FrameState=0elif FrameState==3: # angleif Bytenum<10:AngleData[Bytenum-2]=dataCheckSum+=dataBytenum+=1else:if data == (CheckSum&0xff):Angle = get_angle(AngleData)d = a+w+Angleprint("a(g):%10.3f %10.3f %10.3f w(deg/s):%10.3f %10.3f %10.3f Angle(deg):%10.3f %10.3f %10.3f"%d)CheckSum=0Bytenum=0FrameState=0def get_acc(datahex): axl = datahex[0] axh = datahex[1]ayl = datahex[2] ayh = datahex[3]azl = datahex[4] azh = datahex[5]k_acc = 16.0acc_x = (axh << 8 | axl) / 32768.0 * k_accacc_y = (ayh << 8 | ayl) / 32768.0 * k_accacc_z = (azh << 8 | azl) / 32768.0 * k_accif acc_x >= k_acc:acc_x -= 2 * k_accif acc_y >= k_acc:acc_y -= 2 * k_accif acc_z >= k_acc:acc_z-= 2 * k_accreturn acc_x,acc_y,acc_zdef get_gyro(datahex): wxl = datahex[0] wxh = datahex[1]wyl = datahex[2] wyh = datahex[3]wzl = datahex[4] wzh = datahex[5]k_gyro = 2000.0gyro_x = (wxh << 8 | wxl) / 32768.0 * k_gyrogyro_y = (wyh << 8 | wyl) / 32768.0 * k_gyrogyro_z = (wzh << 8 | wzl) / 32768.0 * k_gyroif gyro_x >= k_gyro:gyro_x -= 2 * k_gyroif gyro_y >= k_gyro:gyro_y -= 2 * k_gyroif gyro_z >=k_gyro:gyro_z-= 2 * k_gyroreturn gyro_x,gyro_y,gyro_zdef get_angle(datahex): rxl = datahex[0] rxh = datahex[1]ryl = datahex[2] ryh = datahex[3]rzl = datahex[4] rzh = datahex[5]k_angle = 180.0angle_x = (rxh << 8 | rxl) / 32768.0 * k_angleangle_y = (ryh << 8 | ryl) / 32768.0 * k_angleangle_z = (rzh << 8 | rzl) / 32768.0 * k_angleif angle_x >= k_angle:angle_x -= 2 * k_angleif angle_y >= k_angle:angle_y -= 2 * k_angleif angle_z >=k_angle:angle_z-= 2 * k_anglereturn angle_x,angle_y,angle_zif __name__=='__main__': port = '/dev/ttyUSB0' # use '/dev/ttyAMA0' for USB or '/dev/ttyAMA0' for GPIObaud = 9600 # baudrateser = serial.Serial(port, baud, timeout=0.5) # ser = serial.Serial('com7',115200, timeout=0.5) if ser.is_open:print('The serial port was opened successfully!')while True:datahex = ser.read(33) # How many bytes are read from the portDueData(datahex)else:print('Failed to open the serial!')