ROS2 多机器人通用 Driver 层复盘:BaseRobotDriver 到多平台 Mock 切换实现

1. Driver 层的作用

在机器人二次开发中,不能把所有逻辑都写在 ROS2 节点里。

ROS2 节点更适合负责:

Topic 通信 Service 调用 参数读取 launch 启动 日志输出 任务逻辑组织

而机器人底层相关能力应该交给 Driver 层,例如:

连接机器人 读取状态 发送速度 普通停止 急停 模式切换

这样设计的核心思想是:

ROS2 节点负责"通信和调度",Driver 层负责"真正控制机器人"。

后续如果从 Mock 机器人换成真实四足机器人、人形机器人或者机械臂,只需要替换 Driver,不需要大改上层 ROS2 节点。


2. BaseRobotDriver 统一接口

BaseRobotDriver 是所有机器人 Driver 的统一标准。

它不直接控制机器人,而是规定每一种机器人都应该具备哪些基础能力。

推荐接口:

connect() get_state() send_velocity(linear_x, angular_z) stop() emergency_stop() set_mode(mode)

每个接口的含义:

|--------------------|------------------------------------|
| 接口 | 作用 |
| connect() | 连接机器人,或初始化模拟机器人 |
| get_state() | 获取机器人状态,例如电量、速度、模式、急停状态 |
| send_velocity() | 发送速度命令 |
| stop() | 普通停止 |
| emergency_stop() | 急停,进入安全停止状态 |
| set_mode() | 切换机器人模式,例如 stand/walk/stop/estop |


3. MockRobotDriver 的意义

MockRobotDriver 是一个模拟机器人驱动。

它不需要真实硬件,而是在代码里模拟机器人状态和控制行为。

它可以模拟:是否连接 connected 当前模式 mode 当前电量 battery 当前线速度 linear_x

当前角速度 angular_z 是否急停 emergency_stop

示例状态:{

"connected": true,

"mode": "stand",

"battery": 87.5,

"linear_x": 0.0,

"angular_z": 0.0,

"emergency_stop": false

}

没有真实机器人时,也能先把 ROS2 通信、状态发布、速度控制、安全保护这些上层逻辑跑通。


4. /robot/state 状态发布

机器人状态是持续变化的数据,所以应该用 ROS2 Topic 发布。

推荐话题名:/robot/state

前期为了简单,可以用:std_msgs/msg/String 里面放 JSON 字符串。

数据流如下:

复制代码
MockRobotDriver
      |
      | get_state()
      v
state_publisher_node
      |
      | publish
      v
/robot/state

也就是说:

  1. state_publisher_node 定时调用 driver.get_state()
  2. Driver 返回当前机器人状态
  3. 节点把状态发布到 /robot/state
  4. 其他模块,比如 FSM、安全模块、可视化模块,都可以订阅这个状态

验证命令:ros2 topic echo /robot/state

也可以查看发布频率:ros2 topic hz /robot/state


5. /cmd_vel 速度控制

移动机器人常用 /cmd_vel 表示速度控制命令。

话题名:/cmd_vel

消息类型:geometry_msgs/msg/Twist

常用字段:linear.x # 前进 / 后退速度 angular.z # 左转 / 右转角速度

控制节点的数据流:

复制代码
/cmd_vel
   |
   | Twist 消息
   v
control_node
   |
   | 提取 linear.x 和 angular.z
   v
driver.send_velocity()

也就是说,control_node 不直接控制硬件,而是把 ROS2 收到的速度命令转交给 Driver 层。

/cmd_vel 负责 ROS2 通信,send_velocity() 负责底层控制。


6. 速度限幅

速度控制不能完全相信上游输入。

因为 /cmd_vel 可能来自:键盘控制节点 视觉闭环节点 FSM 状态机 导航模块 测试脚本

如果某个节点发出了过大的速度,机器人可能发生危险。所以控制节点里要加入速度限幅。

例如参数:max_linear_speed: 0.5 max_angular_speed: 1.0

如果收到:linear.x = 9.9 angular.z = 9.9

实际下发给 Driver 的速度应该被限制成:linear.x = 0.5 angular.z = 1.0

超过最大速度,就裁剪到安全范围内。


7. 普通停止和急停

机器人停止至少要区分两种:普通停止 stop() 急停 emergency_stop()

