ROS2从入门到实战:去中心化机器人操作系统详解

复制代码
本文是独立成篇的 ROS2 笔记,涵盖从命令行到仿真的全链路。建议配合 Ubuntu 22.04 + Humble 食用。

1. 什么是 ROS2?为什么要用它?

ROS 全称 Robot Operating System,它不是传统意义的操作系统 (像 Linux/Windows),而是一套运行在 Linux 上的 机器人软件框架

  • 硬件抽象: 屏蔽雷达、摄像头、IMU、电机驱动的底层差异

  • 中间件: 提供标准化的节点间通信(类似你之前学的 MQTT,但更强大)

  • 工具链: 调试、可视化(RViz2)、仿真(Gazebo)、录包(bag)

  • 算法库: 导航 Nav2、建图 SLAM、MoveIt2 机械臂规划,开箱即用

不用 ROS2 的痛点:

假设机器人有 3个模块:激光雷达、摄像头、底盘控制,由3个团队开发。

  • 没 ROS2:雷达团队写个 socket 发数据,摄像头团队写个串口,底盘团队写个 CAN,接口对不上,联调地狱。

  • 有 ROS2:大家都说 Topic 普通话,雷达发 /scan,导航订阅 /scan,底盘订阅 /cmd_vel,即插即用。

2. ROS1 vs ROS2:一次颠覆性的重构

特性 ROS1 (Noetic) ROS2 (Humble/Iron)
核心架构 中心化,必须有一个 roscore / Master 节点,Master挂了全挂 去中心化,无Master,基于 DDS 自动发现,无单点故障
通信中间件 自定义 TCPROS/UDPROS DDS 标准(工业级,航空/国防在用)
实时性 弱,TCP延迟不可控 ,DDS 可配置 QoS 实时策略
跨平台 主要 Linux Linux/Windows/macOS/RTOS
构建系统 catkin ament + colcon
Python Python2 Python3
节点生命周期 无,节点启动即运行 ,可配置 unconfigured/inactive/active/shutdown,适合产品
安全性 无加密 SROS2 支持认证加密

一句话总结:ROS1 是实验室玩具,ROS2 是能上产线的商业系统。

3. ROS2 架构:五层分层模型

从底到顶:

  1. DDS层 (Data Distribution Service): 厂商实现,Fast DDS(默认)、CycloneDDS、Connext。负责真正的网络传输,UDP多播/单播、共享内存。

  2. RMW层 (ROS Middleware Interface): 抽象层,把不同厂商 DDS API 统一成一套标准接口 rmw_*。好处:今天用 Fast DDS,明天切 CycloneDDS,代码一行不改。

  3. RCL层 (ROS Client Library): C语言实现的 rcl,封装节点、话题、服务等核心概念。

  4. 客户端库层: rclcpp (C++)、rclpy (Python)、rcljava (Java) 等,面向开发者。

  5. 应用层: 你的节点、Nav2、MoveIt2。

所以 ROS2 删除 Master 后怎么发现彼此?

靠 DDS 的 SPDP + SEDP 自动发现:

  • 新节点上线,DDS 向 239.255.0.1 多播发广播:我来了,我有 /scan 发布器。

  • 其他节点收到,回复我是谁我有什么订阅。

  • 两边 QoS 兼容,则建立 P2P 直连,后续不经过任何中心。

4. 五大核心通信机制(嵌入式类比秒懂)

对于 STM32 开发者,用 FreeRTOS 类比:

ROS2组件 FreeRTOS类比 核心功能 通信模式 典型场景
节点 Node 任务 Task 最小功能单元 - 激光驱动、电机控制、路径规划各一个节点
话题 Topic 消息队列 + 串口广播 连续数据流 异步、多对多 雷达发 /scan,相机发 /image_raw,底盘发 /odom
消息 Message struct 结构体 数据格式定义 - geometry_msgs/Twist 速度, sensor_msgs/LaserScan 雷达
服务 Service 函数调用 + 问答 一次性远程调用 同步、一对一 拍照、查询电量、重置里程计
动作 Action 状态机 + 带反馈任务 长时间可取消任务 异步 + 反馈 导航到目标点 NavigateToPose,可中途取消,看进度
参数 Parameter Flash配置 + 全局变量 节点动态配置 - PID增益、最大速度,不重启即可修改

4.1 话题 Topic(最常用,80%场景)

复制代码
publisher_node -- /scan (sensor_msgs/LaserScan) --> subscriber_node(s)

特点:解耦,发布者不知道谁在听,订阅者不知道谁发的。

4.2 服务 Service

