| 
 之前介绍过,项目的第一项操作是要采集帕金森病人的震颤数据,整体架构图如下:  
  
  
 这里采用的是一款基于MPU6050的维特智能的JY61型号传感器,好处在于内置卡尔曼滤波,直接可以通过串口输出六轴数据,大大方便了编程效率。模块如图:  
其产品介绍如下(摘自使用说明书):  
性能参数:![]()   
经测试,用在我的项目里精度已经足够。采用TTL转USB线后,与我的linux开发板相连接,发现问题在于官方给出的例程不能直接拿来使用,考虑到python的通用性,因此利用python改写读取程序后分享给大家。  
无论是windows还是linux,亲测都可以通过python成功运行。注意是python3版本。 ---------------------   
第一版:由于自带例程没有python样例,因此尝试自己读取处理。 注意: 1 安装的包名叫pyserial而不是serial 2 在linux下不用安装驱动,直接利用串口调试工具即可看到串口号 读取加速度: #Initial-T 2019.4 # -*- coding: UTF-8 -*- import serial def get_acc(self):          #定义处理加速度函数  
    try:         axh = int(acchex[6:8],16)     #注意字符串转成16进制的方法         axl = int(acchex[4:6],16)     except IOError:                               print("ReadError: gyro_acc")         return (0, 0, 0)     else:                             #利用转换公式         k_acc = 16                                acc_x = (axh << 8 | axl) / 32768 * k_acc # 以acc_x为例         if acc_x >= k_acc:              acc_x -= 2 * k_acc     return acc_x while(1):     ser = serial.Serial("com6", 115200, timeout=0.5)  # 打开端口     print(ser.is_open)     acchex = (ser.read(11).hex())         #以16进制接收数据     acc = get_acc(acchex)                 #处理数据     print(acchex)      print(acc)          ser.close()                           #处理完一轮后关闭端口  
截图示意: 读取全部数据:  
#Initial-T 2019.4 # -*- coding: UTF-8 -*- import serial def get_acc(self):                                          #加速度  
    try:         axh = int(datahex[6:8],16)         axl = int(datahex[4:6], 16)         ayh = int(datahex[10:12], 16)         ayl = int(datahex[8:10], 16)         azh = int(datahex[14:16], 16)         azl = int(datahex[12:14], 16)     except IOError:         print("ReadError: gyro_acc")         return (0, 0, 0)     else:         k_acc = 16  
        acc_x = (axh << 8 | axl) / 32768 * k_acc         acc_y = (ayh << 8 | ayl) / 32768 * k_acc         acc_z = (azh << 8 | azl) / 32768 * k_acc         if acc_x >= k_acc:             acc_x -= 2 * k_acc         if acc_y >= k_acc:             acc_y -= 2 * k_acc         if acc_z >= k_acc:             acc_z-= 2 * k_acc     return acc_x,acc_y,acc_z def get_gyro(self):                                          #陀螺仪  
    try:         wxh = int(datahex[28:30], 16)         wxl = int(datahex[26:28], 16)         wyh = int(datahex[32:34], 16)         wyl = int(datahex[30:32], 16)         wzh = int(datahex[36:38], 16)         wzl = int(datahex[34:36], 16)     except IOError:         print("ReadError: gyro_acc")         return (0, 0, 0)     else:         k_gyro = 2000  
        gyro_x = (wxh << 8 | wxl) / 32768 * k_gyro         gyro_y = (wyh << 8 | wyl) / 32768 * k_gyro         gyro_z = (wzh << 8 | wzl) / 32768 * k_gyro         if gyro_x >= k_gyro:             gyro_x -= 2 * k_gyro         if gyro_y >= k_gyro:             gyro_y -= 2 * k_gyro         if gyro_z >=k_gyro:             gyro_z-= 2 * k_gyro     return gyro_x,gyro_y,gyro_z def get_angle(self):                                 #角度  
    try:         rxh = int(datahex[50:52], 16)         rxl = int(datahex[48:50], 16)         ryh = int(datahex[54:56], 16)         ryl = int(datahex[52:54], 16)         rzh = int(datahex[58:60], 16)         rzl = int(datahex[56:58], 16)     except IOError:         print("ReadError: gyro_acc")         return (0, 0, 0)     else:         k_angle = 180  
        angle_x = (rxh << 8 | rxl) / 32768 * k_angle         angle_y = (ryh << 8 | ryl) / 32768 * k_angle         angle_z = (rzh << 8 | rzl) / 32768 * k_angle         if angle_x >= k_angle:             angle_x -= 2 * k_angle         if angle_y >= k_angle:             angle_y -= 2 * k_angle         if angle_z >=k_angle:             angle_z-= 2 * k_angle     return angle_x,angle_y,angle_z  
 
 
