arduino 串口实时绘图
兴趣之余,利用晚上的时间,做一些个人兴趣方面的开发. 之前没接触过 arduino, 无意之中买了个开发板做一些小开发, 这里利用python 读取 mpu9250 数据实时绘图.
下位机代码 C++
void Serial_SendDataPython( int16_t *sendData, uint8_t lens )
{
uint8_t tmpData[32] = {0}; // tmpData lens >= 2 * lens + 4
uint8_t *ptrData = tmpData;
uint8_t dataBytes = lens << 1;
uint8_t dataLens = dataBytes + 4;
uint8_t count = 0;
uint16_t tmpSum = 0;
tmpData[0] = 'S';
while(count < dataBytes) {
// tmpData[count+1] = Byte8H(sendData[count >> 1]);
// tmpData[count+2] = Byte8L(sendData[count >> 1]);
tmpData[count+1] = (sendData[count >> 1])>>8;
tmpData[count+2] = (sendData[count >> 1])&0x00ff; ;
count = count + 2;
}
for(uint8_t i = 0; i < dataBytes; i++)
tmpSum += tmpData[i+1];
tmpData[dataLens - 3] = (uint8_t)(tmpSum & 0x00FF);
tmpData[dataLens - 2] = '\r';
tmpData[dataLens - 1] = '\n';
do {
//Serial_SendByte(*ptrData++);
Serial.write(*ptrData++);
} while(--dataLens);
}
....................................
IMU_Buf[0] = testLostRate++;
MU_Buf[1] = ax/2;
IMU_Buf[2] = ay/2;
IMU_Buf[3] = az/2;
IMU_Buf[4] = gx/2;
IMU_Buf[5] = gy/2;
IMU_Buf[6] = gz/2;
IMU_Buf[7] = mx/2;
IMU_Buf[8] = my/2;
IMU_Buf[9] = mz/2;
Serial_SendDataMATLAB(IMU_Buf, 10);
.................................................
这里简要说明一下, 发送数据以'S'开头,传感器数据分低8位和高8位数据分别发送,最后以换行符结尾.
"""
ldr.py
http://electronut.in/plotting-real-time-data-from-arduino-using-python/
Display analog data from Arduino using Python (matplotlib)
Author: Mahesh Venkitachalam
Website: electronut.in
"""
import ctypes
import sys, serial, argparse
import numpy as np
from time import sleep
from collections import deque
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# plot class
class AnalogPlot:
# constr
def __init__(self, strPort, maxLen):
# open serial port
self.ser = serial.Serial(strPort, 38400)
self.ax = deque([0.0]*maxLen)
self.ay = deque([0.0]*maxLen)
self.az = deque([0.0]*maxLen)
self.gx = deque([0.0]*maxLen)
self.gy = deque([0.0]*maxLen)
self.gz = deque([0.0]*maxLen)
self.mx = deque([0.0]*maxLen)
self.my = deque([0.0]*maxLen)
self.mz = deque([0.0]*maxLen)
self.maxLen = maxLen
# add to buffer
def addToBuf(self, buf, val):
if len(buf) < self.maxLen:
buf.append(val)
else:
buf.pop()
buf.appendleft(val)
# add data
def add(self, data):
assert(len(data) == 9)
self.addToBuf(self.ax, data[0])
self.addToBuf(self.ay, data[1])
self.addToBuf(self.az, data[2])
self.addToBuf(self.gx, data[3])
self.addToBuf(self.gy, data[4])
self.addToBuf(self.gz, data[5])
self.addToBuf(self.mx, data[6])
self.addToBuf(self.my, data[7])
self.addToBuf(self.mz, data[8])
# update plot
def update(self,frameNum,a0,a1,a2,a3,a4,a5,a6,a7,a8):
try:
data = self.ser.readline()
length = len(data)
if length == 24 and ord(data[0])== 83:
count = (ord(data[1])<<8)+ord(data[2])
value = (ord(data[3])<<8)+ord(data[4])
ax = ctypes.c_int16(value).value
value = (ord(data[5])<<8)+ord(data[6])
ay = ctypes.c_int16(value).value
value = (ord(data[7])<<8)+ord(data[8])
az = ctypes.c_int16(value).value
value = (ord(data[9])<<8)+ord(data[10])
gx = ctypes.c_int16(value).value
value = (ord(data[11])<<8)+ord(data[12])
gy = ctypes.c_int16(value).value
value = (ord(data[13])<<8)+ord(data[14])
gz = ctypes.c_int16(value).value
value = (ord(data[15])<<8)+ord(data[16])
mx = ctypes.c_int16(value).value
value = (ord(data[17])<<8)+ord(data[18])
my = ctypes.c_int16(value).value
value = (ord(data[19])<<8)+ord(data[20])
mz = ctypes.c_int16(value).value
array = [ax,ay,az,gx,gy,gz,mx,my,mz]
print array
self.add(array)
a0.set_data(range(self.maxLen), self.ax)
a1.set_data(range(self.maxLen), self.ay)
a2.set_data(range(self.maxLen), self.az)
a3.set_data(range(self.maxLen), self.gx)
a4.set_data(range(self.maxLen), self.gy)
a5.set_data(range(self.maxLen), self.gz)
a6.set_data(range(self.maxLen), self.mx)
a7.set_data(range(self.maxLen), self.my)
a8.set_data(range(self.maxLen), self.mz)
except KeyboardInterrupt:
print('exiting')
return a0,
# clean up
def close(self):
# close serial
self.ser.flush()
self.ser.close()
# main() function
def main():
# create parser
#parser = argparse.ArgumentParser(description="LDR serial")
# add expected arguments
#parser.add_argument('--port', dest='port', required=True)
# parse args
#args = parser.parse_args()
strPort = 'COM3'
#strPort = args.port
print('reading from serial port %s...' % strPort)
# plot parameters
analogPlot = AnalogPlot(strPort, 100)
print('plotting data...')
# set up animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 100), ylim=(-20000, 20000))
a0, = ax.plot([], [])
a1, = ax.plot([], [])
a2, = ax.plot([], [])
a3, = ax.plot([], [])
a4, = ax.plot([], [])
a5, = ax.plot([], [])
a6, = ax.plot([], [])
a7, = ax.plot([], [])
a8, = ax.plot([], [])
anim = animation.FuncAnimation(fig, analogPlot.update,
fargs=(a0,a1,a2,a3,a4,a5,a6,a7,a8),
interval=50)
# show plot
plt.show()
# clean up
analogPlot.close()
print('exiting.')
# call main
if __name__ == '__main__':
main()
运行结果如下图:
从互联网搜索了一下,可以串口绘图的工具很多,试了一下 SerialChart工具,感觉还不错,界面如下:
下位机数据格式较简单:
interval(两次数据获取时间间隔,可设置为0),ax,ay,az 为int 类型,
Serial.print(interval); //microseconds since last sample, please note that printing more data will increase interval
Serial.print(",");
Serial.print(ax); //Inclination X axis (as measured by accelerometer)
Serial.print(",");
Serial.print(ay); //Inclination X axis (estimated / filtered)
Serial.print(",");
Serial.print(az); //Inclination X axis (estimated / filtered)
Serial.println("");
具体使用方法请参见官方网站: https://en.wikiversity.org/wiki/SerialChart_Tutorial ,这里有详细说明和配置方法.
总结: 利用 python 读取seria 数据似乎效率不怎么高, 和之前matlab 测试遇到的情况情况类似,容易出现卡顿的情况. 下篇博客我将会介绍数据可视化工具 Processing在这方便的用途和代码.
参考,引用:
http://electronut.in/plotting-real-time-data-from-arduino-using-python/
https://en.wikiversity.org/wiki/SerialChart_Tutorial