客户端发 Request,等待服务端 Response。同步阻塞,但 ROS2 中是异步回调,不会卡死。

复制代码
/client 请求 "计算路径" -> /planner 服务端 -> 返回路径

4.3 动作 Action(服务+话题的合体)

处理3秒以上的长任务:导航、机械臂抓取。

包含3部分:Goal目标 + Feedback周期反馈 + Result最终结果,且可取消。底层由3个话题+2个服务实现,但对你透明。

4.4 参数 + QoS

  • 参数:ros2 param set /turtlesim background_r 128 动态改背景颜色,无需重启。

  • QoS:可靠性 RELIABLE / BEST_EFFORT,历史 KEEP_LAST,持久性 TRANSIENT_LOCAL 等,可针对雷达/图像/控制指令精细配置。

4.5 ROS2命令行操作

ROS2 90%的调试都靠命令行,掌握它就掌握了机器人的控制台。

命令族 常用命令 作用
ros2 node list, info /turtlesim, kill 查看/杀死节点
ros2 topic list -t, echo /scan, hz /scan, bw, pub /cmd_vel ... 调试连续数据流,最常用
ros2 service list -t, call /spawn ..., type, find 调用一次性服务
ros2 action list, info /navigate_to_pose, send_goal 调试导航等长任务
ros2 param list, get /node param, set, dump/load 动态改参,运行时调PID
ros2 interface show geometry_msgs/msg/Twist, list, proto 查看消息结构
ros2 bag record -a, play, info 录包回放,复现偶发Bug
ros2 run run turtlesim turtlesim_node 运行单个节点
ros2 launch launch nav2_bringup bringup_launch.py 一键启动多节点
colcon colcon build --symlink-install, --packages-select 编译工作空间

实战口诀:

复制代码
# 不知道有什么?
ros2 topic list -t        # 看话题
ros2 node list            # 看节点
ros2 service list         # 看服务
​
# 不知道数据格式?
ros2 interface show sensor_msgs/msg/LaserScan
​
# 看数据流是否正常?
ros2 topic echo /scan --no-arr       # 不打超长数组
ros2 topic hz /scan                  # 看雷达频率是不是10Hz

5. ROS2开发环境配置

推荐组合:Ubuntu 22.04 + ROS2 Humble Hawksbill,LTS到2027年,最稳。

5.1 一键安装

复制代码
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
​
sudo apt install software-properties-common -y
sudo add-apt-repository universe
sudo apt install curl gnupg lsb-release -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
​
sudo apt update
sudo apt install ros-humble-desktop -y          # 桌面完整版,含RViz2+Gazebo+示例
sudo apt install python3-colcon-common-extensions python3-rosdep ros-dev-tools -y
​
# 环境变量
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
​
# 初始化 rosdep
sudo rosdep init || true
rosdep update

5.2 多机隔离与工具

复制代码
# 多机器人同WiFi防串台
export ROS_DOMAIN_ID=10  # 0~101,同一ID才能互通
​
# VSCode插件:ROS, URDF, 记得装
​
# Docker版(Windows/Mac用户)
docker pull osrf/ros:humble-desktop

验证:

复制代码
ros2 run demo_nodes_cpp talker &
ros2 run demo_nodes_py listener
# 看到 hello world 互通即成功

6. 工作空间与功能包:开发过程的大本营

工作空间 Workspace 是项目的物理边界。官方推荐 ~/ros2_ws

四个子目录:

  • src:放所有功能包源码,git clone 都在里

  • build:colcon 编译中间文件,不用管

  • install:编译产物,setup.bash 在这

  • log:编译日志

功能包 Package 是最小复用单元。包含 package.xml(依赖声明)+ CMakeLists.txt (C++) 或 setup.py (Python) + 代码。

复制代码
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
​
# 创建C++包
ros2 pkg create my_cpp_pkg --build-type ament_cmake --dependencies rclcpp std_msgs
​
# 创建Python包
ros2 pkg create my_py_pkg --build-type ament_python --dependencies rclpy std_msgs
​
# 创建带消息定义的包
ros2 pkg create my_interfaces --build-type ament_cmake --dependencies rosidl_default_generators
​
cd ~/ros2_ws
rosdep install -i --from-path src --rosdistro humble -y
colcon build --symlink-install
source install/setup.bash

--symlink-install 对Python极其重要,改.py不用重编,直接运行。

7. 节点:机器人的工作细胞

节点 Node 是 ROS2 最小执行单元,一个独立进程,只做一件事。

