You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4多USB串口转换器pyserial时序异常问题求助

串口自动化测试批量运行时随机失败问题

环境配置

  • 树莓派4连接带外部供电的USB集线器
  • 集线器外接5个USB-Serial转换器,每个转换器连接一台低功耗STM32设备,设备通过转换器供电

测试场景

使用pytest实现自动化测试:向设备发送命令并等待响应,因设备间存在交互,需近乎同时向多台设备发送命令。

问题现象

  • 手动逐个运行测试时,整套设备工作正常
  • 批量串行运行pytest时,第一个测试总能成功,其余测试随机失败;调整代码中的延迟时间会改变失败的测试用例,不修改代码则失败模式固定
  • 所有串口、设备、布线均已单独验证正常(部分测试会用到全部设备且多次通过)

调试发现

Python代码中serial.write()返回成功,但示波器确认物理线路有时无数据传输;该现象仅随机出现,部分测试/延迟配置下数据可正常传输,排除示波器设置问题。

关键代码片段

串口通信类实现

class Link_Serial(linkcore.LinkCore):
    def __init__(self, comport, packet_queue, ack_queue, id_queue, link_address):
        super().__init__(packet_queue, ack_queue, id_queue, link_address)
        self.serial = serial.Serial(port=comport, baudrate=115200)
        self.rx_buffer = []
        self.received_packets = []
        self.events = []

    def on_transmit(self, tx_data):
        print("TX", self.serial.name, self.serial.is_open, tx_data)
        time.sleep(0.02)
        self.serial.write(tx_data)
        self.tx_done()
        return 1

    def reset(self):
        self.rx_buffer.clear()
        self.received_packets.clear()
        self.events.clear()

        self.serial.reset_input_buffer()
        self.serial.reset_output_buffer()

        super().reset()

微调time.sleep(...)的数值会导致不同测试失败

pytest fixture初始化逻辑

def get_module_n(n):

    if n >= len(modules) or n < 0:
        raise

    if radios[n] is None:
        info = modules[n]
        radios[n] = Link_Serial(...)
    radios[n].reset()
    return radios[n]

def stop_module(radio):
    radio.power_off()
    radio.reset()


...

@pytest.fixture
def radio0():
    ctrl = rack.get_module_n(0)
    yield ctrl
    rack.stop_module(ctrl)

@pytest.fixture
def radio1():
    ctrl = rack.get_module_n(1)
    yield ctrl
    rack.stop_module(ctrl)

...

时序敏感测试用例示例

def test_many_senders_one_receiver(radio0, radio1, radio2, radio3, radio4):
    time.sleep(0.1)
    radio0.power_on()
    radio1.power_on()
    radio2.power_on()
    radio3.power_on()
    radio4.power_on()
    time.sleep(0.1)

    message = [1, 2, 3, 4, 5, 6]

    for radio in [radio1, radio2, radio3, radio4]:
        radio.send_packet(radio0.id, message)

    for _ in range(0, 1000):
        rack.run_links([radio0, radio1, radio2, radio3, radio4], 10)
        if radio0.get_events().count(LINK_DATA_RECEIVED) == 4:
            break

    assert LINK_DATA_ACKED in radio1.get_events()
    print(radio2.get_events())
    assert LINK_DATA_ACKED in radio2.get_events()
    assert LINK_DATA_ACKED in radio3.get_events()
    assert LINK_DATA_ACKED in radio4.get_events()
    assert radio0.get_events().count(LINK_DATA_RECEIVED) == 4
    assert len(radio0.get_packets()) == 4

尝试过的调整

最初设置为每个测试初始化新的Link_Serial对象,仅第一个测试成功(手动单独运行所有测试正常);改为全局初始化一次对象,测试间仅执行reset操作,问题仍存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 01:37:26