#!/usr/bin/env python3 """车端 CAN 报文模拟器 / 上行抓包器(联调用,非工程代码)。 依据《洗消机器人遥控器通信协议20260810.xlsx》sheet RC(分类一/二/三,全部扩展帧、Intel 小端位序)。 线格式:帧头 0xAA + 32 位 canId + DLC(8) + 8 字节数据 + 校验和 + 帧尾 0xBB,共 16 字节, 多字节字段按小端排列,与 comm/car.cpp 的 CanFrame 一致。 用法示例: # 向 UI 的 9001 端口周期发 VCU 反馈,看底盘页电量/电压/车速刷新 python can_sender.py --soc 85 --volt 360 --speed 2.0 # 制造故障:MCU 码 61(电机缺相故障)+ 整系统通信异常(底盘BMS) python can_sender.py --mcu-fault 61 --comm-fault 2 # 洗消 + 气体检测仪反馈 python can_sender.py --wash disinfect --level-a 88 --press 0.3 --gas-conc 250 --gas-type 2 --gas-level 2 # 反向:绑 9000 抓 UI 下发的控制指令并解出来 python can_sender.py --listen """ import argparse import socket import struct import time HDR = 0xAA # 帧头 TAIL = 0xBB # 帧尾 # 分类一 遥控器控制指令(上行,UI → 车端) ID_CHASSIS_CMD = 0x18208081 ID_ARM_CMD1 = 0x18218081 ID_ARM_CMD2 = 0x18228081 ID_DECONTAM_CMD = 0x18238081 ID_DECONTAM_DBG = 0x18248081 ID_DETECTOR_CMD = 0x18258081 ID_EMERGENCY = 0x18268081 # 分类二/三 VCU 状态反馈(下行,车端 → UI) ID_VEHICLE_FB1 = 0x18308180 ID_VEHICLE_FB2 = 0x18318180 ID_ARM_FB1 = 0x18328180 ID_ARM_FB2 = 0x18338180 ID_ARM_FB3 = 0x18348180 ID_ARM_FB4 = 0x18358180 ID_DECONTAM_FB1 = 0x18368180 ID_DECONTAM_FB2 = 0x18378180 ID_DETECTOR_FB1 = 0x18388180 ID_DETECTOR_FB2 = 0x18398180 ID_VEHICLE_FB3 = 0x183A8180 ID_VEHICLE_FB4 = 0x183B8180 NAMES = { ID_CHASSIS_CMD: "Chassis_ControlCmd", ID_ARM_CMD1: "Arm_ControlCmd1", ID_ARM_CMD2: "Arm_ControlCmd2", ID_DECONTAM_CMD: "Decontam_ControlCmd", ID_DECONTAM_DBG: "Decontam_DebugCmd", ID_DETECTOR_CMD: "Detector_ControlCmd", ID_EMERGENCY: "Emergency_Cmd", ID_VEHICLE_FB1: "Vehicle_StatusFeedBack1", ID_VEHICLE_FB2: "Vehicle_StatusFeedBack2", ID_ARM_FB1: "Arm_StatusFeedBack1", ID_ARM_FB2: "Arm_StatusFeedBack2", ID_ARM_FB3: "Arm_StatusFeedBack3", ID_ARM_FB4: "Arm_StatusFeedBack4", ID_DECONTAM_FB1: "Decontam_StatusFeedBack1", ID_DECONTAM_FB2: "Decontam_StatusFeedBack2", ID_DETECTOR_FB1: "Detector_StatusFeedBack1", ID_DETECTOR_FB2: "Detector_StatusFeedBack2", ID_VEHICLE_FB3: "Vehicle_StatusFeedBack3", ID_VEHICLE_FB4: "Vehicle_StatusFeedBack4", } def set_bits(d, start, ln, v): """Intel(小端):起始位即最低位序号,位序由低到高,可跨字节。""" v = int(v) for i in range(ln): b = start + i m = 1 << (b & 7) if v & (1 << i): d[b >> 3] |= m else: d[b >> 3] &= ~m & 0xFF def get_bits(d, start, ln): v = 0 for i in range(ln): b = start + i if d[b >> 3] & (1 << (b & 7)): v |= 1 << i return v def get_signed(d, start, ln): raw = get_bits(d, start, ln) sign = 1 << (ln - 1) return (raw ^ sign) - sign def checksum(can_id, dlc, d): # 帧头 + canId 四字节 + DLC + 数据八字节 + 帧尾 求和取低 8 位 return (HDR + sum((can_id >> (8 * i)) & 0xFF for i in range(4)) + dlc + sum(d) + TAIL) & 0xFF def pack(can_id, d): return struct.pack("