#ifndef CAR_H #define CAR_H #include #include #include #include #include #include #include "global.h" class QSerialPort; // 摇杆量协议范围 0~4096,中位 2048(分类一各轴、Vehi_gear/Vehi_turning 通用) static const int kRcAxisMid = 2048; // CAN 反馈只给故障码,这里带上系统与中文描述: // system 取界面故障历史既有的四个分组名,desc 供页面直接显示,code 供故障查询追溯。 struct CanFault { QString system; QString code; QString desc; }; // ===================== 车端通信层(CAN 报文经 /dev/ttyS7 串口收发) ===================== // 依据《洗消机器人遥控器通信协议20260810》sheet RC 实现的 19 条报文: // 上行 分类一 7 条(遥控器 → 车端):Chassis_ControlCmd / Arm_ControlCmd1 / Arm_ControlCmd2 / // Decontam_ControlCmd / Decontam_DebugCmd / Detector_ControlCmd / Emergency_Cmd, // 按协议「报文周期时间」列分 50 / 100 / 1000ms 三组重发; // 下行 分类二/三 12 条(车端 → 遥控器):底盘 4 条、机械臂 4 条、洗消 2 条、气体检测仪 2 条, // 按 canId 分流转 handleFrame() 写入 Telemetry。 // 全部为 29 位扩展帧、信号一律 Intel(小端)位序。 // 串口是字节流,故线上帧统一为 18 字节:帧头 0x5AA5FF00 + canId + DLC + 8 字节数据 + 校验和。 // 通信超时判定:连续 2s 未收到任何合法帧则判为通信异常(最慢的下行周期 1000ms)。 class CarCommunication : public QObject { Q_OBJECT public: explicit CarCommunication(Telemetry* tel, QObject* parent = nullptr); ~CarCommunication() override; bool start(); void stop(); QString deviceName() const { return m_device; } // 行车/机械臂模式(面板旋钮或遥控器报文)→ Arm_ControlCmd1 的 Arm_modeCmd / Arm_enable void setArmMode(bool arm) { m_armMode = arm; } // ---------- 上行命令(分类一)---------- // 命令只更新本端控制状态,实际报文由周期定时器编码发送(CAN 控制帧本就是周期报文)。 // turn 非空("left"/"right")时与 dir 同时下发,支持边前进/后退边转向 void sendChassisMove(const QString& dir, double speed, const QString& turn = QString()); void sendArmMove(const QString& axis, int dir); // dir: +1 / -1 / 0(停止) void sendArmReturn(); void sendArmPause(); void sendGasStart(); void sendGasStop(); void sendWashStart(const QString& mode); // "clean" / "disinfect" void sendWashStop(); void sendBallValve(int valve, bool open); // valve: 1=D1, 2=D2 void sendPumpPower(const QString& pump, bool on); // "plunger"/"air"/"leaf" void sendPumpRpm(const QString& pump, int rpm); void sendSetParam(const QString& key, double value); void sendSelfCheckStart(); // 启动本端自检序列(不发 CAN) void sendEstop(); void sendEstopReset(); signals: void telemetryUpdated(); // 任意遥测包到达(页面据此刷新) void commOkChanged(bool ok); // 通信状态变化 void selfCheckItem(int index, bool ok); // 自检单项结果(0~9) void selfCheckDone(bool allOk); // 自检完成 void faultAppended(const QString& system, const QString& code, const QString& desc); private slots: void onReadyRead(); void onSendFast(); // 50ms 组:底盘 / 机械臂 / 急停 void onSendMid(); // 100ms 组:洗消指令 / 洗消调试 void onSendSlow(); // 1000ms 组:气体检测仪 void onHeartbeatTimeout(); void onSelfCheckTick(); private: // 收包:按 canId 分流;发包:18 字节封帧后写串口 void handleFrame(quint32 canId, const quint8* d); void sendFrame(quint32 canId, const quint8* data); void cacheFaults(); void setCommOk(bool ok); Telemetry* m_tel = nullptr; QSerialPort* m_serial = nullptr; QByteArray m_buf; // 串口字节流缓冲:帧头滑窗重同步用 QTimer* m_hbTimer = nullptr; QTimer* m_fastTimer = nullptr; QTimer* m_midTimer = nullptr; QTimer* m_slowTimer = nullptr; QTimer* m_selfCheckTimer = nullptr; QString m_device = "/dev/ttyS7"; int m_baud = 500000; bool m_lastCommOk = true; bool m_armMode = false; // 本地自检序列(CAN 矩阵无自检报文,见 .cpp TODO) int m_selfCheckIndex = 0; bool m_selfCheckFault = true; // ---- 分类一 上行控制状态 ---- // Chassis_ControlCmd 0x18208081 quint16 m_gear = kRcAxisMid; // Vehi_gear:后 0 / 中 2048 / 前 4096 quint16 m_turning = kRcAxisMid; // Vehi_turning:左 0 / 中 2048 / 右 4096 quint16 m_targetSpd = 0; // Vehi_TargetSpd,精度 0.01,0~500(0~5.00 km/h) // Arm_ControlCmd1/2 0x18218081 / 0x18228081 —— 六轴位 0~4096 quint16 m_updown = kRcAxisMid; quint16 m_leftright = kRcAxisMid; quint16 m_frontrear = kRcAxisMid; quint16 m_roll = kRcAxisMid; quint16 m_pitch = kRcAxisMid; quint16 m_yaw = kRcAxisMid; quint8 m_homingPause = 0x55; // System_homing_pause:0xAA=系统回位 0x55=暂停回位 // Decontam_ControlCmd 0x18238081 // 四个参数缓存与 config.ini 的 param/* 同源:构造时按存盘值初始化, // 页面保存时经 sendSetParam 更新,周期帧只读缓存(不再每帧读文件)。 quint8 m_decontamMode = 0; // 2=手动消除 3=手动消毒 bool m_decontamStart = false; int m_plungerFlow = 20; // PlungerPump_flow,L/min,0~24(param/pump_flow) int m_foamRatio = 6; // Expansion_ratioCmd,倍,6~12(param/foam_ratio) int m_foamPercent = 3; // Foam_ratio,%,0~10(param/foam_percent) int m_airFlow = 100; // AirComp_flow,L/min,0~340(param/air_flow) // Decontam_DebugCmd 0x18248081 bool m_debugMode = false; // 0=正常模式 1=调试模式(球阀/泵操作置 1) bool m_plungerOn = false, m_airOn = false, m_vaneOn = false; bool m_d1Open = false, m_d2Open = false; quint16 m_airRpm = 0, m_plungerRpm = 0, m_vaneRpm = 0; // Detector_ControlCmd 0x18258081 / Emergency_Cmd 0x18268081 quint8 m_detectorCmd = 0x55; // 0xAA=启动检测 0x55=停止检测 quint8 m_emergStop = 0; // 0x55=急停 0=正常 // ---- 下行故障缓存 ---- // 底盘故障由 VSFB1~4 四帧共同构成,各自重建后再合并,避免互相覆盖。 // 气体检测仪告警周期 1000ms、洗消故障 200ms,分开存放,否则后到的会把先到的清掉。 QVector m_vsf1Faults, m_vsf2Faults, m_vsf3Faults, m_vsf4Faults; QVector m_washFaults, m_pumpFaults, m_detectorFaults; QSet m_reportedFaults; // 已记入故障历史的“系统|码”,周期性报文只上报新增故障 }; #endif // CAR_H