ROS2系列教程:Humble环境搭建与Hello World

🕒 阅读时间:15 分钟📝 字数:4020👀 阅读量:Loading...

本文是 ROS2 系列教程的第 1 篇

本文是 ROS2 系列教程的第 1 篇:Humble 环境搭建与 Hello World。本系列参照「动手学 ROS2」Humble LTS 的知识体系,采用 C++(rclcpp)与 Python(rclpy)双语言并讲的方式,从零开始带你掌握 ROS2 的核心概念与实战技巧。每一篇都会给出可运行的完整示例,建议你在自己的机器上亲自动手实践。

一、ROS2 是什么

ROS(Robot Operating System,机器人操作系统)并不是一个真正的操作系统,而是一套面向机器人与自动化系统的分布式中间件框架。它建立在 Linux 等宿主操作系统之上,为机器人软件提供统一的通信、调度、工具链与生态。

ROS2 是 ROS1 的全新重写版本,解决了 ROS1 在实时性、多机通信、安全性、跨平台以及长期支持方面的诸多痛点。本节先建立整体认知,不必着急记细节,后续章节会逐个展开。

1.1 ROS1 与 ROS2 的核心区别

ROS1 面向学术与原型验证,虽成熟但存在先天限制;ROS2 面向工业级与生产部署,做了架构性升级。理解它们的差别,有助于我们理解 ROS2 设计中那些看似「多此一举」的概念。

维度 ROS1 ROS2
通信中间件 自研 TCPROS / UDPROS DDS(数据分发服务)
实时性 较弱,无 QoS 保障 强,支持 QoS 服务质量策略
多机/分布式 依赖一台 ROS Master 无需中心节点,DDS 自动发现
跨平台 主要 Linux Linux/Windows/macOS
安全性 无加密与身份认证 支持 SROS2 加密与认证
Python 消息分发 需要 rospy 全局状态 纯 Python + rclpy
长期支持 无 LTS 概念 有 LTS 版(如 Humble)

最大的架构差异在于去中心化。ROS1 必须有一个 roscore(ROS Master)来维护节点注册与话题匹配,Master 一旦挂掉整个系统瘫痪;ROS2 基于 DDS 的 P2P 发现机制,节点之间直接协商通信,无需单点故障中心。这也是 ROS2 适合多机、长时间部署机器人的根本原因。

1.2 DDS 与 QoS

DDS(Data Distribution Service)是一个由 OMG 组织维护的发布/订阅式实时通信标准。DDS 本身蕴含了节点发现、可靠传输、权限控制、QoS 策略等能力,ROS2 选择 DDS 作为通信底座,使自己能直接复用这些工业级能力。

QoS(Quality of Service,服务质量)是 ROS2 通信的核心概念,它决定消息传输的可靠性与实时性。ROS2 常用的 QoS 策略包括:

  • Reliability(可靠性):RELIABLE 尽力可靠送达(可能重传),BEST_EFFORT 尽力而为(不重传,适合高带宽传感器)。
  • Durability(持久性):TRANSIENT_LOCAL 让晚加入的订阅者也能收到最近的「最后一条」消息(常用于参数、静态 TF),VOLATILE 只收发布之后的消息。
  • History(历史):KEEP_LAST(N) 只保留最近 N 条,KEEP_ALL 保留全部。
  • Deadline / Lifespan / Liveliness:用于超时、有效期与活性检测。

同一话题上的发布者与订阅者 QoS 必须兼容才能通信。例如发布者用 RELIABLE,订阅者用 BEST_EFFORT 可以兼容(可靠侧向下兼容),但反过来则不行。第 9 篇会专门深入 QoS,这里先记住:QoS 是 ROS2 中「看似啰嗦、实则关键」的设计。

1.3 版本与 LTS

ROS2 每年发布一个版本(奇数为 LTS,偶数为半年版)。当前主流长期支持版是 Humble Hawksbill(Humble,H 系列),支持到约 2027 年,也是 fishros「动手学 ROS2」教程采用的版本。其余常见版本如 Foxy、Galactic、Iron、Jazzy、Kilted 等。我们统一使用 Ubuntu 22.04 + Humble 这套最经典的组合,社区资料最丰富、踩坑最少。

