嵌入式开发日记(3)——利用Python接收并处理JY61传感器数据
之前介绍过,项目的第一项操作是要采集帕金森病人的震颤数据,整体架构图如下:
这里采用的是一款基于MPU6050的JY61型号传感器,好处在于内置卡尔曼滤波,直接可以通过串口输出六轴数据,大大方便了编程效率。模块如图:
其产品介绍如下(摘自使用说明书):
此六轴模块采用高精度的陀螺加速度计 MPU6050,通过处理器读取 MPU6050 的测量数据
然后通过串口输出,同时精心的 PCB 布局和工艺保证了 MPU6050 收到外接的干扰最小,
测量的精度最高。
模块内部自带电压稳定电路,可以兼容 3.3V/5V 的嵌入式系统,连接方便。
采用先进的数字滤波技术,能有效降低测量噪声,提高测量精度。
模块内部集成了姿态解算器,配合动态卡尔曼滤波算法,能够在动态环境下准确输出
模块的当前姿态,姿态测量精度 0.05 度,稳定性极高,性能甚至优于某些专业的倾角
仪!
采用邮票孔镀金工艺,品质保证,可嵌入用户的 PCB 板中。
性能参数:
、电压:3.3V~5V
2、电流:<10mA
3、体积:51.3mm X 36mm X 15mm
4、焊盘间距:上下 100mil(2.54mm),左右 600mil(15.24mm)
5、测量维度:加速度:3 维,角速度:3 维,角度:3 维
6、量程:加速度:±16g,角速度:±2000deg/s,角度 X Z 轴±180° Y 轴±90°。
7、分辨率:加速度:0.0005g,角速度:0.61°/s。
8、测量精度:静态 0.05°,动态 0.1°。
9、数据输出内容:时间、加速度、角速度、角度。
10、数据输出频率:100HZ(波特率 115200)/20HZ(波特率 9600)。
11、波特率:9600kps、115200kps(默认)。
12、数据接口:串口(TTL/232 电平)可选。
经测试,用在我的项目里精度已经足够。采用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_accreturn 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 = 16acc_x = (axh << 8 | axl) / 32768 * k_accacc_y = (ayh << 8 | ayl) / 32768 * k_accacc_z = (azh << 8 | azl) / 32768 * 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_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 = 2000gyro_x = (wxh << 8 | wxl) / 32768 * k_gyrogyro_y = (wyh << 8 | wyl) / 32768 * k_gyrogyro_z = (wzh << 8 | wzl) / 32768 * 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_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 = 180angle_x = (rxh << 8 | rxl) / 32768 * k_angleangle_y = (ryh << 8 | ryl) / 32768 * k_angleangle_z = (rzh << 8 | rzl) / 32768 * 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_zser = 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 serialACCData=[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 Bytenumglobal CheckSumfor data in inputdata: #在输入的数据进行遍历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): #假如校验位正确print(get_acc(ACCData))CheckSum=0 #各数据归零,进行新的循环判断Bytenum=0FrameState=0elif FrameState==2: # gyroif Bytenum<10:GYROData[Bytenum-2]=dataCheckSum+=dataBytenum+=1else:if data == (CheckSum&0xff):print(get_gyro(GYROData))CheckSum=0Bytenum=0FrameState=0elif FrameState==3: # angleif Bytenum<10:AngleData[Bytenum-2]=dataCheckSum+=dataBytenum+=1else:if data == (CheckSum&0xff):print(get_angle(AngleData))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 = 16acc_x = (axh << 8 | axl) / 32768 * k_accacc_y = (ayh << 8 | ayl) / 32768 * k_accacc_z = (azh << 8 | azl) / 32768 * 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 = 2000gyro_x = (wxh << 8 | wxl) / 32768 * k_gyrogyro_y = (wyh << 8 | wyl) / 32768 * k_gyrogyro_z = (wzh << 8 | wzl) / 32768 * 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 = 180angle_x = (rxh << 8 | rxl) / 32768 * k_angleangle_y = (ryh << 8 | ryl) / 32768 * k_angleangle_z = (rzh << 8 | rzl) / 32768 * 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__': #主函数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 2013by Zhaowenserial mpu6050 module can be found in the link below:http://item.taobao.com/item.htm?id=19785706431*/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;}}
}
需要注意的问题有:
利用python的pyserial模块注意不能出现占用端口的现象更改程序要注意端口是否对应不关闭串口再循环的时候,会出现串口被占用的错误字符串要进行类型转换才能参与计算try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。
如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)。
如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
改进版代码的github地址如下,读取并记录到本地文件。https://github.com/hanjintao1996/jy61-/tree/master
如有帮助请在github点赞,感激不尽。
参考链接: https://www.cnblogs.com/dongxiaodong/p/9992083.html 串口处理
https://www.oschina.net/question/89964_62779 常见新手错误
https://blog.csdn.net/woxiaozhi/article/details/58603865 字符串整数转换
https://blog.csdn.net/APP852045932/article/details/87995972 树莓派处理JY901
嵌入式开发日记(3)——利用Python接收并处理JY61传感器数据相关推荐
- 嵌入式开发日记(8)——用python实现FIR滤波(未完待续)
第一阶段的方法是根据单位时间内的加速度绝对值差值来判断震颤程度,存在很多问题.因此设想采用更加高级的算法来加以改进. 这部分的主要工作有: 1 学习数字信号处理的滤波算法,重点学习python下使用 ...
- python为啥爬取数据会有重复_利用Python来爬取“吃鸡”数据,为什么别人能吃鸡?...
原标题:利用Python来爬取"吃鸡"数据,为什么别人能吃鸡? 首先,神装镇楼 背景 最近老板爱上了吃鸡(手游:全军出击),经常拉着我们开黑,只能放弃午休的时间,陪老板在沙漠里奔波 ...
- 利用python获取微信企业号打卡数据,并生成windows计划任务
利用python获取微信企业号打卡数据,并生成windows计划任务 安装python 安装第三方库 写主程序 设置Windows计划任务 由于公司的系统用的是Java版本,开通了企业号打卡之后又没有 ...
- python 实现对地图的点击_利用python和百度地图API实现数据地图标注的方法
如题,先上效果图: 主要分为两大步骤 使用python语句,通过百度地图API,对已知的地名抓取经纬度 使用百度地图API官网的html例程,修改数据部分,实现呈现效果 一.使用python语句,通过 ...
- 利用python爬取58同城简历数据
利用python爬取58同城简历数据 最近接到一个工作,需要获取58同城上面的简历信息(http://gz.58.com/qzyewu/).最开始想到是用python里面的scrapy框架制作爬虫.但 ...
- 利用python爬取58同城简历数据_利用python爬取58同城简历数据-Go语言中文社区
利用python爬取58同城简历数据 最近接到一个工作,需要获取58同城上面的简历信息(http://gz.58.com/qzyewu/).最开始想到是用python里面的scrapy框架制作爬虫.但 ...
- 使用Python读取和处理安卓传感器数据与CSV读取
使用Python读取和处理安卓传感器数据与CSV读取 计算机通过从标准输入.文件和传感器中读取数据,然后将其存储在内存中进行处理.数据处理可以是在线的,也可以是离线的,这取决于用户的喜好. 数据处理是 ...
- 【逗老师带你学IT】PRTG监控通过Python+Modbus RTU获取温湿度传感器数据
前文[逗老师带你学IT]PRTG监控通过Python+TCP Modbus获取温湿度传感器数据中我们讲了如何通过Python读取支持TCP Modbus的传感器数据.本章我们讲解下如何读取Modbus ...
- 嵌入式开发有必要学习python吗?
嵌入式与Python之间在概念上存在着明显的差异,嵌入式是一个开发领域,而python是一种编程语言. 对于新手来说,如果有时间,python是应该去学的.一方面是因为python语言本身相对简单,即 ...
- 利用python下载哨兵1号轨道数据
python下载哨兵一号轨道数据 最近因为项目需要,突然想起来自己曾写过这么一份脚本,就顺便修改了一下.首先明确一下我们的目标,根据已经下载的哨兵1号影像文件,下载哨兵1号对应的精密轨道数据.哨兵轨道 ...
最新文章
- Android按钮事件的4种写法
- Java Eclipse解决中文字体太小
- oracle高级查询用法
- C# 多线程 线程池(ThreadPool) 2 如何控制线程池?
- android122 zhihuibeijing 新闻中心NewsCenterPager加载网络数据实现
- 无线路由器怎么改密码
- window中的DLL和linux中的os文件是什么东西
- MHDD修复UNC和TIMEOUT
- android qq截屏快捷键是什么,手机截屏的快捷键是什么,超过3种截图的快捷键操作方法!...
- 2016北京集训测试赛(九)Problem C: 狂飙突进的幻想乡
- 计算机网络(四)——组建对等网
- 搭建个人网站 保姆级教程(一)云服务器购买以及环境部署
- 用bcb实 现Word 97 自 动 化
- 酱狗的杂七杂八(叁)
- swing界面如何增加日历功能
- 电子证据是计算机系统,电子证据的分类
- 如何用PLSQL导出数据库存表结构信息
- 浙江农林大学第二十届程序设计竞赛暨团体程序设计天梯赛选拔赛(同步赛) K.来自良心出题人wzc的简单题
- Yimin Xiao
- 【R语言进阶】不同数值大小的比较
热门文章
- 【Excel 教程系列第 15 篇】Excel 中的简单排序(升序 / 降序)、多条件排序、按颜色排序、自定义排序、以及巧用“升序“制作工资条
- 虚幻引擎UE4加载GIS数据《数字孪生智慧城市》
- Python的h5py模块
- H5社交漂流瓶交友源码/附安装教程
- 苹果手机怎么定位安卓手机_苹果AirPods搭配安卓手机怎么样?那是相当好
- bzoj5369loj6433 [Pkusc2018]最大前缀和
- 对称网络的电路分析方法
- 【ATSC】 为什么选择ATSC 3.0
- MyBatisPlus之逻辑删除
- 【Unity5】实现24小时日出日落的效果 24小时天幕系统