Ubuntu 22.04 搭建 ROS 2 Humble 环境与创建节点教程
虚拟机以及ubuntu22.04搭建见以下链接
juejin.cn/post/756722...
本文档记录了在 VMware 虚拟机中的 Ubuntu 22.04 (Jammy Jellyfish) 操作系统上,从零开始安装 ROS 2 Humble,处理安装过程中的依赖冲突,并最终完成一个 C++ 功能包(3+4=7 加法器)的创建、编译与运行的完整过程。
一、 环境准备与 ROS 2 Humble 安装
1.1 系统环境检查 (Locale)
在终端输入以下代码,确保系统支持 UTF-8 编码。
bash
locale
预期输出应包含 LANG=...UTF-8。
1.2 添加 ROS 2 GPG 密钥
添加 ROS 2 软件源的 GPG 密钥以验证软件包。
bash
sudo apt install curl -y && sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
遇到的问题: apt 锁被占用(unattended-upgrade 进程)。
csharp
正在等待缓存锁:无法获得锁 /var/lib/dpkg/lock-frontend...
解决方案: 强制停止自动更新进程并移除锁文件。
bash
sudo killall apt.systemd.daily apt-get unattended-upgrade
sudo rm /var/lib/dpkg/lock-frontend
sudo rm /var/lib/dpkg/lock
sudo dpkg --configure -a
之后,重新运行 GPG 密钥添加命令。
1.3 添加 ROS 2 软件源
将 ROS 2 的 apt 仓库添加到系统源列表。
bash
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
1.4 更新软件源列表
刷新 apt 缓存以拉取新添加的 ROS 2 仓库信息。
bash
sudo apt update
1.5 安装 ROS 2 Humble (Desktop Full)
安装 ROS 2 桌面版。
bash
sudo apt install ros-humble-desktop -y
遇到的问题: 依赖关系冲突(libpulse-dev, libudev-dev 等版本不匹配)。
yaml
下列软件包有未满足的依赖关系:
libpulse-dev : 依赖: libpulse0 (= 1:15.99.1+dfsg1-1ubuntu1) 但是 1:15.99.1+dfsg1-1ubuntu2.2 正要被安装
...
E: 无法修正错误...
分析: 系统中某些基础包的版本(如 libpulse0)高于 ROS 2 依赖包(如 libpulse-dev)所要求的版本,apt 无法自动协调。
失败的尝试:
sudo apt upgrade -y(系统升级)sudo apt full-upgrade -y(全面升级) 以上尝试均失败,apt仍然报告同样的依赖冲突。
最终解决方案: 使用 aptitude 进行依赖降级。
-
安装
aptitude:bashsudo apt install aptitude -y -
使用
aptitude尝试安装 ROS 2:bashsudo aptitude install ros-humble-desktop -
aptitude提供了多个解决方案。第一个方案是"保持现状(不安装)",我们选择n(否)。 -
aptitude提供了第二个解决方案: 降级 下列软件包: libpulse-mainloop-glib0 [... -> 1:15.99.1+dfsg1-1ubuntu1] libpulse0 [... -> 1:15.99.1+dfsg1-1ubuntu1] ... libudev1 [... -> 249.11-0ubuntu3.16] python3 [... -> 3.10.6-1~22.04] ... 是否接受该解决方案?[Y/n/q/?] -
选择
Y(是)。aptitude成功将冲突的包降级,并完成了ros-humble-desktop的安装。
1.6 验证 ROS 2 安装
激活 ROS 2 环境并检查 ros2 命令是否可用。
bash
source /opt/ros/humble/setup.bash
ros2 --help
成功显示 ros2 的帮助信息,证明 ROS 2 安装成功。
二、 (已放弃)尝试安装 ROS 1 Noetic(失败记录)
此部分操作后已全部回滚。
目标: 在 Ubuntu 22.04 上与 ROS 2 共存安装 ROS 1 Noetic。 核心问题: ROS 1 Noetic 官方不支持 Ubuntu 22.04 (jammy),必须从源码编译。
-
添加 ROS 1 软件源(导致错误)
bashsudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 sudo apt updateapt update报错404 Not Found,因为jammy的Release文件不存在。 -
安装编译工具
bashsudo apt install python3-pip python3-rosdep python3-rosinstall-generator python3-wstool python3-rosinstall build-essential cmake git -y -
初始化
rosdep(遇到网络问题)bashsudo rosdep init问题:
TimeoutError: The read operation timed out。 解决: 网络波动,重试后成功。bashrosdep update问题: 下载
fuerte.yaml时超时。 分析: 此为古老版本,不影响 Noetic 编译,可忽略。 -
下载 Noetic 源码(遇到网络问题) 创建工作空间并下载源码列表:
bashmkdir -p ~/ros1_ws/src cd ~/ros1_ws/src rosinstall_generator desktop --rosdistro noetic --deps --tar > noetic-desktop.rosinstall使用
wstool拉取源码:bashwstool init . noetic-desktop.rosinstall问题: 源码下载过程中断,报告
[Errno 111] Connection refused。 分析: 在下载大量源码包时,由于网络不稳定导致部分包下载失败。
结论: 决定放弃 ROS 1 的安装,因为它在 22.04 上的编译过程受网络影响大,且维护复杂。
三、 清理 ROS 1 并配置 ROS 2 环境
3.1 删除 ROS 1 工作空间
bash
cd ~
rm -rf ~/ros1_ws
3.2 移除 ROS 1 软件源及工具
bash
sudo rm /etc/apt/sources.list.d/ros-latest.list
sudo apt remove python3-rosdep python3-rosinstall-generator python3-wstool python3-rosinstall -y
sudo apt autoremove -y
3.3 永久配置 ROS 2 环境
将 ROS 2 系统环境写入 .bashrc 使其自动加载。
bash
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
四、 创建 ROS 2 工作空间与加法器功能包
4.1 安装 Colcon 构建工具
在执行 colcon build 时发现 colcon:未找到命令。 原因: 核心构建工具未在 PATH 中。 解决: 安装 ros-dev-tools 并重新激活环境。
bash
sudo apt install ros-dev-tools -y
source /opt/ros/humble/setup.bash
4.2 初始化工作空间
-
创建
src目录:bashmkdir -p ~/ros2_ws/src -
进入根目录并执行空构建:
bashcd ~/ros2_ws colcon build输出
Summary: 0 packages finished,表示工作空间初始化成功。
4.3 激活工作空间环境
将工作空间环境(install/setup.bash)也加入 .bashrc,使其在系统环境 之后 加载。
bash
cd ~/ros2_ws
source install/setup.bash
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
4.4 创建 C++ 功能包 (Package)
-
进入
src目录:bashcd ~/ros2_ws/src -
使用
ros2 pkg create创建功能包和节点骨架。 注意:package_name(my_adder_pkg) 必须在--dependencies标志之前,否则参数解析会出错。bashros2 pkg create --build-type ament_cmake --node-name simple_adder my_adder_pkg --dependencies rclcpp此命令自动创建了
my_adder_pkg目录及src/simple_adder.cpp文件。
4.5 编写 C++ 节点代码 (3+4=7)
编辑自动生成的 simple_adder.cpp 文件。
bash
gedit ~/ros2_ws/src/my_adder_pkg/src/simple_adder.cpp
完整代码 (simple_adder.cpp):
cpp
#include "rclcpp/rclcpp.hpp"
// 创建一个继承自 rclcpp::Node 的类
class SimpleAdderNode : public rclcpp::Node
{
public:
// 构造函数,节点名字叫 "simple_adder_node"
SimpleAdderNode() : Node("simple_adder_node")
{
// --- 加法逻辑 ---
int a = 3;
int b = 4;
int sum = a + b;
// 使用 RCLCPP_INFO 将结果打印到终端
RCLCPP_INFO(this->get_logger(), "计算结果: %d + %d = %d", a, b, sum);
// --- 逻辑结束 ---
}
};
// --- 标准的 ROS 2 main 函数 ---
int main(int argc, char * argv[])
{
// 1. 初始化 ROS 2
rclcpp::init(argc, argv);
// 2. 创建一个 SimpleAdderNode 节点实例并运行它
rclcpp::spin(std::make_shared<SimpleAdderNode>());
// 3. 关闭 ROS 2
rclcpp::shutdown();
return 0;
}
保存并关闭 gedit。
4.6 编译功能包
回到工作空间根目录,使用 colcon 进行编译。 注:由于使用了 --node-name 参数创建,CMakeLists.txt 已被自动配置,无需手动修改。
bash
cd ~/ros2_ws
colcon build
输出 Summary: 1 package finished,表示编译成功。
4.7 运行节点
-
刷新当前终端环境,使其能找到刚编译好的可执行文件:
bashsource install/setup.bash -
使用
ros2 run运行节点:bashros2 run my_adder_pkg simple_adder
最终输出:
ini
[INFO] [1678886400.000000000] [simple_adder_node]: 计算结果: 3 + 4 = 7
任务完成。 好的,这是接续上一篇教程的第五部分。
五、 创建 ROS 2 话题发布器 (RViz 画圆)
本节记录了在 ~/ros2_ws 工作空间中创建第二个功能包的过程。该功能包创建了一个节点,用于发布 visualization_msgs/Marker 消息,以在 RViz 中显示一个方程为 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x − 2 ) 2 + ( y − 2 ) 2 = 4 (x-2)^2 + (y-2)^2 = 4 </math>(x−2)2+(y−2)2=4 的圆。
5.1 创建功能包 (Package)
-
进入
src目录bashcd ~/ros2_ws/src -
创建功能包 创建一个名为
circle_publisher_pkg的包,该包依赖于rclcpp(C++库) 和visualization_msgs(RViz标记消息库),并自动生成一个名为draw_circle_node的节点骨架。bashros2 pkg create --build-type ament_cmake --node-name draw_circle_node circle_publisher_pkg --dependencies rclcpp visualization_msgs
5.2 编写 C++ 节点代码
-
打开 C++ 文件 使用
gedit编辑器打开新创建的 C++ 源文件。bashgedit ~/ros2_ws/src/circle_publisher_pkg/src/draw_circle_node.cpp -
粘贴代码 删除文件中的所有模板代码,并替换为以下完整代码。该代码创建了一个节点,该节点通过一个定时器(每500ms)发布一个
Marker消息,该消息包含构成圆形的点集。完整代码 (
draw_circle_node.cpp):cpp#include "rclcpp/rclcpp.hpp" #include "visualization_msgs/msg/marker.hpp" #include <cmath> // 用于 sin 和 cos #include <chrono> // 用于时间 // 使用 C++ 的 using 声明简化代码 using namespace std::chrono_literals; // 继承 rclcpp::Node class DrawCircleNode : public rclcpp::Node { public: // 构造函数 DrawCircleNode() : Node("draw_circle_node") { // 创建一个 Marker 消息的发布者 // 话题名称为 "circle_marker",队列大小为 10 publisher_ = this->create_publisher<visualization_msgs::msg::Marker>("circle_marker", 10); // 创建一个定时器,每 500ms (0.5秒) 调用一次 publish_circle 回调函数 timer_ = this->create_wall_timer( 500ms, std::bind(&DrawCircleNode::publish_circle, this)); RCLCPP_INFO(this->get_logger(), "画圆节点已启动,正在发布 /circle_marker 话题"); } private: // 定时器回调函数,用于计算并发布 Marker void publish_circle() { auto marker = visualization_msgs::msg::Marker(); // 1. 设置 Marker 的基础属性 // 设置坐标系 (Frame ID) // 这是一个虚拟的2D坐标系,我们稍后在 RViz 中会用到它 marker.header.frame_id = "my_circle_frame"; marker.header.stamp = this->get_clock()->now(); marker.ns = "shapes"; // 命名空间 marker.id = 0; // ID // 设置类型:LINE_STRIP (线带) marker.type = visualization_msgs::msg::Marker::LINE_STRIP; // 设置动作:ADD (添加/修改) marker.action = visualization_msgs::msg::Marker::ADD; // 设置姿态 (我们画的是2D,所以 Z=0, 旋转 W=1 即可) marker.pose.position.z = 0; marker.pose.orientation.w = 1.0; // 设置线条的粗细 marker.scale.x = 0.1; // 线宽 // 设置颜色 (红色, 100%不透明) marker.color.r = 1.0f; marker.color.g = 0.0f; marker.color.b = 0.0f; marker.color.a = 1.0; // 2. 计算圆上的点 // 方程: (x-2)^2 + (y-2)^2 = 4 // 中心: (cx, cy) = (2, 2) // 半径: r = 2 double radius = 2.0; double center_x = 2.0; double center_y = 2.0; int points_count = 100; // 用100个点来近似这个圆 // 循环生成点 for (int i = 0; i <= points_count; i++) { // 角度从 0 到 2*PI double angle = static_cast<double>(i) / static_cast<double>(points_count) * 2.0 * M_PI; // 使用参数方程计算 x 和 y // x = cx + r * cos(angle) // y = cy + r * sin(angle) geometry_msgs::msg::Point p; // 创建一个点 p.x = center_x + radius * std::cos(angle); p.y = center_y + radius * std::sin(angle); p.z = 0; // 2D圆,z=0 // 将这个点添加到 Marker 的点列表中 marker.points.push_back(p); } // 3. 发布 Marker publisher_->publish(marker); } // 私有成员变量 rclcpp::TimerBase::SharedPtr timer_; rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr publisher_; }; // --- 标准的 ROS 2 main 函数 --- int main(int argc, char * argv[]) { rclcpp::init(argc, argv); // 使用 spin 让节点持续运行(这样定时器才能工作) rclcpp::spin(std::make_shared<DrawCircleNode>()); rclcpp::shutdown(); return 0; } -
保存并关闭 保存并关闭
gedit编辑器。
5.3 编译新功能包
-
回到工作空间根目录
bashcd ~/ros2_ws -
运行构建 使用
--packages-select标志可以只编译这个新包,以节省时间。bashcolcon build --packages-select circle_publisher_pkg输出
Summary: 1 package finished,表示编译成功。
5.4 运行节点并使用 RViz 可视化
此步骤需要使用两个终端。
终端 1:运行画圆节点
-
激活工作空间环境
bashcd ~/ros2_ws source install/setup.bash -
运行节点
bashros2 run circle_publisher_pkg draw_circle_node终端显示日志:"画圆节点已启动,正在发布 /circle_marker 话题"。
终端 2:启动并配置 RViz
-
打开一个新终端
-
激活 ROS 2 系统环境
bashsource /opt/ros/humble/setup.bash -
启动 RViz
bashrviz2
4. 配置 RViz a. 设置 Fixed Frame (固定坐标系) :在 RViz 窗口左侧的 "Global Options" -> "Fixed Frame" 处,将默认的 "map" 双击手动修改为 my_circle_frame,然后按 Enter 键。 b. 添加 Marker 显示 :点击左下角的 "Add" 按钮,在弹出的窗口中选择 "Marker" (位于 rviz_default_plugins/Marker),然后点击 "OK"。
最终结果: RViz 的主窗口中将显示一个红色的圆,其圆心位于 (2, 2),半径为 2,与 C++ 代码中定义的方程一致。