二、环境搭建

搭建 ROS2 Humble 环境的推荐方式是「在 Ubuntu 22.04 上安装」。如果你没有 Ubuntu 物理机,可考虑以下方案(按简单到复杂排列):WSL2、虚拟机(VirtualBox / VMware)、Docker。本教程以 Windows 上的 WSL2 + Ubuntu 22.04 为例,因为它既能利用 Windows 硬件,又让开发体验接近原生 Linux。

2.1 WSL2 安装步骤

在 Windows 上打开「管理员 PowerShell」,依次执行:

Terminal window
# 启用 WSL2 并安装 Ubuntu 22.04
wsl --install -d Ubuntu-22.04

重启计算机后,首次启动 Ubuntu-22.04 会让你设置 Linux 用户名与密码。安装完成后可更新系统软件包:

Terminal window
sudo apt update && sudo apt upgrade -y

如果你的 Windows 版本较老,wsl --install 可能不支持,需要手动启用 WSL 功能与虚拟机平台(控制面板 → 启用或关闭 Windows 功能 → 勾选「适用于 Linux 的 Windows 子系统」与「虚拟机平台」)。

2.2 设置 locale 与软件源

ROS2 对 locale 有要求,必须先配置为 UTF-8 编码,否则中文与特殊字符会出问题:

Terminal window
sudo apt install -y locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

然后设置 UTF-8 软源(如需)并安装基础依赖:

Terminal window
sudo apt install -y software-properties-common curl gnupg2 lsb-release

2.3 添加 ROS2 apt 源

以 Humble 为例,添加官方软件源:

Terminal window
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 $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

国内网络较慢时,可以改用清华镜像源加速:

Terminal window
sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] https://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros2.list'

更新索引后即可安装 ROS2 核心包。选择「ros-base」即可满足大部分教程需求,如需更多工具可安装完整版 desktop:

Terminal window
sudo apt update
sudo apt install -y ros-humble-desktop

ros-humble-desktop 包含核心库、Rviz、Gazebo、常用工具等,体积较大但开箱即用。仅学习入门可先装 ros-humble-ros-base。

2.4 安装 colcon 与入门工具

构建工具 colcon 是 ROS2 的标配:

Terminal window
sudo apt install -y python3-colcon-common-extensions

常用工具链(视需要安装):

Terminal window
sudo apt install -y ros-humble-ros2bag ros-humble-rviz2 python3-pip

2.5 配置环境变量

每次打开新终端都要 source 环境脚本很麻烦,建议写进 .bashrc:

Terminal window
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc

如果你在 WSL2 中使用且需要图形界面(Rviz、Gazebo),可能需要启用 WSLg(Windows 11 默认支持)或配置 X11 转发。WSL2 通常已内置 WSLg,直接在终端运行 rviz2 即可看到窗口。

2.6 验证安装

打开新终端,依次输入:

Terminal window
# 方法一:打印版本
printenv ROS_DISTRO
# 方法二:查看环境变量路径
echo $ROS_DISTRO
# 方法三:查看已安装的可用包
ls /opt/ros/humble/

如果 printenv ROS_DISTRO 输出 humble,说明环境配置成功。你也可以先跑一个最简单的节点测试(见下节)。

三、第一个 ROS2 程序:Hello World

ROS2 程序的最小单元是节点(Node)。一个节点就是一个独立运行的进程,它通过话题、服务、动作等方式与其他节点通信。本节我们写一个最基础的节点,它只负责在启动时打印一句话,以此理解节点的最小骨架。

3.1 Python 版 Hello World(rclpy)

Python 版最直观,代码量最少。创建一个工作空间并新建一个包(包的创建细节见第 3、4 篇,这里先手动搭建最小结构):

# talker.py —— 一个最简的 Python 节点
import rclpy
from rclpy.node import Node
class HelloNode(Node):
def __init__(self):
super().__init__('hello_node')
self.get_logger().info('Hello, ROS2! 我是 Python 节点')
def main(args=None):
rclpy.init(args=args)
node = HelloNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

运行这个脚本前,需要先安装依赖。在已 source 环境的终端中:

Terminal window
python3 -c "import rclpy" # 若报错需安装 python3 依赖
source /opt/ros/humble/setup.bash
python3 talker.py