ser = serial.Serial("com6", 115200, timeout=0.5)  # 打开端口,改到循环外,避免一直开闭串口 while(1):     print(ser.is_open)     datahex = (ser.read(33).hex())     acc = get_acc(datahex)     gyro = get_gyro(datahex)     angle = get_angle(datahex)     print(datahex)  # 读一个字节     print(acc)     print(gyro)     print(angle)     #print(acc_x,acc_y,acc_z)  
 
    #ser.close() 截图示意: 结果对比: 输出: (-0.2060546875, -0.11181640625, 3.00634765625) (0.0, 0.0, 0.0) (-2.0928955078125, 3.9166259765625, 0.0) ? 截图示意: 
 上位机 经对比,处理后数据与自带上位机数据一致。  
  
 第二版:增加了校验和的验证,使其传输更加稳定。添加了更多注释便于理解  
 #Initial-T 2019.6 import serial  
ACCData=[0.0]*8 GYROData=[0.0]*8 AngleData=[0.0]*8         #定义三个数组,分别存储加速度角速度与角度的值  
FrameState = 0            #通过0x后面的值判断属于哪一种情况 Bytenum = 0               #读取到这一段的第几位 CheckSum = 0              #求和校验位           
def DueData(inputdata):   #新增的核心程序,对读取的数据进行划分,各自读到对应的数组里     global  FrameState    #在局部修改全局变量,要进行global的定义     global  Bytenum     global  CheckSum     for data in inputdata:  #在输入的数据进行遍历         if FrameState==0:   #当未确定状态的时候,进入以下判断             if data==0x55 and Bytenum==0: #0x55位于第一位时候,开始读取数据,增大bytenum                 CheckSum=data                 Bytenum=1                 continue             elif data==0x51 and Bytenum==1:#在byte不为0 且 识别到 0x51 的时候,改变frame                 CheckSum+=data                 FrameState=1                 Bytenum=2             elif data==0x52 and Bytenum==1: #同理                 CheckSum+=data                 FrameState=2                 Bytenum=2             elif data==0x53 and Bytenum==1:                 CheckSum+=data                 FrameState=3                 Bytenum=2         elif FrameState==1: # acc    #已确定数据代表加速度             if Bytenum<10:            # 读取8个数据                 ACCData[Bytenum-2]=data # 从0开始                 CheckSum+=data                 Bytenum+=1             else:                 if data == (CheckSum&0xff):  #假如校验位正确                     print(get_acc(ACCData))                 CheckSum=0                  #各数据归零,进行新的循环判断                 Bytenum=0                 FrameState=0         elif FrameState==2: # gyro             if Bytenum<10:                 GYROData[Bytenum-2]=data                 CheckSum+=data                 Bytenum+=1             else:                 if data == (CheckSum&0xff):                     print(get_gyro(GYROData))                 CheckSum=0                 Bytenum=0                 FrameState=0         elif FrameState==3: # angle             if Bytenum<10:                 AngleData[Bytenum-2]=data                 CheckSum+=data                 Bytenum+=1             else:                 if data == (CheckSum&0xff):                     print(get_angle(AngleData))                 CheckSum=0                 Bytenum=0                 FrameState=0  
 
def get_acc(datahex):  #加速度     axl = datahex[0]                                             axh = datahex[1]     ayl = datahex[2]                                             ayh = datahex[3]     azl = datahex[4]                                             azh = datahex[5]  
    k_acc = 16  
    acc_x = (axh << 8 | axl) / 32768 * k_acc     acc_y = (ayh << 8 | ayl) / 32768 * k_acc     acc_z = (azh << 8 | azl) / 32768 * k_acc     if acc_x >= k_acc:         acc_x -= 2 * k_acc     if acc_y >= k_acc:         acc_y -= 2 * k_acc     if acc_z >= k_acc:         acc_z-= 2 * k_acc  
    return acc_x,acc_y,acc_z  
 
def get_gyro(datahex):                                          #陀螺仪     wxl = datahex[0]                                             wxh = datahex[1]     wyl = datahex[2]                                             wyh = datahex[3]     wzl = datahex[4]                                             wzh = datahex[5]     k_gyro = 2000  
    gyro_x = (wxh << 8 | wxl) / 32768 * k_gyro     gyro_y = (wyh << 8 | wyl) / 32768 * k_gyro     gyro_z = (wzh << 8 | wzl) / 32768 * k_gyro     if gyro_x >= k_gyro:         gyro_x -= 2 * k_gyro     if gyro_y >= k_gyro:         gyro_y -= 2 * k_gyro     if gyro_z >=k_gyro:         gyro_z-= 2 * k_gyro     return gyro_x,gyro_y,gyro_z  
 
