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

Python多线程CAN总线通信脚本无法终止及值错误问题

Python-CAN多ECU通信脚本问题:无法终止+ValueError错误

问题描述

使用python-can库开发多电子控制单元(ECU1、ECU2)通信脚本,需求为读取BLF文件中的消息,按指定ID过滤后为每个ECU分配独立线程处理。但脚本无法正常终止,打印“main_ECU done”“filtering done”“ECU1 Thread has finished.”后陷入停滞;当前新增ValueError: byte must be in range(0, 256)错误。

脚本流程

  • main_ecu函数:读取BLF文件中的消息并发送至虚拟总线
  • ecu_filter函数:按指定ID过滤总线消息,接收到ID为0xDE0Q时终止线程
  • main函数:创建虚拟总线,启动两个ECU处理线程

核心代码片段

main函数

def main():
    bus = can.interface.Bus(interface='virtual', channel='0', bitrate=500000,receive_own_messages=True)

    can_id_filter_ecu1 = [0xKEREE, 0xWJKL0, oxDE0Q]
    can_id_filter_ecu_2 = [0xIOBF, oxDE0Q]

    main_ECU(bus, "input.blf")
    # 为两个ECU创建独立线程
    ecu_thread_1 = threading.Thread(target=ecu_filter,args= (bus,can_id_filter_ecu1,"File_1_msg.asc",))
    ecu_thread_2 = threading.Thread(target=ecu_filter, args=(bus,can_id_filter_ecu_2,"File_2_msg.asc",))

    ecu_thread_1.start()
    ecu_thread_2.start()

    ecu_thread_1.join()
    print("ECU1 Thread has finished.")
    ecu_thread_2.join()
    print("ECU2 Thread has finished.")
    bus.shutdown()

ecu_filter函数片段

def ecu_filter(bus, filter_ids, asc_file):
    stop_break = False
    log_ecu = can.ASCWriter(asc_file)
    msg_count = {}

    while not stop_break:
        mesg = bus.recv(1)
        print(mesg)  # 调试输出
        if mesg is not None and mesg.arbitration_id in filter_ids:
            log_ecu.log_event(mesg)
            if mesg.arbitration_id == oxDE0Q:
                stop_break = True
            elif mesg.arbitration_id in msg_count:
                msg_count[mesg.arbitration_id] += 1
            else:
                msg_count[mesg.arbitration_id] = 1
        for msg_id, count in msg_count.items():
            response_msg = can.Message(arbitration_id=msg_id, data=bytearray([count]), is_extended_id=False)
            bus.send(response_msg)
    log_ecu.stop()

错误详情

  • ValueError触发点:response_msg = can.Message(arbitration_id=msg_id,data= bytearray([count]), is_extended_id=False),原因是count值超出了字节范围(0-255)
  • 线程停滞现象:ECU1线程完成后,ECU2线程无法终止,一直处于循环等待状态

当前输出

main_ECU done
filtering done
ECU1 Thread has finished.

问题分析与修复方案

1. 修正无效十六进制ID

代码中0xKEREE、0xWJKL0、oxDE0Q均为无效十六进制值(十六进制仅支持0-9、A-F/a-f),这会导致过滤逻辑失效,线程无法触发停止条件。需改为合法值,例如:

can_id_filter_ecu1 = [0x1234, 0x5678, 0xDE0]
can_id_filter_ecu_2 = [0x9ABC, 0xDE0]

2. 修复ValueError错误

bytearray([count])要求元素必须是0-255的整数,当消息计数超过255时触发错误。可通过以下方式处理:

  • 限制计数范围:count % 256
  • 用多字节存储计数(如需更大数值):
    # 用2字节大端模式存储计数
    data = count.to_bytes(2, byteorder='big')
    response_msg = can.Message(arbitration_id=msg_id, data=data, is_extended_id=False)
    

3. 修复线程停滞问题

  • 调整执行顺序:先启动线程,再发送BLF消息,确保线程能实时接收总线消息:
    def main():
        bus = can.interface.Bus(interface='virtual', channel='0', bitrate=500000, receive_own_messages=True)
    
        # 修正后的合法ID
        can_id_filter_ecu1 = [0x1234, 0x5678, 0xDE0]
        can_id_filter_ecu_2 = [0x9ABC, 0xDE0]
    
        # 先启动线程
        ecu_thread_1 = threading.Thread(target=ecu_filter, args=(bus, can_id_filter_ecu1, "File_1_msg.asc",))
        ecu_thread_2 = threading.Thread(target=ecu_filter, args=(bus, can_id_filter_ecu_2, "File_2_msg.asc",))
        ecu_thread_1.start()
        ecu_thread_2.start()
    
        # 再发送BLF消息
        main_ECU(bus, "input.blf")
    
        # 发送停止信号
        stop_msg = can.Message(arbitration_id=0xDE0, data=b'', is_extended_id=False)
        bus.send(stop_msg)
    
        # 等待线程结束
        ecu_thread_1.join()
        print("ECU1 Thread has finished.")
        ecu_thread_2.join()
        print("ECU2 Thread has finished.")
        bus.shutdown()
    
  • 优化ecu_filter逻辑:避免重复发送响应消息,确保停止条件触发后直接退出循环:
    def ecu_filter(bus, filter_ids, asc_file):
        stop_break = False
        log_ecu = can.ASCWriter(asc_file)
        msg_count = {}
    
        while not stop_break:
            mesg = bus.recv(1)
            if mesg is not None and mesg.arbitration_id in filter_ids:
                log_ecu.log_event(mesg)
                if mesg.arbitration_id == 0xDE0:
                    stop_break = True
                    continue
                # 更新计数并发送响应
                msg_count[mesg.arbitration_id] = msg_count.get(mesg.arbitration_id, 0) + 1
                count = msg_count[mesg.arbitration_id] % 256
                response_msg = can.Message(arbitration_id=mesg.arbitration_id, data=bytearray([count]), is_extended_id=False)
                bus.send(response_msg)
        log_ecu.stop()
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:32:07