Rasberry Pi 4 USB串口pyserial时序问题

问题描述 投票:0回答:1

我有一个设置,其中 Raspberry Pi 4 通过 5 个 USB 串行转换器连接到 USB 集线器 (https://www.dfrobot.com/product-104.html)

每个转换器都连接到基于 STM32 的设备。这些设备还通过 USB 转换器供电。这些设备消耗的电量并不多,USB 转换器还连接有外部电源。

我正在尝试使用 pytest 在设备上运行自动化测试。测试将命令写入设备并等待响应。设备相互交互,因此命令大致同时发送到许多设备。

如果测试是逐个手动运行的,那么设置似乎工作正常,但是当一起运行所有测试时(pytest 仍然串行运行它们,因此串行端口上的竞争条件不应该发生)第一个总是成功,但其余的似乎非常随机地失败。不过,随机性并不完全随机,因为如果我更改代码中的延迟,测试会以不同的方式失败,但如果不进行任何更改,则测试总是会以相同的方式失败。

所有端口和所有设备都被证明可以工作(有些测试使用所有设备和端口并且已经通过了很多次),因此接线应该没问题并且USB串行转换器正在工作。

我做了一些调试,注意到测试确实写入了串行端口,但有时物理线路上没有任何内容(用示波器检查)。因此,在 pytest/python 端,写入似乎成功,但线路中仍然没有数据流。这种情况仅有时发生,在某些测试/延迟配置中存在数据流动,因此范围设置也应该没问题。

这是串行数据初始化和传输的片段:

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 初始化测试对象的方式:

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

最初我有它,以便 pytest 为每个测试初始化一个新对象,但只有第一个测试成功(手动运行时所有测试都工作正常)。这样,对象就会初始化一次,并且仅在测试之间重置。

raspberry-pi serial-port pytest pyserial raspberry-pi4
1个回答
0
投票

事实证明,如果串行转换器有故障的话。工作了一段时间,然后就不再工作了。 另外,我的代码中的一个错误导致一些消息延迟了很长时间。这些问题加在一起使得问题非常难以调试。

© www.soinside.com 2019 - 2024. All rights reserved.