Files
ROS2_learn/doc/10-concepts.md
T
2026-08-03 18:09:35 +08:00

864 lines
25 KiB
Markdown

# 10 · ROS2 核心概念速览(完整概念地图)
> **目标**:30 分钟内把 ROS2 所有核心概念装进脑子里,后续文档都能"秒懂"。
---
## 目录
- [一图总览](#一图总览)
- [1. 计算图(Computational Graph)](#1-计算图computational-graph)
- [2. Node(节点)](#2-node节点)
- [3. Topic(话题)](#3-topic话题)
- [4. Service(服务)](#4-service服务)
- [5. Action(动作)](#5-action动作)
- [6. Parameter(参数)](#6-parameter参数)
- [7. TF2(坐标变换)](#7-tf2坐标变换)
- [8. URDF(机器人模型)](#8-urdf机器人模型)
- [9. sensor_msgs(常用消息类型)](#9-sensor_msgs常用消息类型)
- [10. Launch(启动文件)](#10-launch启动文件)
- [11. DDS / QoS / 时间(底层)](#11-dds--qos--时间底层)
- [12. 6 大概念怎么一起工作](#12-6-大概念怎么一起工作)
- [13. 概念速查表](#13-概念速查表)
---
## 一图总览
```
┌──────────────────────────────────────────────────────────────────┐
│ DDS 总线 (默认 fastdds) │
│ │
│ Topic /chatter Topic /image_raw Topic /tf │
│ Topic /joint_states Service /add_two_ints │
│ Action /fibonacci Parameter server │
└───────┬─────────────────┬──────────────────┬─────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌───────────┐
│ talker │ │ camera │ │ tf listener│
│ listener│ │processor │ │joint_pub │
│ (Node) │ │ (Node) │ │ (Node) │
└─────────┘ └──────────┘ └───────────┘
```
**6 大概念**:Node / Topic / Service / Action / Parameter / TF。
下面 12 节拆解。
---
## 1. 计算图(Computational Graph)
### 1.1 是什么
ROS2 程序由**节点**(Node)组成,节点之间通过**话题/服务/动作**连接,形成一张"计算图"。
图不是静态配置,是**运行时由 DDS 自动发现**。
### 1.2 看计算图
```bash
# 命令行看拓扑
ros2 node list
ros2 topic list
ros2 service list
ros2 action list
# 可视化(GUI)
ros2 run rqt_graph rqt_graph
```
### 1.3 三个关键术语
| 术语 | 含义 |
|---|---|
| **Node** | 一个独立运行的程序 |
| **Edge** | Node 之间的连接(Topic / Service / Action) |
| **Discovery** | DDS 自动找节点,无需中心注册 |
---
## 2. Node(节点)
### 2.1 是什么
ROS2 程序的**基本单元**。一个 Node = 一个进程 = 一项业务功能。
### 2.2 怎么写(Python)
```python
import rclpy
from rclpy.node import Node
class MyNode(Node):
def __init__(self):
super().__init__('my_node_name') # 节点名,在 ROS Domain 内必须唯一
# 在这里创建 publisher / subscription / timer / param
self.timer_ = self.create_timer(0.5, self.tick)
def tick(self):
self.get_logger().info('tick')
def main():
rclpy.init() # 全局初始化
node = MyNode()
rclpy.spin(node) # 进入事件循环,阻塞
rclpy.shutdown() # 退出
if __name__ == '__main__':
main()
```
### 2.3 怎么写(C++)
```cpp
#include "rclcpp/rclcpp.hpp"
class MyNode : public rclcpp::Node {
public:
MyNode() : rclcpp::Node("my_node_name") {
timer_ = this->create_wall_timer(
500ms, std::bind(&MyNode::tick, this));
}
private:
void tick() {
RCLCPP_INFO(this->get_logger(), "tick");
}
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char * argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MyNode>());
rclcpp::shutdown();
return 0;
}
```
### 2.4 关键 API
| API | 用途 |
|---|---|
| `super().__init__('name')` | 节点构造时设名字 |
| `create_publisher(...)` | 创建发布者 |
| `create_subscription(...)` | 创建订阅者 |
| `create_service(...)` | 创建服务端 |
| `create_action_server(...)` | 创建动作服务端 |
| `create_timer(period, cb)` | 创建定时器 |
| `declare_parameter(...)` | 声明参数 |
| `get_logger().info(...)` | 打日志 |
| `get_clock()` | 取时钟 |
| `rclpy.spin(node)` | 进入事件循环,处理所有回调 |
### 2.5 生命周期
```
rclpy.init() ─┐
├─ 实例化 Node ─ 创建 pub/sub/service ─ spin 等待回调
实例化 Node ─┘
rclpy.spin(node) ── 阻塞,处理 timer / subscription / service 回调
▼ (Ctrl+C 或 shutdown)
rclpy.shutdown() ── 清理
```
### 2.6 本仓库对照
- Python:[`src/py_pubsub/py_pubsub/publisher_member_function.py`](../src/py_pubsub/py_pubsub/publisher_member_function.py)
- C++:[`src/cpp_pubsub/src/publisher_member_function.cpp`](../src/cpp_pubsub/src/publisher_member_function.cpp)
---
## 3. Topic(话题)
### 3.1 是什么
**异步、多对多、单向**的发布订阅通道。
- 异步:`publish()` 不阻塞
- 多对多:1 个 publisher,任意多个 subscriber
- 单向:消息只从 pub 到 sub,反方向不通
### 3.2 通信模型
```
Publisher ──publish()──> Topic (chatter) ──callback(msg)──> Subscriber
────────────────────────────────────────────────────
异步,非阻塞 多对多,单向 事件循环触发
```
### 3.3 vs 其他通信方式
| | Topic | Service | Action |
|---|---|---|---|
| 同步 | 异步 | 同步 | 异步 |
| 一对多 | ✅ | ❌ | ❌ |
| 反馈 | ❌ | ❌ | ✅ |
| 取消 | N/A | ❌ | ✅ |
### 3.4 Python API
```python
# Publisher
pub = node.create_publisher(
std_msgs.msg.String, # 消息类型
'chatter', # topic 名
10 # QoS 深度
)
# 构造 + 发送
msg = std_msgs.msg.String()
msg.data = 'hello'
pub.publish(msg) # 异步,不等任何东西
# Subscriber
sub = node.create_subscription(
std_msgs.msg.String, # 类型
'chatter', # topic 名
callback, # 回调函数
10 # QoS 深度
)
def callback(msg):
node.get_logger().info(f'recv: {msg.data}')
```
### 3.5 C++ API
```cpp
// Publisher
auto pub = node->create_publisher<std_msgs::msg::String>("chatter", 10);
auto msg = std_msgs::msg::String();
msg.data = "hello";
pub->publish(msg);
// Subscriber
auto sub = node->create_subscription<std_msgs::msg::String>(
"chatter", 10,
[this](const std_msgs::msg::String::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "recv: %s", msg->data.c_str());
});
```
### 3.6 QoS(服务质量)速查
| 维度 | 取值 | 默认 | 影响 |
|---|---|---|---|
| Reliability | RELIABLE / BEST_EFFORT | RELIABLE | 必须 pub/sub 一致 |
| History | KEEP_LAST(N) / KEEP_ALL | KEEP_LAST(10) | 队列大小 |
| Durability | VOLATILE / TRANSIENT_LOCAL | VOLATILE | 晚订阅者是否收到旧数据 |
**兼容规则**:
- RELIABLE ↔ RELIABLE ✅
- BEST_EFFORT ↔ BEST_EFFORT ✅
- BEST_EFFORT → RELIABLE ✅(sub 容忍丢)
- RELIABLE → BEST_EFFORT ❌(sub 不发 ACK,pub 报错)
### 3.7 常用 CLI
```bash
ros2 topic list # 所有 topic
ros2 topic info <topic> -v # 类型 + pub/sub 列表
ros2 topic echo <topic> # 实时打印
ros2 topic hz <topic> # 频率 Hz
ros2 topic bw <topic> # 带宽 bytes/s
ros2 topic pub <topic> <type> "<msg>" --once # 发一条测试
ros2 bag record <topic> # 录包
ros2 bag play <bag> # 回放
```
### 3.8 本仓库对照
- 包:[`src/py_pubsub/`](../src/py_pubsub/), [`src/cpp_pubsub/`](../src/cpp_pubsub/)
- 跨语言互通验证:[`docker/bringup_e2e.log`](../docker/bringup_e2e.log)
**深度**: [`doc/20-topics.md`](20-topics.md)
---
## 4. Service(服务)
### 4.1 是什么
**同步、一对一、双向**的请求/响应。
- 一次性调用 + 等结果
- 几毫秒到几秒
### 4.2 通信模型
```
Client ──call(req)──> Server
◀──response────
同步(阻塞),一次一答
```
### 4.3 .srv 文件定义
```srv
# example_interfaces/srv/AddTwoInts.srv
int64 a # Request 字段
int64 b
---
int64 sum # Response 字段
```
- `---` 上 = Request
- `---` 下 = Response
### 4.4 Server 端
```python
from example_interfaces.srv import AddTwoInts
srv = node.create_service(
AddTwoInts, # 服务类型
'add_two_ints', # 服务名
callback # 回调签名:callback(req, resp) -> resp
)
def callback(request, response):
response.sum = request.a + request.b
return response # 必须 return response
```
### 4.5 Client 端(异步风格)
```python
client = node.create_client(AddTwoInts, 'add_two_ints')
while not client.wait_for_service(timeout_sec=1.0):
node.get_logger().info('waiting...')
req = AddTwoInts.Request()
req.a = 12; req.b = 30
future = client.call_async(req)
# 必须 spin 让 future 完成
rclpy.spin_until_future_complete(node, future, timeout_sec=5.0)
result = future.result()
print(result.sum) # 42
```
### 4.6 何时用
| 场景 | 用 Service |
|---|---|
| 拍照(几 ms) | ✅ |
| 关节角度查询 | ✅ |
| 计算查询 | ✅ |
| 周期性相机帧 | ❌ → Topic |
| 长任务(几秒到几分钟) | ❌ → Action |
### 4.7 常用 CLI
```bash
ros2 service list
ros2 service type <name> # 类型
ros2 service call <name> <type> "<req>"
# 例:
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 12, b: 30}"
```
**深度**: [`doc/30-services.md`](30-services.md)
---
## 5. Action(动作)
### 5.1 是什么
Service 的"长任务"版本:
- client 发 Goal
- server 周期性推 Feedback
- 最终返回 Result
- **client 可中途 cancel**
适合:抓取、导航、SLAM。
### 5.2 通信模型
```
Client Server
│ Goal │
├────────────────────>│
│ ▼ 执行中
│ Feedback │
│<────────────────────┤
│ Feedback │
│<────────────────────┤
│ Result │
│<────────────────────┤
│ cancel (可选) │
├────────────────────>│
```
### 5.3 .action 文件定义
```action
# example_interfaces/action/Fibonacci.action
int32 order
---
int32[] sequence # Result
---
int32[] sequence # Feedback
```
| 段 | 含义 |
|---|---|
| 第一段 | Goal(client 发) |
| `---` | 分隔 |
| 第二段 | Result(server 最终给一次) |
| `---` | 分隔 |
| 第三段 | Feedback(server 周期性推 0..N 次) |
### 5.4 Server 端
```python
import rclpy.action
action_server = rclpy.action.ActionServer(
node,
Fibonacci, # ActionType
'fibonacci', # action 名
execute_callback # 签名:cb(goal_handle) -> result
)
def execute_callback(goal_handle):
order = goal_handle.request.order
feedback = Fibonacci.Feedback()
result = Fibonacci.Result()
sequence = [0, 1]
for i in range(1, order):
if goal_handle.is_cancel_requested:
goal_handle.canceled()
return Fibonacci.Result()
sequence.append(sequence[i] + sequence[i-1])
feedback.sequence = sequence
goal_handle.publish_feedback(feedback)
goal_handle.succeed()
result.sequence = sequence
return result
```
### 5.5 Client 端
```python
client = ActionClient(node, Fibonacci, 'fibonacci')
client.wait_for_server()
goal = Fibonacci.Goal()
goal.order = 6
future = client.send_goal_async(
goal,
feedback_callback=lambda msg: print('fb:', msg.feedback.sequence)
)
future.add_done_callback(cb_goal_response)
```
### 5.6 状态机
```
PENDING → ACCEPTED → EXECUTING → SUCCEEDED
ABORTED
CANCELED
```
### 5.7 MultiThreadedExecutor(关键!)
Action server 的 execute + publish_feedback 都在主线程。**用 MultiThreadedExecutor**
避免 Feedback 卡死:
```python
from rclpy.executors import MultiThreadedExecutor
executor = MultiThreadedExecutor(num_threads=4)
executor.add_node(node)
executor.spin()
```
### 5.8 何时用 vs Service
| 持续 | 用 |
|---|---|
| < 几秒 | Service |
| 几秒 ~ 几小时 | Action |
**深度**: [`doc/40-actions.md`](40-actions.md)
---
## 6. Parameter(参数)
### 6.1 是什么
节点的**运行时配置项**。声明后可以运行时改,不重编译。
### 6.2 声明 / 读取 / 写
```python
class Talker(Node):
def __init__(self):
super().__init__('talker_py')
# 声明参数 + 默认值
self.declare_parameter('period_ms', 500)
self.declare_parameter('topic', 'chatter')
# 读取
period = self.get_parameter('period_ms').value
topic = self.get_parameter('topic').value
def change_param(self, new_period):
# 运行时改
param = rclpy.parameter.Parameter(
'period_ms', rclpy.Parameter.Type.INTEGER, new_period
)
self.set_parameters([param])
```
### 6.3 CLI 改参数
```bash
ros2 param list # 节点的所有参数
ros2 param get /talker_py period_ms
ros2 param set /talker_py period_ms 200
ros2 param describe /talker_py period_ms
ros2 param dump /talker_py > params.yaml # 导出
ros2 param load /talker_py params.yaml # 加载
```
### 6.4 launch 中覆盖
```python
Node(
package='py_pubsub',
executable='talker',
parameters=[{'period_ms': 200, 'topic': 'chatter'}] # 覆盖
)
```
CLI 启动:
```bash
ros2 run py_pubsub talker --ros-args -p period_ms:=200 -p topic:=hello
```
### 6.5 YAML 文件
```yaml
# config/params.yaml
talker_py:
ros__parameters:
period_ms: 200
topic: chatter
```
```python
Node(package='py_pubsub', executable='talker',
parameters=[get_package_share_directory('my_pkg') + '/config/params.yaml'])
```
---
## 7. TF2(坐标变换)
### 7.1 是什么
管理**机器人所有坐标系**之间相对位姿的工具。维护一棵 **TF tree**
### 7.2 典型 TF tree
```
world
└─ map (SLAM)
└─ odom (AMCL / 里程计)
└─ base_link (底盘)
├─ base_footprint
├─ laser_frame (激光雷达)
├─ camera_optical_frame (相机)
└─ arm_base (机械臂)
└─ shoulder (关节 1)
└─ upper_arm (关节 2)
└─ wrist (关节 3)
└─ gripper (夹爪)
```
### 7.3 C++ Listener API
```cpp
#include "tf2_ros/buffer.h"
#include "tf2_ros/transform_listener.h"
tf2_ros::Buffer buffer(node->get_clock());
tf2_ros::TransformListener listener(buffer, node);
// 查"gripper 在 base_link 下"
geometry_msgs::msg::TransformStamped tf = buffer.lookupTransform(
"base_link", // target frame
"gripper", // source frame
tf2::TimePointZero); // latest
RCLCPP_INFO(node->get_logger(),
"gripper in base_link: x=%.3f y=%.3f z=%.3f",
tf.transform.translation.x, ...);
```
### 7.4 几何变换(把点变换到其他系)
```cpp
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
geometry_msgs::msg::PointStamped p_in, p_out;
p_in.header.frame_id = "world";
p_in.point.x = 1.0; p_in.point.y = 2.0; p_in.point.z = 3.0;
p_out = buffer.transform(p_in, "robot");
// p_out 在 robot 系下
```
### 7.5 Python Listener
```python
from tf2_ros import Buffer, TransformListener
buffer = Buffer()
listener = TransformListener(buffer, node)
try:
tf = buffer.lookup_transform(
'base_link', 'gripper', rclpy.time.Time(),
timeout=rclpy.duration.Duration(seconds=1.0))
print(tf.transform.translation)
except Exception as e:
node.get_logger().warn(f'lookup failed: {e}')
```
### 7.6 静态 TF(不变的关系)
```bash
# 命令行:激光雷达固定在底盘
ros2 run tf2_ros static_transform_publisher \
--x 0.1 --y 0 --z 0.2 --roll 0 --pitch 0 --yaw 0 \
--frame-id base_link --child-frame-id laser_frame
```
```python
# launch 里
Node(package='tf2_ros', executable='static_transform_publisher',
arguments=['--x', '0.1', '--y', '0', '--z', '0.2',
'--frame-id', 'base_link', '--child-frame-id', 'laser_frame'])
```
### 7.7 动态 TF(URDF + JointState)
`robot_state_publisher` (ROS2 系统包):
- 输入:URDF + `/joint_states`
- 输出:动态 TF 到 `/tf`
```bash
sudo apt install ros-humble-robot-state-publisher
ros2 run robot_state_publisher robot_state_publisher \
--ros-args -p robot_description:="$(xacro arm.urdf)"
```
### 7.8 调试命令
```bash
ros2 run tf2_tools view_frames # 生成 frames.pdf
ros2 run tf2_ros tf2_echo base_link gripper # 实时打印
ros2 topic hz /tf # /tf 频率
ros2 topic info /tf_static -v # 静态 TF 列表
```
**深度**: [`doc/50-tf2.md`](50-tf2.md)
---
## 8. URDF(机器人模型)
### 8.1 是什么
XML 格式的机器人描述:link / joint / 视觉 / 碰撞 / 物理参数。
### 8.2 最小 URDF
```xml
<?xml version="1.0"?>
<robot name="my_arm">
<link name="base_link">
<visual><geometry><box size="0.1 0.1 0.1"/></geometry></visual>
<collision><geometry><box size="0.1 0.1 0.1"/></geometry></collision>
<inertial><mass value="1.0"/><inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/></inertial>
</link>
<joint name="joint1" type="revolute">
<parent link="base_link"/>
<child link="link1"/>
<origin xyz="0 0 0.05"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="1.0" velocity="1.0"/>
</joint>
<link name="link1">
<visual><geometry><box size="0.05 0.05 0.1"/></geometry></visual>
<collision><geometry><box size="0.05 0.05 0.1"/></geometry></collision>
<inertial><mass value="0.5"/><inertia ixx="0.005" ixy="0" ixz="0" iyy="0.005" iyz="0" izz="0.005"/></inertial>
</link>
</robot>
```
### 8.3 关节类型
| type | 含义 | DoF |
|---|---|---|
| `revolute` | 转动(有限位) | 1 |
| `continuous` | 转动(无限位) | 1 |
| `prismatic` | 滑动 | 1 |
| `fixed` | 固定 | 0 |
| `floating` | 6 DoF | 6 |
### 8.4 校验
```bash
sudo apt install liburdfdom-tools
check_urdf my_arm.urdf # 校验 URDF
urdf_to_graphiz my_arm.urdf # 生成 PDF/PNG 图
```
**深度**: [`doc/60-urdf.md`](60-urdf.md)
---
## 9. sensor_msgs(常用消息类型)
| 消息 | 关键字段 | 用途 |
|---|---|---|
| `std_msgs/String` | `string data` | 通用 |
| `std_msgs/Header` | `stamp`, `frame_id` | 时间戳 + 坐标系 |
| `sensor_msgs/Image` | `height/width/encoding/step/data` | 相机图像 |
| `sensor_msgs/CameraInfo` | `K/D/R/P` | 相机内参/外参 |
| `sensor_msgs/PointCloud2` | `height/width/data/is_bigendian` | 3D 点云 |
| `sensor_msgs/JointState` | `name[]/position[]/velocity[]/effort[]` | 关节状态 |
| `sensor_msgs/Imu` | `orientation/angular_velocity/linear_acceleration` | IMU |
| `geometry_msgs/Pose` | `Point position + Quaternion orientation` | 位姿 |
| `geometry_msgs/PoseStamped` | `Header + Pose` | 带时间戳位姿 |
| `geometry_msgs/Twist` | `Vector3 linear + Vector3 angular` | 速度指令 |
| `geometry_msgs/Transform` | `Vector3 translation + Quaternion rotation` | TF 变换 |
| `nav_msgs/Odometry` | `pose + twist + covariances` | 里程计 |
| `nav_msgs/Path` | `PoseStamped[]` | 路径 |
| `trajectory_msgs/JointTrajectory` | `JointTrajectoryPoint[]` | 关节轨迹(ros2_control 用) |
| `trajectory_msgs/JointTrajectoryPoint` | `positions[]/velocities[]/accelerations[]/effort[]` | 单点轨迹 |
| `vision_msgs/Detection2DArray` | `detections[]` | 目标检测结果 |
---
## 10. Launch(启动文件)
### 10.1 是什么
Python 脚本,描述"启动哪些节点 + 参数",取代 ROS1 XML。
### 10.2 最小 launch
```python
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_pkg',
executable='my_node',
name='my_node',
output='screen',
parameters=[{'param1': 'value1'}],
),
])
```
### 10.3 启动方式
```bash
ros2 launch <pkg> <launch_file.py>
ros2 launch <pkg> <launch_file.py> topic:=hello period_ms:=200
```
**深度**: [`doc/70-launch.md`](70-launch.md)
---
## 11. DDS / QoS / 时间(底层)
### 11.1 DDS 是什么
ROS2 默认用 **DDS**(Data Distribution Service)做底层通信。
本仓库默认 **FastDDS**(`rmw_fastrtps_cpp`)。
DDS 提供的核心能力:
- 自动节点发现(基于 UDP multicast)
- 多种 QoS(可靠 / 尽力而为)
- 实时性
### 11.2 RMW(ROS Middleware)
ROS2 用 RMW 抽象层,RMW 是 DDS 的 ROS 包装:
| RMW 实现 | 包 | 适用 |
|---|---|---|
| `rmw_fastrtps_cpp` | `ros-humble-rmw-fastrtps-cpp`(默认) | 通用 |
| `rmw_cyclonedds_cpp` | `ros-humble-rmw-cyclonedds-cpp` | 跨网段更稳 |
切换:
```bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
```
### 11.3 时间
| 概念 | 含义 | 用法 |
|---|---|---|
| `system time` | 墙钟时间(默认) | 仿真时需配 `use_sim_time: true` |
| `sim time` | 仿真时钟(`/clock` topic) | Gazebo / 录包回放 |
| `Header.stamp` | 消息时间戳 | TF 同步、消息时间关联 |
---
## 12. 6 大概念怎么一起工作
```
┌────────────────────────────────────────────────┐
│ application │
│ (决策 / 控制 / 感知 / 学习) │
└─────────┬──────────────────────────────────────┘
│ 用 TF / Topic / Service / Action / Parameter
┌─────────▼──────────────────────────────────────┐
│ ROS2 中间件 (rclcpp/rclpy) │
│ ┌────────────────────────────────────────┐ │
│ │ Topic Pub/Sub (异步多对多单向) │ │
│ │ Service Req/Resp (同步一对一双向) │ │
│ │ Action Goal/Feedback/Result (长任务) │ │
│ │ Param 配置 │ │
│ │ TF2 坐标变换树 │ │
│ └────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────┐ │
│ │ DDS (默认 fastdds) │ │
│ └────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
│ 走 UDP multicast / unicast
┌─────────▼──────────────────────────────────────┐
│ 网络 │
└─────────────────────────────────────────────────┘
```
---
## 13. 概念速查表
| 概念 | 一句话 | API | 深度文档 |
|---|---|---|---|
| Node | 一个进程 = 一项业务 | `rclpy.spin(node)` | 本篇 §2 |
| Topic | 异步多对多单向 | `create_publisher / create_subscription` | [`20-topics`](20-topics.md) |
| Service | 同步 1对1 双向 | `create_service / create_client` | [`30-services`](30-services.md) |
| Action | 长任务 + 反馈 + 可取消 | `ActionServer / ActionClient` | [`40-actions`](40-actions.md) |
| Parameter | 运行时配置 | `declare_parameter / set_parameter` | 本篇 §6 |
| TF2 | 坐标系树 | `Buffer.lookup_transform` | [`50-tf2`](50-tf2.md) |
| URDF | 机器人 XML 描述 | `check_urdf` | [`60-urdf`](60-urdf.md) |
| Launch | 启动脚本 | `ros2 launch <pkg> <file>` | [`70-launch`](70-launch.md) |
| DDS | 通信中间件 | `RMW_IMPLEMENTATION=` | 本篇 §11 |
---
## 接下来读
按主题深读:
| 你想深挖什么 | 看 |
|---|---|
| Topic 实现细节、QoS、跨语言互通 | [`20-topics.md`](20-topics.md) |
| Service 实现、req/resp 时序 | [`30-services.md`](30-services.md) |
| Action 三件套、cancel、MultiThreadedExecutor | [`40-actions.md`](40-actions.md) |
| TF tree / lookup / static_transform | [`50-tf2.md`](50-tf2.md) |
| URDF / xacro / robot_state_publisher | [`60-urdf.md`](60-urdf.md) |
| launch 嵌套、参数覆盖、事件 | [`70-launch.md`](70-launch.md) |
| 三机部署(PC + RDK X5 + RK3506) | [`100-embedded-deployment.md`](100-embedded-deployment.md) |
| 进入具身智能 / VLA / 机器人 | [`99-embodied-ai.md`](99-embodied-ai.md) |