如何使用Python实现串口实时数据的动画可视化绘图
串口实时绘图问题
我需要对串口传入的数据进行实时绘图,无需通过文件读写中转数据。我了解到需要单独开启一个线程实时接收串口数据,在线程运行过程中,animation.FuncAnimation需要每次获取串口数据并完成绘图渲染,但我不清楚如何编写数据传递逻辑让动画正常运行。
这就是我目前卡壳的地方,不知道如何编码实现数据交接让动画生效,我编写的代码如下:
import serial import threading import matplotlib.pyplot as plt import matplotlib.animation as animation import itertools def thread_data_gen(): i = 0 counter = itertools.count() ser = serial.Serial('/dev/tty.SLAB_USBtoUART', 1000000, timeout=1) # 打开端口读取数据 ser.reset_input_buffer() # 清空输入缓冲区,丢弃所有缓存内容 while True: ser_bytes = ser.readline() # 逐行读取串口数据 # 接收的行格式为 -> b'$ 32079 32079 32079 32079 32079 32079 32079 32079;\r\n' # 每个值代表一个数据通道,可测量扭矩、温度等参数 # 当前所有值都设置为扭矩,所以数值完全一致 # 共有8个可用数据通道 decoded_bytes = ser_bytes.decode('utf-8') decoded_bytes = decoded_bytes.lstrip('$').rstrip().split() # 重新格式化为 ['32274', '32274', '32274', '32274', '32274', '32274', '32274', '32274;'] if i == 0: i += 1 continue # 跳过第一次读取结果,因为第一次传输的行为空,原因未知 t = next(counter) # 生成x轴数值 y = decoded_bytes[0] # 读取通道1的数值作为y轴数据 yield t, y # 尝试用生成器返回数据,但没有生效 def run(data): # 接收thread_data_gen()返回的生成器数据 t, y = data # 报错TypeError:"cannot unpack non-iterable int object",不知道怎么修复 # 我需要把运行线程里的while循环改成能返回可迭代整型数据的形式,但找不到解决方案 xdata.append(t) # 把数据加入x值列表 ydata.append(y) # 把数据加入y值列表 line.set_data(xdata, ydata) # 生成传给plt的数据集 return line, if __name__ == '__main__': dgen = threading.Thread(target=thread_data_gen) dgen.start() fig, ax = plt.subplots() line, = ax.plot([], [], lw=2) ax.grid() xdata, ydata = [], [] ani = animation.FuncAnimation(fig, run, interval=100) plt.show()
更新
我已经自行解决了这个问题,最终的实现代码如下:
# 传动系统中的传感器升级联轴器通过蓝牙输出数据 # 数据包括:扭矩、力、温度和xyz三轴加速度 # 硬件网关通过天线接收数据 # 本代码的作用是读取硬件网关的串口数据并绘图,网关通过USB-C连接到笔记本 # USB-C转UART软件桥可以在MacOS或Windows系统上将数据映射为串口设备 import time import serial import matplotlib.pyplot as plt import matplotlib.animation as animation import itertools def data_gen(): i = 0 counter = itertools.count() # 创建计数器 ser = serial.Serial('/dev/tty.SLAB_USBtoUART', 1000000, timeout=1) # 打开端口读取数据 ser.reset_input_buffer() # 清空输入缓冲区,丢弃所有缓存内容 while True: # 逐行读取串口数据 # 接收的行格式为 -> b'$ 32079 32079 32079 32079 32079 32079 32079 32079;\r\n' # 每个值代表一个数据通道,可测量扭矩、温度等参数 # 当前所有值都设置为扭矩,所以数值完全一致 # 共有8个可用数据通道 ser_bytes = ser.readline() decoded_bytes = ser_bytes.decode('utf-8') # 重新格式化为列表 ['32274', '32274', '32274', '32274', '32274', '32274', '32274', '32274;'] decoded_bytes = decoded_bytes.lstrip('$').rstrip().split() # 跳过第一次读取结果,因为第一次传输的行为空,原因未知 if i == 0: i += 1 continue t = next(counter) # 生成x轴数值 y = decoded_bytes[0] # 读取通道1的数值作为y轴数据 yield t, float(y) # 返回绘图用的x和y值 def run(data): x, y = data y_cal = round(y * 0.00166, 1) # 校准计算 xdata.append(x) # 把数据加入x值列表 ydata.append(y_cal) # 把数据加入y值列表 line.set_data(xdata, ydata) # 生成传给绘图的数据集 return line, if __name__ == '__main__': fig, ax = plt.subplots() # 初始化画布和坐标轴 line, = ax.plot([], [], lw=2) # 初始化折线 ax.set_ylim(40, 80) # 设置y轴范围 ax.set_xlim(0, 1000) # 设置x轴范围 ax.grid() # 生成网格 xdata, ydata = [], [] # 创建空数据列表 # frames参数:从串口连接接收生成的数据 # run参数:提供折线绘图数据 ani = animation.FuncAnimation(fig, run, frames=data_gen, blit=True, interval=10) plt.show()
内容的提问来源于stack exchange,提问作者Sascha
相关产品推荐
相关产品推荐

