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
相关产品推荐
相关产品推荐

