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)
每个接口的含义:
接口 | 作用 |
| 连接机器人,或初始化模拟机器人 |
| 获取机器人状态,例如电量、速度、模式、急停状态 |
| 发送速度命令 |
| 普通停止 |
| 急停,进入安全停止状态 |
| 切换机器人模式,例如 |
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也就是说:
state_publisher_node定时调用driver.get_state()- Driver 返回当前机器人状态
- 节点把状态发布到
/robot/state - 其他模块,比如 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()是“危险情况下立刻停,并且锁住运动”。
急停后,普通速度命令不应该继续生效。
例如:
触发 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重点是分清职责:
模块 | 职责 |
| 封装机器人底层能力 |
| ROS2 通信节点 |
| 参数和机器人类型配置 |
| 一键启动 |
| 根据配置创建不同 Driver |