你将看到日志输出 Hello, ROS2! 我是 Python 节点,同时进程会一直保持运行(因为 rclpy.spin() 让节点不断处理回调)。按 Ctrl+C 即可优雅退出。

3.2 C++ 版 Hello World(rclcpp)

C++ 版结构更规范,但需要 CMakeLists.txt 与 package.xml。这里先给出核心源码,完整包结构在第 3、4 篇讲解:

// hello_node.cpp —— 一个最简的 C++ 节点
#include "rclcpp/rclcpp.hpp"
class HelloNode : public rclcpp::Node
{
public:
HelloNode() : Node("hello_node")
{
RCLCPP_INFO(this->get_logger(), "Hello, ROS2! 我是 C++ 节点");
}
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<HelloNode>();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

编译与运行(假设已用 colcon 构建并 source):

Terminal window
# 构建
colcon build --symlink-install --packages-select my_pkg
source install/setup.bash
# 运行
ros2 run my_pkg hello_node

同样,你会看到 Hello, ROS2! 我是 C++ 节点 的日志。

3.3 两种语言的关键差异

对比上面两段代码,可以快速抓住 rclcpp 与 rclpy 的编写差异:

维度 C++ (rclcpp) Python (rclpy)
头文件/导入 #include "rclcpp/rclcpp.hpp" import rclpy
初始化 rclcpp::init(argc, argv) rclpy.init(args=args)
节点创建 std::make_shared<Node>() 或继承 Node 继承 rclpy.node.Node
进入回调循环 rclcpp::spin(node) rclpy.spin(node)
退出清理 rclcpp::shutdown() rclpy.shutdown()
日志宏/方法 RCLCPP_INFO(...) self.get_logger().info(...)
管理方式 智能指针,需显式 spin 对象自动生命周期

C++ 更强调资源管理(智能指针 shared_ptr)与显式控制,性能更高、更适合实时与嵌入场景;Python 上手快、开发效率高、适合原型验证与快速迭代。本系列将始终同时给出两种语言的示例。

3.4 认识 spin:回调循环的本质

无论是 rclcpp::spin(node) 还是 rclpy.spin(node),其本质都是进入一个不断处理回调的循环。ROS2 节点是「事件驱动」的:它平时挂起,一旦有新的消息到达、定时器触发或服务请求进来,就执行对应的回调函数。spin 就是这个「等待并分发事件」的循环。