复制代码
import rclpy
from rclpy.node import Node
​
class MyNode(Node):
    def __init__(self):
        super().__init__('my_first_node')  # 节点名唯一
        self.get_logger().info('Hello, 我是工作细胞!')
        self.timer = self.create_timer(1.0, self.tick)
​
    def tick(self):
        self.get_logger().info('心跳...')
​
def main():
    rclpy.init()
    rclpy.spin(MyNode())  # 阻塞,处理回调
    rclpy.shutdown()

节点生命周期(ROS2 独有,产品级必用): unconfigured -> inactive -> active -> finalized,可通过生命周期管理器 lifecycle_manager 统一配置,机器人启动时先加载参数,再激活。

8. 话题:节点间传递数据的桥梁

话题 Topic 是异步、多对多广播,最常用。

复制代码
/demonstration
Publisher ---(/cmd_vel, geometry_msgs/Twist)---> Subscriber(s)

Python 发布者:

复制代码
self.pub = self.create_publisher(Twist, '/cmd_vel', 10)
msg = Twist()
msg.linear.x = 0.2
self.pub.publish(msg)

订阅者:

复制代码
self.sub = self.create_subscription(LaserScan, '/scan', self.scan_callback, 10)
def scan_callback(self, msg):
    print(f'最前面障碍物距离: {msg.ranges[0]}')

命令行调试:

复制代码
ros2 topic list -t
ros2 topic echo /turtle1/pose
ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5}, angular: {z: 0.5}}" -1

QoS 可选 RELIABLE/BEST_EFFORT,雷达用 BEST_EFFORT 少延迟,控制指令用 RELIABLE 保到达。

9. 服务:节点间的你问我答

服务 Service 是同步 一对一 请求响应,类似函数调用。

复制代码
Client ---(Request: 拍照请求)---> Server
Client <---(Response: 照片结果)--- Server

turtlesim 典型服务:

复制代码
ros2 service list
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: 'turtle2'}"

代码:

复制代码
from turtlesim.srv import Spawn
self.client = self.create_client(Spawn, '/spawn')
req = Spawn.Request(x=2.0, y=2.0, name='t2')
future = self.client.call_async(req)
rclpy.spin_until_future_complete(self, future)

适用: 重置里程计、保存地图、触发拍照等只需执行一次的任务。

10. 通信接口:数据传递的标准结构

所有话题/服务/动作的数据类型都有标准定义,放在 msg/srv/action 文件中。

  • Message (.msg): 话题载体

    复制代码
    # Twist.msg
    Vector3 linear
    Vector3 angular
  • Service (.srv): 请求---响应

    复制代码
    # AddTwoInts.srv
    int64 a
    int64 b
    ---
    int64 sum
  • Action (.action): 目标---结果---反馈

    复制代码
    # Fibonacci.action
    int32 order  # Goal
    ---
    int32[] sequence  # Result
    ---
    int32[] partial_sequence  # Feedback

自定义接口:

复制代码
# my_interfaces/msg/Student.msg
string name
int32 age

# CMakeLists.txt
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Student.msg"
  "srv/AddTwoInts.srv"
)

ros2 interface show 就能看到。

11. 动作:完整行为的流程管理

Action = Service(可取消) + Topic(周期反馈)。处理长时间任务:导航、机械臂执行。

复制代码
Client --Goal--> Server (开始去(2,2))
       <--Feedback-- (已走30%)
       <--Feedback-- (已走80%)
       --Cancel-->   (用户中途取消)
       <--Result--   (成功/失败/取消)

命令行:

复制代码
ros2 action list
ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose "{pose: {pose: {position: {x: 2, y: 2}}}}"

Nav2 导航就是一个 Action Server,RViz2 点目标点就是 Client。

12. 参数:机器人系统的全局字典

参数 Parameter 是节点的 可动态配置变量,无需重启。

复制代码
self.declare_parameter('kp', 1.0)
kp = self.get_parameter('kp').value
# 支持回调,参数一改,控制立刻生效
self.add_on_set_parameters_callback(self.param_callback)

命令行:

复制代码
ros2 param list
ros2 param get /turtlesim background_r
ros2 param set /turtlesim background_r 200
ros2 param dump /turtlesim > params.yaml
ros2 param load /turtlesim params.yaml

应用: 现场调小车最大速度、PID增益、相机曝光,直接 param set,不用重新编译烧录。

13. 分布式通信:多计算平台的任务分配

ROS2 原生支持分布式:

  • 机器人端:Jetson Orin 跑激光+相机驱动

  • PC端:高性能主机跑建图、Nav2导航

  • 只要同一局域网,同一 ROS_DOMAIN_ID,同一WiFi,节点自动发现,话题互通。