|--------------------|-------------|--------------|
| 功能 | 含义 | 后续能否继续运动 |
| stop() | 普通停止,把速度清零 | 可以 |
| emergency_stop() | 急停,进入安全锁定状态 | 不应该直接继续 |

stop() 是"停一下",emergency_stop() 是"危险情况下立刻停,并且锁住运动"。

急停后,普通速度命令不应该继续生效。

例如:

复制代码
触发 emergency_stop
        |
        v
速度清零
        |
        v
emergency_stop = True
        |
        v
后续 send_velocity() 被拒绝

急停可以设计成 Service:/robot/emergency_stop

调用命令:ros2 service call /robot/emergency_stop std_srvs/srv/Trigger "{}"


8. Heartbeat 心跳机制

Heartbeat 中文叫心跳机制。它用来判断控制端是否还在线。

例如控制端持续发送:/robot/heartbeat

如果机器人控制节点长时间没有收到心跳,就认为控制端可能崩溃或断开连接。

这时应该自动调用:driver.stop()

它主要解决这个危险场景:

程序崩溃后,机器人继续执行最后一次速度命令。

例如机器人正在前进,控制程序突然退出,如果没有心跳超时保护,机器人可能还会保持前进状态。

心跳逻辑可以理解为:

复制代码
如果当前时间 - 上一次心跳时间 > heartbeat_timeout
    自动停止机器人

9. 多平台 Driver 切换

为了体现"多机器人平台二次开发",不能只写一个 Mock 机器人。

可以设计多个 Driver:

复制代码
BaseRobotDriver
      |
      ├── MockRobotDriver
      ├── MockDogDriver
      └── MockHumanoidDriver

它们都实现同一套接口:connect() get_state() send_velocity() stop() emergency_stop() set_mode()

区别只是底层实现不同。

例如: MockDogDriver 模拟四足机器人

MockHumanoidDriver 模拟人形机器人

MockRobotDriver 通用模拟机器人

上层 ROS2 节点不需要知道当前是哪种机器人,只需要调用统一接口。

这就是接口抽象的价值:

上层代码不变,底层 Driver 可替换。


10. 配置文件切换机器人类型

为了避免在代码里写死机器人类型,可以使用配置文件。

例如:robot_type: mock_dog max_linear_speed: 0.5 max_angular_speed: 1.0 heartbeat_timeout: 2.0

也可以切换成:robot_type: mock_humanoid

切换机器人平台时,只改配置,不改代码。


11. 推荐项目结构

可以采用下面这种结构:

复制代码
robot_base/
├── robot_base/
│   ├── drivers/
│   │   ├── base_driver.py
│   │   ├── mock_robot_driver.py
│   │   ├── mock_dog_driver.py
│   │   └── mock_humanoid_driver.py
│   │
│   ├── nodes/
│   │   ├── state_publisher_node.py
│   │   └── control_node.py
│   │
│   ├── config/
│   │   └── robot_config.yaml
│   │
│   └── utils/
│       └── driver_factory.py
│
├── launch/
│   └── robot_base.launch.py
├── package.xml
└── setup.py

重点是分清职责:

|---------------------|-----------------|
| 模块 | 职责 |
| drivers/ | 封装机器人底层能力 |
| nodes/ | ROS2 通信节点 |
| config/ | 参数和机器人类型配置 |
| launch/ | 一键启动 |
| driver_factory.py | 根据配置创建不同 Driver |

相关推荐
我命由我123452 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
Hopebearer_3 小时前
页面突然只剩 DOM?一次静态资源版本错配排查
前端·部署
抱抱宝3 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
东风破_3 小时前
ESLint 是什么?为什么你的项目需要它?
前端·后端·代码规范
用户938515635073 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
M-Robots echo4 小时前
M-CLAW,面向具身智能的机器人任务编排开发框架
机器人·ros·鸿蒙·开源社区·m-robots
圣殿骑士-Khtangc5 小时前
Go字符串高效拼接性能对比与底层原理分析
服务器·前端·golang
BigTopOne5 小时前
【ijkplayer】 硬解码流程
前端
Axis tech6 小时前
无标记点动作捕捉 vs 惯性动作捕捉:专业从业者需要了解这些要点
科技·机器人
kyriewen6 小时前
DeepSeek Harness开源第一天我就上手了——和Claude Code的差距比想象中大
前端·ai编程·deepseek