8.3 KiB
8.3 KiB
板卡运动控制适配说明
本文档说明如何把当前 C++ Modbus RTU 协议库迁移到真实驱动板,并对接板卡已有的运动控制模块。
迁移结论
你不需要重写 Modbus 协议层。板卡侧主要实现 MotionControlAdapter 接口,然后在串口收齐一帧 RTU 数据后调用 MotionControlBridge::process_request()。
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:
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。
推荐固件主循环
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 非空则发送
伪代码:
#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());
}
}
数据流
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["上位机读取当前位姿/状态"]
模式和状态映射建议
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
线程和中断注意事项
如果板卡上通信任务和运动控制任务不是同一个线程,需要处理共享数据同步。
flowchart TB
UartTask["通信任务<br/>调用 MotionControlBridge"] --> Shared["共享运动数据快照"]
MotionTask["运动控制任务<br/>更新轴位姿和状态"] --> Shared
Shared --> Lock["互斥锁 / 临界区 / 双缓冲"]
建议:
- 不要在串口中断里直接执行复杂运动控制逻辑;中断只收字节,完整帧交给通信任务处理。
current_pose()和current_state()应尽量只读取快照,避免阻塞。on_correction()如果运行在通信任务中,应把纠偏量写入线程安全队列或双缓冲,再由运动控制周期消费。- 如果驱动板不支持 C++ 异常,当前实现仍可使用,因为协议和适配层没有依赖异常流程。
与现有代码的关系
classDiagram
class MotionControlAdapter {
<<interface>>
+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 响应。
构建后可运行:
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()中返回板卡真实反馈。