复制代码
# 机器人端(192.168.1.10)
export ROS_DOMAIN_ID=42
ros2 run rplidar_ros rplidar_composition

# PC端(192.168.1.20)
export ROS_DOMAIN_ID=42
ros2 topic echo /scan  # 就能收到机器人雷达
rviz2                  # 就能可视化

比 ROS1 需要 ROS_MASTER_URI 配置简单太多。

进阶:DDS 支持跨广域网、SROS2 加密,适合车队。

14. DDS:机器人的神经网络

DDS 是 ROS2 的底座,工业级标准。

  • Domain: 逻辑隔离域,ROS_DOMAIN_ID 就是 DDS Domain ID。

  • Participant: 每个进程一个 Participant。

  • Topic + DataWriter/DataReader: 底层真正收发。

  • QoS策略:

    • Reliability: RELIABLE/BEST_EFFORT

    • Durability: VOLATILE/TRANSIENT_LOCAL(新订阅者能否收到历史)

    • History: KEEP_LAST depth

RMW: ROS中间件接口层,抽象不同厂商 DDS。切换实现:

复制代码
# 默认 Fast DDS
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# 换 CycloneDDS,更轻量
sudo apt install ros-humble-rmw-cyclonedds-cpp
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

理解 DDS,调透 QoS,是解决 图像卡顿、控制丢包 的关键。

15. Launch:多节点启动与配置脚本

机器人启动要启动 10+ 节点:雷达、IMU、底盘、TF、RViz...一个个 ros2 run 会累死,Launch 一键搞定。

ROS2 Launch 是 Python 脚本,比 ROS1 XML 强大百倍,支持 if 判断、变量。

复制代码
# my_robot/launch/robot.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(package='rplidar_ros', executable='rplidar_composition', 
             parameters=[{'serial_port': '/dev/ttyUSB0', 'frame_id': 'laser'}]),
        Node(package='my_robot', executable='base_driver', output='screen'),
        Node(package='tf2_ros', executable='static_transform_publisher',
             arguments=['0','0','0.2','0','0','0','base_link','laser']),
        Node(package='rviz2', executable='rviz2', arguments=['-d', 'my.rviz'])
    ])

运行:ros2 launch my_robot robot.launch.py 带参:ros2 launch my_robot robot.launch.py use_sim_time:=true

16. TF:机器人坐标系管理器

机器人有无数坐标系:map 地图、odom 里程计、base_link 底盘、laser 雷达、camera_link。TF就是管理它们关系的 时变树

  • TF 是话题 /tf/tf_static

  • 每个变换都是 父坐标 -> 子坐标 + 时间戳

  • tf2 可查询任意时刻任意两坐标系的关系。

复制代码
ros2 run tf2_ros static_transform_publisher 0 0 0.2 0 0 0 base_link laser
ros2 run tf2_tools view_frames  # 生成PDF的TF树
rviz2 -> Add -> TF 看坐标轴

代码监听:

复制代码
from tf2_ros import Buffer, TransformListener
self.tf_buffer = Buffer()
self.tf_listener = TransformListener(self.tf_buffer, self)
trans = self.tf_buffer.lookup_transform('map', 'base_link', rclpy.time.Time())

没有 TF,导航、建图全崩。 必须保证TF树连通无环。

17. URDF:ROS机器人建模方法

URDF (Unified Robot Description Format) 用 XML 描述机器人 连杆 Link + 关节 Joint

复制代码
<robot name="my_car">
  <link name="base_link">
    <visual><geometry><cylinder length="0.1" radius="0.2"/></geometry></visual>
  </link>
  <link name="left_wheel"/>
  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/><child link="left_wheel"/>
    <origin xyz="0 0.2 0"/><axis xyz="0 1 0"/>
  </joint>
</robot>
  • link:外观 visual、碰撞 collision、惯性 inertial

  • jointfixed 固定、continuous 连续旋转轮子、revolute 有限转角舵机、prismatic 滑轨

  • Xacro:URDF 宏,支持变量、计算,复杂机器人必用。

复制代码
sudo apt install ros-humble-joint-state-publisher-gui
ros2 launch urdf_tutorial display.launch.py model:=my_car.urdf
# 在RViz里拖动滑杆,看关节运动

URDF + TF = 机器人完整数字孪生。

18. Gazebo:三维物理仿真平台

Gazebo 是独立的物理引擎,支持重力、摩擦、碰撞、光照、传感器仿真(雷达噪声、相机畸变)。

  • Gazebo 负责 让机器人动起来,有物理

  • Rviz 负责 把数据画出来,无物理

