ROS2核心概念与架构详解:从零理解新一代机器人操作系统
基于Jazzy Jalisco LTS(支持至2029年),从DDS通信底层到上层API,讲解ROS2的架构设计、核心概念与开发环境搭建。适合ROS1老手迁移、ROS零基础入门、以及想理解ROS2设计哲学的开发者。
一、ROS2是什么?
ROS2(Robot Operating System 2)不是传统意义上的操作系统,而是一套分布式机器人软件框架。它运行在Linux/Windows/macOS之上,提供硬件抽象、进程间通信、包管理和常用算法库。
核心设计目标
| 目标 | 实现方式 |
|---|---|
| 去中心化 | 无Master节点,基于DDS自发现 |
| 实时性 | 支持实时操作系统和实时调度 |
| 安全性 | DDS-Security提供认证加密 |
| 跨平台 | Ubuntu 24.04 / Windows 10 / macOS |
| 多语言 | C++17 / Python 3.10+ / Rust |
版本说明:Jazzy Jalisco是第10个ROS2发行版,2024年5月发布,LTS支持至2029年5月。推荐搭配Gazebo Harmonic仿真器。前一版Humble Hawksbill(Ubuntu 22.04)仍被广泛使用但逐步退役。
二、ROS2 vs ROS1:为什么要升级?
架构对比
flowchart LR
subgraph ROS1["ROS1架构(中心化)"]
direction TB
M1["Master节点\n(单点故障风险)"]
N1["Node A"]
N2["Node B"]
N1 -->|"注册"| M1
N2 -->|"注册"| M1
N1 <-.->|"TCP/UDP直连"| N2
end
ROS1 -.->|"对比"| ROS2
subgraph ROS2["ROS2架构(去中心化)"]
direction TB
DDS["DDS中间件\n(自发现)"]
N3["Node A"]
N4["Node B"]
N3 <-->|"自动发现+通信"| DDS
N4 <-->|"自动发现+通信"| DDS
end
style ROS1 fill:#FFEBEE,stroke:#D32F2F
style ROS2 fill:#E8F5E9,stroke:#388E3C
style M1 fill:#FFCDD2
style DDS fill:#C8E6C9
关键差异:
| 特性 | ROS1 | ROS2 |
|---|---|---|
| 通信中间件 | 自研TCP/UDP | DDS(工业标准) |
| 发现机制 | Master节点(XML-RPC) | DDS自发现 |
| 参数管理 | 全局参数服务器 | 节点本地参数 |
| QoS配置 | 无 | 可配置可靠性、持久性、深度 |
| 节点生命周期 | 无 | 状态机管理(Unconfigured→Active) |
| 安全 | 无 | DDS-Security认证加密 |
| 推荐OS | Ubuntu 20.04 | Ubuntu 24.04 |
| Python版本 | Python 2.7/3 | Python 3.10+ |
| 推荐仿真器 | Gazebo Classic | Gazebo Harmonic |
三、DDS通信层:ROS2的"神经网络"
四层架构
flowchart TB
subgraph 用户层["用户应用层"]
N1["Node A<br/>(Python)"]
N2["Node B<br/>(C++)"]
end
subgraph RCL["ROS客户端库 (rcl)"]
RCL1["rclpy<br/>Python绑定"]
RCL2["rclcpp<br/>C++绑定"]
RCLC["rcl<br/>C核心库"]
end
subgraph RMW["ROS中间件接口(rmw)"]
FAST["rmw_fastrtps<br/>(默认)"]
CYCLONE["rmw_cyclonedds"]
end
subgraph DDS["DDS实现层"]
FAST_DDS["eProsima Fast DDS"]
CYCLONE_DDS["Eclipse Cyclone DDS"]
end
N1 --> RCL1 --> RCLC
N2 --> RCL2 --> RCLC
RCLC --> RMW
RMW --> DDS
style 用户层 fill:#E3F2FD,stroke:#1976D2
style RCL fill:#FFF8E1,stroke:#F57C00
style RMW fill:#F3E5F5,stroke:#7B1FA2
style DDS fill:#E8F5E9,stroke:#388E3C
逐层解释:
- 用户应用层:开发者编写的ROS2节点,调用rclcpp或rclpy的API
- RCL(ROS Client Library):C语言核心库
rcl,上层提供rclcpp(C++)和rclpy(Python)绑定 - RMW(ROS Middleware):抽象DDS层,通过
rmw_fastrtps或rmw_cyclonedds适配不同DDS实现 - DDS实现层:Jazzy默认使用eProsima Fast DDS 2.14,也支持Eclipse Cyclone DDS
DDS vs ROS1的核心优势
DDS的自发现机制替代了ROS1的Master节点。节点启动后自动通过DDS协议发现网络中的其他节点和话题,无需中央服务器。这带来了三个关键好处:
- 无单点故障:任何节点崩溃不影响整体系统
- 动态加入/离开:机器人运行中可以随时加入新的传感器或计算节点
- 跨网络通信:不同机器上的ROS2节点通过DDS直接通信
# 查看当前使用的DDS实现
echo $RMW_IMPLEMENTATION
# 默认输出: rmw_fastrtps_cpp
# 切换到Cyclone DDS
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
四、五大核心概念
1. 节点(Node)
节点是ROS2的最小执行单元。每个节点是一个独立进程,负责一个具体功能。
# minimal_node.py — 最简ROS2节点
import rclpy
from rclpy.node import Node
class MinimalNode(Node):
def __init__(self):
super().__init__('minimal_node')
self.get_logger().info('ROS2节点已启动!')
def main():
rclpy.init()
node = MinimalNode()
rclpy.spin(node) # 阻塞等待回调
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
运行命令:
来自 linuxros.cn · linuxROS
# 安装ROS2 (Ubuntu 24.04)
# 详见: https://docs.ros.org/en/jazzy/Installation.html
ros2 run my_package minimal_node
2. 话题(Topic)
话题采用发布-订阅模式,是ROS2中最常用的通信方式,适用于连续数据流。
| 特性 | 说明 |
|---|---|
| 通信模式 | 发布者→话题→订阅者 |
| 方向性 | 单向(One-way) |
| 适用场景 | 传感器数据流、状态广播 |
| 典型消息 | sensor_msgs/Image、nav_msgs/Odometry |
# 发布者示例
self.publisher = self.create_publisher(String, 'chatter', 10)
msg = String()
msg.data = 'Hello ROS2!'
self.publisher.publish(msg)
3. 服务(Service)
服务采用请求-响应模式,适合单次交互。
| 特性 | 说明 |
|---|---|
| 通信模式 | 客户端→服务端→响应 |
| 方向性 | 双向(Two-way) |
| 适用场景 | 参数查询、触发计算 |
# 服务端示例
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.callback)
def callback(self, request, response):
response.sum = request.a + request.b
return response
4. 动作(Action)
动作是带反馈的异步任务,适合长时间执行的操作。
| 特性 | 说明 |
|---|---|
| 通信模式 | 客户端→服务端(目标+反馈+结果) |
| 方向性 | 双向 |
| 特色 | 可中途取消、实时反馈进度 |
| 适用场景 | 导航到目标点、机械臂运动 |
# 动作反馈示例
goal_handle.publish_feedback(feedback_msg) # 发布进度
goal_handle.succeed() # 标记完成
result = Fibonacci.Result()
result.sequence = feedback_msg.partial_sequence
return result
5. 参数(Parameter)
参数是节点的运行时配置,支持动态修改,带类型检查和范围约束。
# 声明参数(带范围和描述)
from rcl_interfaces.msg import ParameterDescriptor, IntegerRange
descriptor = ParameterDescriptor(
description='最大线速度(m/s)',
integer_range=[IntegerRange(from_value=0, to_value=100, step=1)]
)
self.declare_parameter('max_speed', 50, descriptor)
五大概念对比总览
| 概念 | 通信模式 | 方向 | 适用场景 |
|---|---|---|---|
| 话题 | 发布-订阅 | 单向 | 传感器数据流 |
| 服务 | 请求-响应 | 双向 | 单次计算/查询 |
| 动作 | 目标-反馈-结果 | 双向 | 长时间任务 |
| 参数 | 键值配置 | - | 运行时配置 |
五、QoS(服务质量)策略
ROS2对比ROS1的一个关键增强就是QoS策略,可以精细控制数据传输行为。
核心QoS策略
| 策略 | 选项 | 含义 |
|---|---|---|
| Reliability | RELIABLE / BEST_EFFORT | 可靠传输 vs 尽力而为 |
| Durability | VOLATILE / TRANSIENT_LOCAL | 新订阅者能否收到历史消息 |
| History | KEEP_LAST / KEEP_ALL | 保留最近N条 vs 全部保留 |
| Depth | 整数 | 缓存队列深度 |
| Deadline | 时间间隔 | 消息最大间隔时间 |
实战配置示例
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy, HistoryPolicy
# 场景1:传感器数据(允许丢帧,低延迟优先)
sensor_qos = QoSProfile(
reliability=ReliabilityPolicy.BEST_EFFORT,
durability=DurabilityPolicy.VOLATILE,
history=HistoryPolicy.KEEP_LAST,
depth=5
)
# 场景2:控制指令(不允许丢失)
control_qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
durability=DurabilityPolicy.VOLATILE,
history=HistoryPolicy.KEEP_LAST,
depth=10
)
# 场景3:状态数据(晚加入也能获取最新状态)
status_qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
durability=DurabilityPolicy.TRANSIENT_LOCAL,
history=HistoryPolicy.KEEP_LAST,
depth=1
)
六、工作空间与文件结构
标准工作空间
ros2_ws/
├── src/ # 源代码目录
│ ├── my_package/ # Python包
│ │ ├── my_package/ # 代码目录
│ │ │ ├── __init__.py
│ │ │ └── my_node.py
│ │ ├── launch/ # Launch文件
│ │ ├── config/ # 参数YAML
│ │ ├── package.xml # 包清单
│ │ └── setup.py # Python安装配置
│ └── my_interfaces/ # 自定义接口包
│ ├── msg/ # 自定义消息
│ ├── srv/ # 自定义服务
│ ├── action/ # 自定义动作
│ ├── CMakeLists.txt # CMake构建
│ └── package.xml
├── build/ # 编译中间产物
├── install/ # 安装产物
└── log/ # 日志
创建和构建
# 创建工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
# 创建Python包
ros2 pkg create --build-type ament_python my_package \
--dependencies rclpy std_msgs
# 创建C++包
ros2 pkg create --build-type ament_cmake my_cpp_package \
--dependencies rclcpp std_msgs
# 创建接口包(消息/服务/动作)
ros2 pkg create --build-type ament_cmake my_interfaces \
--dependencies rosidl_default_generators
# 构建
colcon build --symlink-install
source install/setup.bash
七、常用命令行工具速查
# === 节点 ===
ros2 node list # 列出所有节点
ros2 node info /node_name # 查看节点详情
# === 话题 ===
ros2 topic list # 列出所有话题
ros2 topic list -t # 列出话题及类型
ros2 topic echo /topic_name # 实时查看数据
ros2 topic info /topic_name # 查看话题信息
ros2 topic hz /topic_name # 查看发布频率
ros2 topic pub /topic std_msgs/msg/String "data: 'hello'"
# === 服务 ===
ros2 service list # 列出所有服务
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5, b: 3}"
# === 动作 ===
ros2 action list # 列出所有动作
ros2 action send_goal /fibonacci action_tutorials_interfaces/action/Fibonacci "{order: 10}"
# === 参数 ===
ros2 param list /node_name # 列出节点的参数
ros2 param get /node_name param # 获取参数值
ros2 param set /node_name param value # 设置参数值
# === 数据记录 ===
ros2 bag record /topic1 /topic2 # 录制话题
ros2 bag play my_bag/ # 回放
ros2 bag info my_bag/ # 查看bag信息
八、Jazzy Jalisco新特性速览
| 新特性 | 说明 |
|---|---|
| Gazebo Harmonic | 推荐仿真器,通过ros_gz桥接ROS2 |
| ROSBag记录服务 | 支持录制和回放服务调用 |
| CLI自定义日志 | --log-file-name指定日志文件名 |
| 服务信息增强 | ros2 service info显示已连接客户端数 |
| 动作类型查询 | ros2 action type /action_name返回类型 |
九、总结
ROS2的核心设计思路是去中心化+工业级通信。理解DDS架构和五大概念(节点/话题/服务/动作/参数)的关系是掌握ROS2的关键。
| 你要做的事 | 用哪个概念 |
|---|---|
| 发送传感器数据 | 话题(Publisher) |
| 请求一次计算 | 服务(Client→Server) |
| 执行长时间任务(可取消+反馈) | 动作(ActionClient) |
| 运行时改配置 | 参数(Parameter) |
| 管理节点启停 | 生命周期节点 + Launch |
本文首发于linuxros.cn,转载请注明出处。