You need to enable JavaScript to run this app. 如何在Python中设置serial.readline()采样率 实现500次/秒稳定串口读取
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中设置serial.readline()采样率 实现500次/秒稳定串口读取

串口固定500Hz采样的可控实现方案

原代码波动原因

  • 依赖time()计时精度不足,常规time()在多数系统下精度仅为10~16ms,无法满足2ms间隔的控制需求
  • ser.readline()为阻塞调用,串口无可用数据时会一直等待到超时,单次执行耗时不稳定
  • 动态append numpy数组会触发频繁的内存重新分配,额外开销波动大,进一步干扰采样间隔
  • 未做显式的间隔控制,循环执行速度完全受串口返回速度、系统调度影响,采样率自然不稳定

可行实现方案

优先使用高精度计时器+忙等待控制间隔+预分配存储空间的方案,兼顾精度和易用性,代码示例如下:

import numpy as np
from time import perf_counter
import serial

# 串口配置
ser = serial.Serial('COM3', 115200, timeout=0.001)  # 超时设为1ms,远小于2ms间隔,避免长时间阻塞
ser.flushInput()

# 采样参数
sample_rate = 500  # Hz
interval = 1 / sample_rate  # 2ms
duration = 60  # 秒
total_samples = int(sample_rate * duration)

# 预分配存储空间,避免动态扩容开销
digital_data = [None] * total_samples
sample_idx = 0

start_time = perf_counter()
next_sample_time = start_time + interval

while sample_idx < total_samples:
    current_time = perf_counter()
    # 到达采样时间点
    if current_time >= next_sample_time:
        # 读取串口数据
        if ser.in_waiting:  # 先判断有数据再读,进一步降低阻塞概率
            line = ser.readline().decode('utf-8').strip()
            digital_data[sample_idx] = line
        else:
            digital_data[sample_idx] = None  # 无数据时填占位符,避免索引错位
        sample_idx += 1
        next_sample_time = start_time + sample_idx * interval  # 对齐基准时间,避免误差累积
    # 不需要极致精度时可取消下面两行注释,降低CPU占用
    # else:
    #     time.sleep(0.0005)

# 过滤空值转numpy数组
digital_data = np.array([x for x in digital_data if x is not None])
print(f"实际有效采样数: {len(digital_data)}")

ser.close()

额外优化建议

  • 若对CPU占用敏感,Windows系统可调用winmm.dll的多媒体定时器,Linux系统可使用nanosleep实现更高精度的低占用休眠
  • 确认硬件端串口发送速率匹配500Hz,115200波特率下单次数据包最大长度不能超过23字节(含换行符),否则会出现硬件发送瓶颈导致丢包
  • 如果要求完全不丢采样点,可拆分读写逻辑:单独开一个子线程持续读取串口数据存入队列,主线程按固定间隔从队列中取数,完全隔离串口读取阻塞对定时的影响

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 04:15:01