def get_angle(datahex):                                 #角度     rxl = datahex[0]                                             rxh = datahex[1]     ryl = datahex[2]                                             ryh = datahex[3]     rzl = datahex[4]                                             rzh = datahex[5]     k_angle = 180  
    angle_x = (rxh << 8 | rxl) / 32768 * k_angle     angle_y = (ryh << 8 | ryl) / 32768 * k_angle     angle_z = (rzh << 8 | rzl) / 32768 * k_angle     if angle_x >= k_angle:         angle_x -= 2 * k_angle     if angle_y >= k_angle:         angle_y -= 2 * k_angle     if angle_z >=k_angle:         angle_z-= 2 * k_angle  
    return angle_x,angle_y,angle_z  
 
if __name__=='__main__':  #主函数     ser = serial.Serial("com8", 115200, timeout=0.5)  # 打开端口,改到循环外     print(ser.is_open)     while(1):         #datahex = (ser.read(33).hex()) #之前转换成了字符串,一位变成了两位         datahex = ser.read(33)       #不用hex()转化,直接用read读取的即是16进制         DueData(datahex)            #调用程序进行处理 附上Arduino读取程序样例:  
/* This code is used for connecting arduino to serial mpu6050 module, and test in arduino uno R3 board. connect map: arduino   mpu6050 module VCC    5v/3.3v TX     RX<-0 TX     TX->1 GND    GND note:  because arduino download and mpu6050 are using the same serial port, you need to un-connect 6050 module when you want to download program to arduino.  Created 14 Nov 2013  by Zhaowen  
 serial mpu6050 module can be found in the link below:  
 */  
unsigned char Re_buf[11],counter=0; unsigned char sign=0; float a[3],w[3],angle[3],T; void setup() {   // initialize serial:   Serial.begin(115200); }  
void loop() {   if(sign)   {        sign=0;      if(Re_buf[0]==0x55)      //检查帧头      {           switch(Re_buf [1])         {         case 0x51:                 a[0] = (short(Re_buf [3]<<8| Re_buf [2]))/32768.0*16;                 a[1] = (short(Re_buf [5]<<8| Re_buf [4]))/32768.0*16;                 a[2] = (short(Re_buf [7]<<8| Re_buf [6]))/32768.0*16;                 T = (short(Re_buf [9]<<8| Re_buf [8]))/340.0+36.25;                 break;         case 0x52:                 w[0] = (short(Re_buf [3]<<8| Re_buf [2]))/32768.0*2000;                 w[1] = (short(Re_buf [5]<<8| Re_buf [4]))/32768.0*2000;                 w[2] = (short(Re_buf [7]<<8| Re_buf [6]))/32768.0*2000;                 T = (short(Re_buf [9]<<8| Re_buf [8]))/340.0+36.25;                 break;         case 0x53:                 angle[0] = (short(Re_buf [3]<<8| Re_buf [2]))/32768.0*180;                 angle[1] = (short(Re_buf [5]<<8| Re_buf [4]))/32768.0*180;                 angle[2] = (short(Re_buf [7]<<8| Re_buf [6]))/32768.0*180;                 T = (short(Re_buf [9]<<8| Re_buf [8]))/340.0+36.25;                 Serial.print("a:");                 Serial.print(a[0]);Serial.print(" ");                 Serial.print(a[1]);Serial.print(" ");                 Serial.print(a[2]);Serial.print(" ");                 Serial.print("w:");                 Serial.print(w[0]);Serial.print(" ");                 Serial.print(w[1]);Serial.print(" ");                 Serial.print(w[2]);Serial.print(" ");                 Serial.print("angle:");                 Serial.print(angle[0]);Serial.print(" ");                 Serial.print(angle[1]);Serial.print(" ");                 Serial.print(angle[2]);Serial.print(" ");                 Serial.print("T:");                 Serial.println(T);                 break;         }      }   }  }  
void serialEvent() {   while (Serial.available()) {  
    //char inChar = (char)Serial.read(); Serial.print(inChar); //Output Original Data, use this code   
    Re_buf[counter]=(unsigned char)Serial.read();     if(counter==0&&Re_buf[0]!=0x55) return;      //第0号数据不是帧头                   counter++;            if(counter==11)             //接收到11个数据     {            counter=0;               //重新赋值,准备下一帧数据的接收         sign=1;     }  
  } }  截图示意:  
1、利用python的pyserial模块  
2、注意不能出现占用端口的现象 
  
3、更改程序要注意端口是否对应  
4、不关闭串口再循环的时候,会出现串口被占用的错误  
5、字符串要进行类型转换才能参与计算  
6、try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。  
7、如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。  
8、如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)。  
9、如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。 ?  |