  • 如果你不再调用 spin,节点的回调永远不会被触发(消息来了也处理不了)。
  • spin 会一直阻塞,直到收到 Ctrl+C 或 shutdown 信号。
  • 异步场景下也可用 spin_some()(轮询一次)或单独管理一个 SingleThreadedExecutor,这在第 8 篇回调组章节会深入。

四、理解节点的生命周期与日志

4.1 节点的生命周期

ROS2 节点有一个规范化的生命周期状态机(第 26 篇硬件控制会用到),但普通节点的大致流程是:构造节点 → 注册功能(话题/服务/定时器)→ 进入 spin 回调 → 关闭清理。理解「构造期执行一次、回调期反复执行、关闭期清理资源」这个节奏,是学好 ROS2 的关键。

# lifecycle_demo.py —— 演示构造期与回调期的区别
import rclpy
from rclpy.node import Node
class LifecycleDemo(Node):
def __init__(self):
super().__init__('lifecycle_demo')
# 构造期:只执行一次
self.get_logger().info('构造期执行一次')
self.count = 0
# 创建一个定时器,每 1 秒触发一次回调
self.create_timer(1.0, self.on_timer)
def on_timer(self):
# 回调期:每秒执行一次
self.count += 1
self.get_logger().info(f'回调期执行第 {self.count} 次')
def main(args=None):
rclpy.init(args=args)
node = LifecycleDemo()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

运行后,你会看到「构造期执行一次」只打一遍,而「回调期执行第 N 次」每秒递增。

4.2 日志级别与过滤

ROS2 的日志系统支持分级过滤,常见的日志级别为 DEBUG、INFO、WARN、ERROR、FATAL。默认只显示 INFO 及以上。在 Python 中:

self.get_logger().set_level(rclpy.logging.LoggingSeverity.DEBUG)
self.get_logger().debug('调试信息')
self.get_logger().info('普通信息')
self.get_logger().warn('警告')
self.get_logger().error('错误')

在 C++ 中:

RCLCPP_DEBUG(this->get_logger(), "调试信息");
RCLCPP_INFO(this->get_logger(), "普通信息");
RCLCPP_WARN(this->get_logger(), "警告");
RCLCPP_ERROR(this->get_logger(), "错误");

你也可以在命令行设置全局日志级别,例如 --ros-args --log-level DEBUG。

4.3 命令行运行节点

作为运行节点最常用的一条指令是:

Terminal window
# 运行某个包里的某个可执行节点
ros2 run <package_name> <executable_name>

例如运行我们上面创建的节点:ros2 run my_pkg hello_node。若只想看节点有哪些可执行文件,可用:

Terminal window
ros2 pkg executables <package_name>

五、实战:组织一个小型节点项目

为了让你把前面的零散概念串起来,我们做一个「带定时器 + 命令行动态参数」的完整小项目。它会在定时器里持续输出计数,并允许通过命令行参数覆盖节点名称。

5.1 完整代码(Python)

# timer_counter.py —— 定时计数器节点,支持命令行参数
import rclpy
from rclpy.node import Node
class TimerCounter(Node):
def __init__(self):
super().__init__('timer_counter')
self.count = 0
self.timer = self.create_timer(0.5, self.on_timer)
def on_timer(self):
self.count += 1
self.get_logger().info(f'计数: {self.count}')
def main(args=None):
rclpy.init(args=args)
node = TimerCounter()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

用命令行参数覆盖节点名称:

Terminal window
python3 timer_counter.py --ros-args --remap __node:=my_counter

此时 ros2 node list 中该节点会显示为 /my_counter。--remap __node:=xxx 是 ROS2 中非常常用的重映射技巧。

5.2 完整代码(C++)

timer_counter.cpp
#include "rclcpp/rclcpp.hpp"
#include <chrono>
class TimerCounter : public rclcpp::Node
{
public:
TimerCounter() : Node("timer_counter"), count_(0)
{
timer_ = this->create_wall_timer(
std::chrono::milliseconds(500),
std::bind(&TimerCounter::onTimer, this));
}
private:
void onTimer()
{
count_++;
RCLCPP_INFO(this->get_logger(), "计数: %d", count_);
}
int count_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<TimerCounter>());
rclcpp::shutdown();
return 0;
}

C++ 版同样可用 --remap __node:=my_counter 重命名节点,运行效果一致。

5.3 节点管理常用指令

完成本节后,你应该能熟练使用以下命令来查看与操作节点:

Terminal window
# 查看当前所有活动的节点
ros2 node list
# 查看某个节点的详细信息(话题、服务、参数等)
ros2 node info /timer_counter
# 查看所有节点及其关联信息
ros2 node list -t

六、总结

本节我们完成了 ROS2 的入门:理解 ROS2 与 ROS1 的架构区别、DDS 与 QoS 的概念、搭建 Humble 开发环境的基本流程,并用 C++ 与 Python 两种语言写出了第一个 Hello World 节点。重点掌握:

  • ROS2 = 分布式中间件,去中心化,DDS 通信底座,QoS 是核心。
  • 环境搭建:Ubuntu 22.04 + Humble,source /opt/ros/humble/setup.bash。
  • 节点是最小单元,rclpy 与 rclcpp 两种写法,spin 是回调循环。
  • 日志与生命周期:构造期一次、回调期反复、关闭期清理。
  • 常用指令:ros2 run、ros2 node list/info、--remap。

下一篇预告

下一节我们将正式认识「节点与 ROS 图」,学习如何用 ros2 命令行、rqt 图形工具观察节点之间的连接关系,理解节点、话题、服务之间是如何通过 ROS 图组织起来的,并动手创建多个相互通信的节点。

ROS2系列教程:Humble环境搭建与Hello World

作者:Wang Shijie

本文链接:https://wsj-blog.pages.dev/posts/ros2-xi-lie-jiao-cheng-humble-huan-jing-da-jian-yu-hello/

本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

Creative Commons

留言评论