Ubuntu 22.04 搭建 ROS 2 Humble 环境与创建节点教程

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 无法自动协调。

失败的尝试:

  1. sudo apt upgrade -y (系统升级)
  2. sudo apt full-upgrade -y (全面升级) 以上尝试均失败,apt 仍然报告同样的依赖冲突。

最终解决方案: 使用 aptitude 进行依赖降级。

  1. 安装 aptitude

    bash 复制代码
    sudo apt install aptitude -y
  2. 使用 aptitude 尝试安装 ROS 2:

    bash 复制代码
    sudo aptitude install ros-humble-desktop
  3. aptitude 提供了多个解决方案。第一个方案是"保持现状(不安装)",我们选择 n (否)。

  4. 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/?]

  5. 选择 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),必须从源码编译。

  1. 添加 ROS 1 软件源(导致错误)

    bash 复制代码
    sudo 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 update

    apt update 报错 404 Not Found,因为 jammyRelease 文件不存在。

  2. 安装编译工具

    bash 复制代码
    sudo apt install python3-pip python3-rosdep python3-rosinstall-generator python3-wstool python3-rosinstall build-essential cmake git -y
  3. 初始化 rosdep(遇到网络问题)

    bash 复制代码
    sudo rosdep init

    问题: TimeoutError: The read operation timed out解决: 网络波动,重试后成功。

    bash 复制代码
    rosdep update

    问题: 下载 fuerte.yaml 时超时。 分析: 此为古老版本,不影响 Noetic 编译,可忽略。

  4. 下载 Noetic 源码(遇到网络问题) 创建工作空间并下载源码列表:

    bash 复制代码
    mkdir -p ~/ros1_ws/src
    cd ~/ros1_ws/src
    rosinstall_generator desktop --rosdistro noetic --deps --tar > noetic-desktop.rosinstall

    使用 wstool 拉取源码:

    bash 复制代码
    wstool 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 初始化工作空间

  1. 创建 src 目录:

    bash 复制代码
    mkdir -p ~/ros2_ws/src
  2. 进入根目录并执行空构建:

    bash 复制代码
    cd ~/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)

  1. 进入 src 目录:

    bash 复制代码
    cd ~/ros2_ws/src
  2. 使用 ros2 pkg create 创建功能包和节点骨架。 注意: package_name (my_adder_pkg) 必须在 --dependencies 标志之前,否则参数解析会出错。

    bash 复制代码
    ros2 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 运行节点

  1. 刷新当前终端环境,使其能找到刚编译好的可执行文件:

    bash 复制代码
    source install/setup.bash
  2. 使用 ros2 run 运行节点:

    bash 复制代码
    ros2 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)

  1. 进入 src 目录

    bash 复制代码
    cd ~/ros2_ws/src
  2. 创建功能包 创建一个名为 circle_publisher_pkg 的包,该包依赖于 rclcpp (C++库) 和 visualization_msgs (RViz标记消息库),并自动生成一个名为 draw_circle_node 的节点骨架。

    bash 复制代码
    ros2 pkg create --build-type ament_cmake --node-name draw_circle_node circle_publisher_pkg --dependencies rclcpp visualization_msgs

5.2 编写 C++ 节点代码

  1. 打开 C++ 文件 使用 gedit 编辑器打开新创建的 C++ 源文件。

    bash 复制代码
    gedit ~/ros2_ws/src/circle_publisher_pkg/src/draw_circle_node.cpp
  2. 粘贴代码 删除文件中的所有模板代码,并替换为以下完整代码。该代码创建了一个节点,该节点通过一个定时器(每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;
    }
  3. 保存并关闭 保存并关闭 gedit 编辑器。

5.3 编译新功能包

  1. 回到工作空间根目录

    bash 复制代码
    cd ~/ros2_ws
  2. 运行构建 使用 --packages-select 标志可以只编译这个新包,以节省时间。

    bash 复制代码
    colcon build --packages-select circle_publisher_pkg

    输出 Summary: 1 package finished,表示编译成功。

5.4 运行节点并使用 RViz 可视化

此步骤需要使用两个终端。

终端 1:运行画圆节点

  1. 激活工作空间环境

    bash 复制代码
    cd ~/ros2_ws
    source install/setup.bash
  2. 运行节点

    bash 复制代码
    ros2 run circle_publisher_pkg draw_circle_node

    终端显示日志:"画圆节点已启动,正在发布 /circle_marker 话题"。

终端 2:启动并配置 RViz

  1. 打开一个新终端

  2. 激活 ROS 2 系统环境

    bash 复制代码
    source /opt/ros/humble/setup.bash
  3. 启动 RViz

    bash 复制代码
    rviz2

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++ 代码中定义的方程一致。

相关推荐
橘子134 小时前
Linux线程同步(四)
linux·c++
Xの哲學5 小时前
Linux Netlink全面解析:从原理到实践
linux·网络·算法·架构·边缘计算
yolo_guo5 小时前
opencv 学习: 04 通过ROI处理图片局部数据,以添加水印为例
linux·c++·opencv
「QT(C++)开发工程师」5 小时前
VTK开源视觉库 | 行业应用第一篇
linux·qt·物联网·计算机视觉·信息可视化·vtk
LCG元6 小时前
记一次线上故障排查:Linux磁盘空间莫名占满,原来是它在"作妖"(附清理脚本)
linux
杜子不疼.6 小时前
【Linux】信号机制详解:进程间通信的核心
linux·运维·服务器
..过云雨6 小时前
11.【Linux系统编程】文件系统详解——从磁盘硬件到文件系统
linux·c++·后端·缓存
qq_271581797 小时前
Ubuntu OpenCV C++ 获取MYNT EYE S1030-IR摄像头图像
linux·opencv·ubuntu
156082072197 小时前
在Ubuntu20.04下安装iperf3
linux·ubuntu