# 板卡运动控制适配说明 本文档说明如何把当前 C++ Modbus RTU 协议库迁移到真实驱动板,并对接板卡已有的运动控制模块。 ## 迁移结论 你不需要重写 Modbus 协议层。板卡侧主要实现 `MotionControlAdapter` 接口,然后在串口收齐一帧 RTU 数据后调用 `MotionControlBridge::process_request()`。 ```mermaid flowchart LR UartRx["UART/RS-485 收完整 RTU 帧"] --> Bridge["MotionControlBridge"] Bridge --> Server["DeviceServer"] Server --> Bank["RegisterBank"] Bridge --> Adapter["MotionControlAdapter 接口"] Adapter --> Motion["板卡已有运动控制模块"] Motion --> Adapter Bridge --> UartTx["UART/RS-485 发响应帧"] ``` ## 需要实现的接口 接口定义在 `include/line_laser_modbus/motion_adapter.hpp`: ```cpp class MotionControlAdapter { public: virtual ~MotionControlAdapter() = default; virtual void on_mode_changed(WorkMode mode) = 0; virtual void on_target_pose(const Pose6D& pose) = 0; virtual void on_correction(const Pose6D& correction) = 0; [[nodiscard]] virtual Pose6D current_pose() const = 0; [[nodiscard]] virtual DeviceState current_state() const = 0; }; ``` 每个函数的含义: - `on_mode_changed()`:上位机写入 `0xD000` 模式命令字,且模式值和切换规则合法后调用。 - `on_target_pose()`:上位机写入 `0xD020 ~ 0xD02D` 目标示教位姿后调用。 - `on_correction()`:上位机写入 `0xD036 ~ 0xD043` 六轴纠偏量后调用。 - `current_pose()`:返回板卡当前实际位姿,桥接层会写入 `0xD00A ~ 0xD017`。 - `current_state()`:返回板卡当前状态字,桥接层会写入 `0xD001`。 ## 推荐固件主循环 ```mermaid sequenceDiagram participant UART as UART_RS485 participant Main as 固件主循环 participant Bridge as MotionControlBridge participant Adapter as 你的板卡适配器 participant Motion as 运动控制模块 Motion-->>Adapter: 更新当前位姿和状态 UART-->>Main: 收到完整 RTU 请求帧 Main->>Bridge: process_request(request) Bridge->>Adapter: current_pose() Bridge->>Adapter: current_state() Bridge->>Bridge: 写入当前位姿和状态寄存器 Bridge->>Bridge: DeviceServer 处理读写请求 Bridge->>Adapter: 写请求成功后回调模式/目标/纠偏 Adapter->>Motion: 转发给板卡运动控制逻辑 Bridge-->>Main: response Main-->>UART: response 非空则发送 ``` 伪代码: ```cpp #include "line_laser_modbus/motion_adapter.hpp" class BoardMotionAdapter final : public line_laser_modbus::MotionControlAdapter { public: void on_mode_changed(line_laser_modbus::WorkMode mode) override { // 调用你的板卡模式切换函数,例如 motion_set_mode(...) } void on_target_pose(const line_laser_modbus::Pose6D& pose) override { // 把目标示教位姿送入轨迹/插补/记录模块 } void on_correction(const line_laser_modbus::Pose6D& correction) override { // 把实时纠偏量送入跟踪控制模块 } line_laser_modbus::Pose6D current_pose() const override { // 从板卡轴控反馈读取当前实际 XYZABC return {}; } line_laser_modbus::DeviceState current_state() const override { // 从板卡报警、运行、急停、标定等状态生成协议状态字 return line_laser_modbus::DeviceState::StandbyReady; } }; line_laser_modbus::DeviceServer server; BoardMotionAdapter adapter; line_laser_modbus::MotionControlBridge bridge(server, adapter); void on_complete_rtu_frame(const line_laser_modbus::ByteVector& request) { const auto response = bridge.process_request(request); if (!response.empty()) { uart_send(response.data(), response.size()); } } ``` ## 数据流 ```mermaid flowchart TD HostWriteMode["上位机写模式 0xD000"] --> ServerCheck["DeviceServer 校验模式合法性"] ServerCheck --> AdapterMode["on_mode_changed(mode)"] AdapterMode --> BoardMode["板卡切换运动模式"] HostWriteTarget["上位机写目标位姿 0xD020"] --> BankTarget["RegisterBank 保存目标位姿"] BankTarget --> AdapterTarget["on_target_pose(pose)"] AdapterTarget --> BoardTarget["板卡轨迹/示教模块"] HostWriteCorrection["上位机写纠偏量 0xD036"] --> BankCorrection["RegisterBank 保存纠偏量"] BankCorrection --> AdapterCorrection["on_correction(correction)"] AdapterCorrection --> BoardCorrection["板卡实时跟踪模块"] BoardFeedback["板卡轴控反馈"] --> AdapterFeedback["current_pose/current_state"] AdapterFeedback --> BridgePublish["MotionControlBridge 发布到寄存器"] BridgePublish --> HostRead["上位机读取当前位姿/状态"] ``` ## 模式和状态映射建议 ```mermaid flowchart LR subgraph WorkMode["WorkMode 模式命令"] M0["0 待机复位"] M1["1 系统标定"] M2["2 焊前扫描示教"] M3["3 在线全轴跟踪"] M4["4 轨迹批量复现"] M5["5 紧急停止"] end subgraph BoardAction["板卡动作"] A0["清空轨迹/纠偏/停机待命"] A1["执行标定流程"] A2["接收并记录目标轨迹点"] A3["启用实时纠偏叠加"] A4["调用已保存标准轨迹"] A5["断使能/急停制动"] end M0 --> A0 M1 --> A1 M2 --> A2 M3 --> A3 M4 --> A4 M5 --> A5 ``` `current_state()` 建议从板卡真实状态生成: - 无故障待命:`DeviceState::StandbyReady` - 运动中:`DeviceState::MotionRunning` - 示教完成:`DeviceState::TeachingComplete` - 在线跟踪正常:`DeviceState::OnlineTrackingNormal` - 任意报警:`DeviceState::Alarm` - 标定完成:`DeviceState::CalibrationComplete` - 急停触发:`DeviceState::EmergencyTriggered` ## 线程和中断注意事项 如果板卡上通信任务和运动控制任务不是同一个线程,需要处理共享数据同步。 ```mermaid flowchart TB UartTask["通信任务
调用 MotionControlBridge"] --> Shared["共享运动数据快照"] MotionTask["运动控制任务
更新轴位姿和状态"] --> Shared Shared --> Lock["互斥锁 / 临界区 / 双缓冲"] ``` 建议: - 不要在串口中断里直接执行复杂运动控制逻辑;中断只收字节,完整帧交给通信任务处理。 - `current_pose()` 和 `current_state()` 应尽量只读取快照,避免阻塞。 - `on_correction()` 如果运行在通信任务中,应把纠偏量写入线程安全队列或双缓冲,再由运动控制周期消费。 - 如果驱动板不支持 C++ 异常,当前实现仍可使用,因为协议和适配层没有依赖异常流程。 ## 与现有代码的关系 ```mermaid classDiagram class MotionControlAdapter { <> +on_mode_changed(mode) +on_target_pose(pose) +on_correction(correction) +current_pose() Pose6D +current_state() DeviceState } class MotionControlBridge { -DeviceServer server_ -MotionControlAdapter adapter_ +process_request(request) +publish_feedback() } class DeviceServer { +process_request(request) +bank() } class RegisterBank { +read(address, quantity) +write(address, registers) +set_current_pose(pose) +set_state(state) } MotionControlBridge --> MotionControlAdapter MotionControlBridge --> DeviceServer DeviceServer --> RegisterBank ``` ## Demo `apps/adapter_demo.cpp` 提供了一个模拟板卡适配器: - `DemoBoardMotion` 实现 `MotionControlAdapter`。 - 上位机 demo 写入在线跟踪模式、目标位姿和纠偏量。 - 桥接层把这些写请求回调给 `DemoBoardMotion`。 - 读取当前位姿时,桥接层先从 `DemoBoardMotion::current_pose()` 发布反馈,再返回 Modbus 响应。 构建后可运行: ```bash cmake --build cpp/build --config Release cpp/build/Release/adapter_demo.exe ``` ## 最小迁移清单 - 实现一个继承 `MotionControlAdapter` 的板卡适配类。 - 在 UART/RS-485 层实现完整 RTU 帧接收和响应发送。 - 用 `MotionControlBridge::process_request()` 连接协议处理。 - 在 `on_mode_changed()` 中接入板卡模式切换。 - 在 `on_target_pose()` 中接入轨迹示教/记录模块。 - 在 `on_correction()` 中接入实时纠偏模块。 - 在 `current_pose()` 和 `current_state()` 中返回板卡真实反馈。