1. 项目概述:Python串口数据采集与实时可视化系统
这个项目实现了一个完整的STM32毫米波雷达数据采集与可视化系统。通过Python串口通信获取原始距离数据,经过滑动平均滤波处理后,实时显示在动态图表中,并具备超限报警功能。系统将采集到的数据同时保存到CSV文件中,便于后续分析。
我在工业监测领域使用类似方案已有三年,这套代码虽然简洁,但包含了传感器数据处理的几个核心环节:硬件通信、数据滤波、实时显示和持久化存储。对于刚接触硬件交互的Python开发者来说,这是非常好的入门实践。
2. 核心模块解析
2.1 硬件通信层实现
串口通信是与STM32交互的基础,代码中使用了PySerial库:
python复制import serial
ser = serial.Serial(COM_PORT, BAUD_RATE, timeout=0.1)
关键参数说明:
COM_PORT:串口号,Windows通常是COMx,Linux是/dev/tty*BAUD_RATE:波特率,必须与设备端一致timeout:读取超时(秒),避免程序卡死
实际项目中我发现,115200是比较稳定的波特率选择,再高可能导致数据丢失。如果遇到乱码,首先检查波特率设置。
2.2 数据处理流水线
数据处理的完整流程如下:
- 原始数据获取:
python复制b = ser.readline() # 读取串口数据
s = b.decode("utf-8").strip() # 解码为字符串
- 数据解析:
python复制raw = int(s.replace("DIST:", "")) # 提取数值部分
- 滑动平均滤波:
python复制filt_val = filt.filter(raw) # 使用自定义滤波器
滤波器的实现采用了经典的滑动窗口算法:
python复制class MovingAverage:
def __init__(self, window_size):
self.window = window_size
self.buffer = []
def filter(self, val):
self.buffer.append(val)
if len(self.buffer) > self.window:
self.buffer.pop(0)
return sum(self.buffer)/len(self.buffer)
窗口大小FILTER_WINDOW需要根据数据特性调整:值太小滤波效果差,值太大导致响应延迟。对于毫米波雷达,5-10是比较合适的起始值。
3. 实时可视化实现
3.1 Matplotlib动态绘图
使用FuncAnimation实现动态更新:
python复制ani = animation.FuncAnimation(
fig, update, interval=100, blit=True
)
关键参数:
interval=100:每100ms刷新一次blit=True:只重绘变化部分,提升性能
3.2 图表元素配置
专业的数据可视化需要注意以下细节:
- 中文显示配置:
python复制plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams["axes.unicode_minus"] = False
- 多曲线绘制:
python复制line_filter, = ax.plot([], [], "#1286D8", linewidth=2, label="滤波后位移(mm)")
scatter_alerts = ax.scatter([],[], color="red", s=60, label="报警点")
- 坐标轴限定:
python复制ax.set_ylim(0, 1000) # 固定Y轴范围便于观察
4. 数据存储与报警机制
4.1 数据持久化方案
采用CSV格式存储,兼容性好且易于处理:
python复制with open(csv_path, "a", encoding="utf-8") as f:
f.write(f"{t},{raw},{filt_val:.1f},{status}\n")
文件格式示例:
code复制time,raw_data_mm,filter_data_mm,status
14:30:25,423,421.8,normal
14:30:26,612,610.2,alert
4.2 报警逻辑实现
双重报警机制:
- 控制台打印报警信息
python复制print(f"【报警】{t} | 原始={raw:4.0f} | 滤波={filt_val:4.1f} mm")
- 图表中标红显示异常点
python复制alert_x = [x for i, x in enumerate(x_data) if filter_data[i] > WARNING_LIMIT]
alert_y = [y for i, y in enumerate(filter_data) if filter_data[i] > WARNING_LIMIT]
scatter_alerts.set_offsets(list(zip(alert_x, alert_y)))
5. 实战经验与优化建议
5.1 常见问题排查
- 串口连接失败:
- 检查设备管理器确认串口号
- 确保没有其他程序占用串口
- 尝试重新插拔USB线
- 数据跳动严重:
- 适当增大滤波窗口
- 检查传感器供电是否稳定
- 添加硬件滤波电路
- 界面卡顿:
- 降低刷新频率(增大interval)
- 减少显示的数据点数量(MAX_POINTS)
- 关闭blit测试性能
5.2 系统扩展建议
- 增加网络功能:
python复制import socket
# 将报警信息发送到服务器
- 添加数据库支持:
python复制import sqlite3
# 存储历史数据便于分析
- 改进滤波算法:
python复制# 实现卡尔曼滤波等高级算法
- 打包为可执行文件:
bash复制pyinstaller --onefile radar_monitor.py
6. 完整代码结构回顾
整个项目的模块化设计如下:
- 配置区块:定义串口参数、报警阈值等
- 硬件层:串口初始化与通信
- 处理层:数据滤波与报警判断
- 展示层:实时图表绘制
- 存储层:CSV数据记录
这种结构清晰且易于维护,我在多个工业监测项目中都采用了类似架构。对于初学者来说,可以先用这个框架熟悉各环节,再逐步替换各个模块的实现。