经典流程:

复制代码
# 安装
sudo apt install ros-humble-gazebo-ros-pkgs ros-humble-gazebo-ros2-control

# 启动仿真
ros2 launch my_robot gazebo.launch.py

# 话题桥接:Gazebo的 /clock, /scan 会自动转 ROS2 话题

在URDF里加 <gazebo> 标签和插件,如 libgazebo_ros_diff_drive.so 差速驱动,Gazebo就开始仿真轮子转。

价值: 无需真机,在仿真中测试 Nav2 算法,撞烂了也不心疼。

19. Rviz:三维可视化显示平台

Rviz2 不模拟,只 订阅话题并可视化

常用 Display:

  • RobotModel:显示URDF模型

  • LaserScan:雷达点云

  • PointCloud2:3D点云

  • Map:占据栅格地图

  • Path:导航路径

  • TF:坐标系

  • Image:相机图像

复制代码
rviz2
# Add -> By topic -> 勾选 /scan
# 配置文件保存 .rviz,下次一键加载

配合 Nav2,Rviz里可点 2D Pose Estimate 初始位姿,2D Goal Pose 导航目标。

20. RQT:模块化可视化工具

RQT 是基于 Qt 的插件容器,集成几十个小工具:

复制代码
rqt                    # 打开插件选择器
rqt_graph              # 节点图,最常用,看话题连接(上一章用过)
rqt_plot               # 画曲线,/odom速度波形
rqt_console            # 日志过滤
rqt_reconfigure        # 动态调参图形化前端
rqt_bag                # 播放 bag 包

安装:sudo apt install ~nros-humble-rqt*

调试三件套:rqt_graph + ros2 topic echo + rviz2

21. ROS2应用与进阶攻略

到此,你已学完 ROS2 核心。下一步:

应用层

  • 导航 Nav2: sudo apt install ros-humble-navigation2,SLAM建图 slam_toolbox,定位 amcl,一键导航。

  • 机械臂 MoveIt2: 抓取规划。

  • ros2_control: 统一硬件接口,你的 STM32 底盘写一个 hardware_interface,就能被 Nav2 调度。

  • micro-ROS: 在 STM32F4/H7 上直接跑 ROS2 节点,不再经串口转发,订阅 /cmd_vel 成为真·ROS2节点。

进阶路线图

  1. 动手造小车: 差速底盘 + RPLIDAR A1 + IMU,跑通 URDF -> Gazebo -> Nav2 全流程。

  2. 视觉: v4l2_camera + OpenCV + YOLO,话题 /image_raw → 目标检测。

  3. 多机协同: 两台机器人同 ROS_DOMAIN_IDNav2 支持多机编队。

  4. 云边端: ROS2 + MQTT桥,机器人数据上阿里云,参考你之前 MQTT 篇。

最终建议:

  • 先把 turtlesim + 话题服务 玩熟

  • 再用 URDF + Rviz 搭自己模型

  • 再进 Gazebo 仿真 + Nav2 导航

  • 最后 接真车


总结

本篇严格目录,独立介绍了 ROS2 的命令行、环境、工程、五大通信、DDS、Launch、TF、URDF、Gazebo、Rviz、RQT。

工具包:Humble官方文档 + 鱼香ROS《ROS2机器人开发从入门到实践》 + 古月居教程

相关推荐
脚踏实地皮皮晨20 小时前
003006001_WrapPanel控件
开发语言·c#·.net·wpf·visual studio
脚踏实地皮皮晨21 小时前
003005002_WPF StackPanel 基类官方类定义逐行深度解析
开发语言·windows·算法·c#·wpf·visual studio
脚踏实地皮皮晨1 天前
003004002_UniformGrid控件的使用方法
开发语言·c#·.net·wpf·visual studio
酸梅果茶2 天前
ROS2 foxy环境下源码安装Navigation2
ros2·navigation·agx
脚踏实地皮皮晨2 天前
003003002_WPF Grid 基类官方类定义逐行深度解析
开发语言·windows·算法·c#·wpf·visual studio
脚踏实地皮皮晨3 天前
003002004_WPF Panel 基类 官方类定义
开发语言·windows·算法·c#·wpf·visual studio
湿滑路面4 天前
Rouyan:使用WPF/C#构建的基于LLM的快捷翻译小工具
开发语言·c#·wpf
软萌萌的14 天前
C#中的多级缓存架构设计与实现深度解析
缓存·c#·wpf
dalong104 天前
WPF:3D正八面体自动旋转
3d·wpf