ROS2 Jazzy + C++ 实战路线——基础学习1

从 ROS2 基本概念一路讲到 Topic、Service、Action、Parameter、Launch、rosbag2、TF、RViz2 和 URDF,使用的是 Ubuntu 22.04 + ROS2 Jazzy,按下面这条线走:

阶段 学什么 最终你能干什么
1 ROS2、Node、命令行 看懂 ROS2 系统
2 Topic 写发布者/订阅者
3 Service / Action / Parameter 搞懂各种通信方式
4 Workspace、Package、colcon 自己建 C++ ROS2 工程
5 Launch、rosbag2 管理和调试大型项目
6 TF2、URDF、RViz2 建机器人模型和坐标系
7 项目化 把你的动捕/GMR链路 ROS2 化

现在先只记住这个:

复制代码
               ROS2

        ┌──── Node ────┐
        │              │
        │  Publisher   │
        │      │       │
        └──────│───────┘
               │
             Topic
               │
        ┌──────↓───────┐
        │  Subscriber  │
        │              │
        └──── Node ────┘

翻译成人话:

复制代码
Node
程序

Publisher
发数据的人

Subscriber
收数据的人

Topic
传输数据的频道

比如:

复制代码
IMU节点
   │
   │ 发布姿态
   ↓
/imu/data
   │
   ↓
控制器节点

这里:

复制代码
IMU节点          Node
/imu/data        Topic
IMU              Publisher
控制器           Subscriber

这就是 ROS2 最核心的东西之一。

官方文档也把 ROS2 Graph 描述为多个 ROS2 元素共同运行并相互连接形成的网络;通常一个 Node 负责一个相对独立的功能。(Ros Documentation)

我们暂时不碰图形界面、不碰 turtlesim

先验证你的 ROS2 Jazzy 核心环境,这样也不用管之前 VcXsrv/VMware GUI 那些问题。

打开终端:

复制代码
source /opt/ros/jazzy/setup.bash

作用是把 ROS 2 Jazzy 版本的环境变量加载到当前终端:/opt/ros/jazzy/ 是 ROS 2 Jazzy 的安装目录。setup.bash 是 ROS 2 安装时自带的环境配置脚本,source 让这个脚本在当前 Bash 里执行,而不是开子 shell,这样设置的环境变量才会保留下来。

执行后,当前终端才能找到 ros2 命令,找到 ROS 2 的核心库和可执行文件,找到已安装的 ROS 2 包,比如 demo_nodes_cpp,如果不执行这一行,直接输入 ros2,通常会提示:ros2: command not found,或者找不到包。

然后:

复制代码
ros2 --help

ROS2 官方说明,ros2 就是 ROS2 命令行工具的主要入口,下面还有 nodetopicserviceactionparambaglaunch 等子命令。(Ros Documentation)

接下来执行:

复制代码
ros2 node list

终端 1:

复制代码
source /opt/ros/jazzy/setup.bash
ros2 run demo_nodes_cpp talker
  • ros2:ROS 2 的命令行工具。

  • runros2 的子命令,意思是"运行一个节点"。

  • demo_nodes_cpp:一个 ROS 2 示例包,里面包含用 C++ 写的演示节点。

  • talker:这个包里的一个可执行文件,通常是一个发布者节点

启动 demo_nodes_cpp 包里的 talker 节点。

这个节点会:

  • 创建一个发布者

  • 往话题 chatter 上周期性地发布字符串消息

  • 默认大约每秒发布一次,内容类似:

    Publishing: 'Hello World: 1'
    Publishing: 'Hello World: 2'
    Publishing: 'Hello World: 3'

不要关。

再打开 终端 2

复制代码
source /opt/ros/jazzy/setup.bash
ros2 node list

看看现在出现了什么。

再运行:

复制代码
ros2 topic list

然后:

复制代码
ros2 topic echo /chatter

你应该开始看到:

复制代码
data: Hello World: 1

data: Hello World: 2

data: Hello World: 3

这里已经出现了 ROS2 最核心的通信:

复制代码
talker Node
     │
     │ Publisher
     ↓
  /chatter
     │
     │ Topic
     ↓
你执行的 ros2 topic echo

官方 Jazzy 文档也使用 /chatter 演示 Topic 发布与接收。(Ros Documentation)

你暂时不用记几十个命令,只要真正理解这句话:

ROS2 的核心思想,就是把一个大型机器人软件拆成很多 Node,然后让 Node 之间通过标准方式通信。

这句话以后会贯穿你的整个项目。

1. Package 是什么?

可以先把:

复制代码
Package

理解成:

一个功能模块的"文件夹 + 配置 + 代码"。

比如将来你的工程可能有:

复制代码
my_robot_ws/
└── src/
    ├── mocap_driver/
    ├── gmr_retarget/
    ├── robot_output/
    └── humanoid_bringup/

这里:

复制代码
mocap_driver
gmr_retarget
robot_output

每一个都可以是一个 ROS2 Package。

例如:

复制代码
mocap_driver
│
├── Axis驱动
├── Xsens驱动
├── PNLink驱动
├── 参数文件
├── C++源码
└── ROS2配置文件

所以 Package 比 Node 更大。

关系可以理解成:

复制代码
Package
│
├── Node A
├── Node B
├── 配置文件
├── Launch
├── 头文件
└── 其他代码

2. Node 又是什么?

Node 是:

正在运行的 ROS2 功能单元。

例如:

复制代码
mocap_driver package
        │
        └── mocap_driver_node

运行:

复制代码
ros2 run mocap_driver mocap_driver_node

之后系统里才真的出现:

复制代码
/mocap_driver_node

所以一定要区分:

复制代码
Package
   ↓
里面装程序

Executable
   ↓
真正可以运行的程序

Node
   ↓
程序运行起来后,参与 ROS2 通信的节点

这一点非常重要。

初学阶段,你可以近似认为:

复制代码
1 个程序 ≈ 1 个 Node

比如:

复制代码
ros2 run demo_nodes_cpp talker

产生:

复制代码
/talker

但严格来说,一个进程里面可以创建多个 Node。

目前记成:

Node 就是 ROS2 里面负责一项工作的"小程序"。

完全够用了。


3. Message 又是什么?

这里出现:

复制代码
std_msgs/msg/String

什么意思?

拆开:

复制代码
std_msgs / msg / String
   │       │      │
   │       │      └── 消息名称
   │       │
   │       └── message
   │
   └── ROS2标准消息包

就是:

/chatter 里面传输的数据格式是 String。

类似 C++:

复制代码
std::string

但 ROS2 使用自己的 Message 定义通信格式。


4. ROS2 五个东西先建立框架

现在你的脑子里应该开始形成:

复制代码
ROS2
│
├── Package
│       ↓
│    存代码
│
├── Node
│       ↓
│    干活
│
├── Topic
│       ↓
│    数据频道
│
├── Publisher
│       ↓
│    发数据
│
└── Subscriber
        ↓
     收数据

暂时理解这五个就行。

先记住一张图:

复制代码
ROS2 工程
│
└── ros2_ws                 Workspace 工作空间
    │
    ├── src                 放源码
    │   │
    │   └── my_first_pkg    Package
    │
    ├── build               编译中间文件
    ├── install             编译后的可运行环境
    └── log                 编译日志

其中最重要的是:

复制代码
Workspace
    ↓
Package
    ↓
C++源码
    ↓
colcon build
    ↓
Executable
    ↓
ros2 run

这就是以后你开发 ROS2 项目的基本流程。


5. Workspace 是什么?

你可以把 Workspace 理解成:

整个 ROS2 项目的"大工程目录"。

以后你的机器人项目可能是:

复制代码
humanoid_ws/
└── src/
    ├── mocap_driver
    ├── gmr_retarget
    ├── robot_output
    ├── humanoid_description
    └── humanoid_bringup

也就是说:

复制代码
一个 Workspace
可以包含
很多 Package

ROS2 Jazzy 的常见工作流也是在 workspace 的 src 目录中放 Package,然后使用 colcon 构建整个工作空间。(GitHub)

打开终端,先加载 ROS2:

复制代码
source /opt/ros/jazzy/setup.bash

然后:

复制代码
cd ~
mkdir -p ~/ros2_ws/src

再进去看看:

复制代码
cd ~/ros2_ws
ls

现在应该只有:

复制代码
src

所以结构是:

复制代码
/home/你的用户名/
└── ros2_ws/
    └── src/

这里的:

复制代码
ros2_ws

就是我们的 Workspace。

复制代码
src = source

也就是:

放源码的地方。

以后:

复制代码
ros2_ws/src/

里面可能有:

复制代码
mocap_driver/
gmr_retarget/
robot_output/

所以可以理解成:

复制代码
ros2_ws
│
└── src
      │
      ├── 包1
      ├── 包2
      ├── 包3
      └── 包4

6. 创建第一个 C++ Package

进入:

复制代码
cd ~/ros2_ws/src

执行:

复制代码
ros2 pkg create \
  --build-type ament_cmake \
  --license Apache-2.0 \
  --dependencies rclcpp \
  --node-name my_first_node \
  my_first_pkg

拆开看:

复制代码
ros2 pkg create

意思:

创建 ROS2 Package。

然后:

复制代码
--build-type ament_cmake

意思:

这是一个 C++ Package。

目前你可以近似记:

复制代码
C++     → ament_cmake
Python  → ament_python

我们以后主要走 C++。


接下来:

复制代码
--dependencies rclcpp

表示这个 Package 要用:

复制代码
rclcpp

rclcpp 就是:

ROS2 的 C++ 客户端库。

以后你写:

复制代码
rclcpp::Node
rclcpp::Publisher
rclcpp::Subscription

都来自这里。

最后:

复制代码
my_first_pkg

就是你的 Package 名字。

而:

复制代码
my_first_node

是生成的可执行程序名字。

ROS2 官方教程也支持使用 ros2 pkg create --build-type ament_cmake ... --node-name ... 创建 C++ Package 和示例源文件。(GitHub)


7. package.xml 是干什么的?

暂时大白话理解:

复制代码
package.xml

就是:

这个 Package 的身份证。

里面告诉 ROS2:

复制代码
我叫什么
我是什么版本
谁维护
什么许可证
我依赖什么包

可以看看:

复制代码
cat package.xml

里面你应该能找到类似:

复制代码
<name>my_first_pkg</name>

以及:

复制代码
<depend>rclcpp</depend>

说明:

复制代码
my_first_pkg
依赖
rclcpp

8. CMakeLists.txt 又是什么?

这个非常重要。

你已经有一些 C/C++ 基础,所以可以这样理解:

复制代码
CMakeLists.txt

就是告诉编译系统:

我的 C++ 源文件在哪里、需要什么库、最终要生成什么程序。

也就是说:

复制代码
my_first_node.cpp
        ↓
CMakeLists.txt
        ↓
CMake
        ↓
编译
        ↓
my_first_node

ROS2 的 C++ Package 使用的是:

复制代码
ament_cmake

但底下依然是你熟悉的:

复制代码
CMake

所以以后你的 EtherCAT、GMR、SDK 代码往 ROS2 搬时,这部分其实非常重要。


9. 开始编译

现在一定回到:

复制代码
ros2_ws

而不是在:

复制代码
ros2_ws/src

执行:

复制代码
cd ~/ros2_ws

确认:

复制代码
pwd

应该类似:

复制代码
/home/skr/ros2_ws

然后:

复制代码
source /opt/ros/jazzy/setup.bash

开始编译:

复制代码
colcon build --packages-select my_first_pkg

这里:

复制代码
colcon build

意思:

编译 ROS2 Workspace。

而:

复制代码
--packages-select my_first_pkg

意思:

我这次只编译 my_first_pkg

以后你的 Workspace 可能有几十个 Package。

修改了:

复制代码
gmr_retarget

就没必要所有东西全部重新编译,可以:

复制代码
colcon build --packages-select gmr_retarget

这是以后非常常用的命令。ROS2 文档与 Jazzy 工程都普遍使用这种单包构建方式。(GitHub)


10. 编译成功后发生了什么?

运行:

复制代码
ls

现在应该出现:

复制代码
build
install
log
src

也就是:

复制代码
ros2_ws/
│
├── build/
├── install/
├── log/
└── src/

这三个新目录是:

复制代码
build

编译过程中的中间文件。

复制代码
install

真正安装好的 ROS2 Package 和程序。

复制代码
log

编译日志。

以后遇到:

复制代码
编译失败

经常就会去看:

复制代码
build/
log/

11. source install/setup.bash

编译完以后执行:

复制代码
source ~/ros2_ws/install/setup.bash

然后:

复制代码
ros2 pkg list | grep my_first_pkg

应该出现:

复制代码
my_first_pkg

这说明:

ROS2 终于认识你的 Package 了。

你现在已经看到两个非常像的命令。

第一个:

复制代码
source /opt/ros/jazzy/setup.bash

第二个:

复制代码
source ~/ros2_ws/install/setup.bash

这是非常关键的区别。

可以这么理解:

复制代码
/opt/ros/jazzy
        ↓
ROS2 官方环境

~/ros2_ws
        ↓
你自己开发的环境

所以:

复制代码
source /opt/ros/jazzy/setup.bash

相当于告诉终端:

我现在要使用 ROS2 Jazzy。

而:

复制代码
source ~/ros2_ws/install/setup.bash

相当于:

再把我自己开发的 Package 加进 ROS2 环境。

这就是:

复制代码
Underlay
ROS2 Jazzy
     ↓
Overlay
你自己的 Workspace

Jazzy 开发流程中,在构建 Workspace 后 source install/setup.bash 来加载 overlay 是标准做法。(GitHub)

复制代码
ros2 run demo_nodes_cpp talker

意思是:

运行 demo_nodes_cpp 这个包里的 talker 可执行文件。

拆开看:

  • ros2:ROS 2 命令行工具

  • run:运行一个节点

  • demo_nodes_cpp:包名,ROS 2 官方 C++ 示例包

  • talker:可执行文件名

运行后会启动一个节点,节点名默认也叫 /talker,它会不断往 /chatter 话题发布字符串消息


复制代码
ros2 node info /talker

意思是:

查看名为 /talker 的节点的信息。

前提是 talker 节点正在运行。

它会列出这个节点的:

  • 发布者(Publishers)

  • 订阅者(Subscribers)

  • 服务端(Service Servers)

  • 客户端(Service Clients)

  • Action 服务端和客户端

  • 参数相关服务

注意:

  • /talker节点名,不是可执行文件名。

  • 节点名默认和可执行文件名一样,但可以通过参数改。

  • 如果节点没运行,会提示找不到节点。

可以先用:

复制代码
ros2 node list

查看当前有哪些节点在运行。

命令 作用
ros2 run demo_nodes_cpp talker 运行 demo_nodes_cpp 包里的 talker 可执行文件
ros2 node info /talker 查看 /talker 节点的发布、订阅、服务等信息
Executable 可执行文件,ros2 run 的第二个参数
pwd 打印当前工作目录

简单说:

ros2 run 负责运行节点;ros2 node info 负责查看节点;Executable 是可执行文件;pwd 是看当前目录。

nano my_first_node.cpp 的意思是:

nano 这个终端文本编辑器,打开当前目录下名为 my_first_node.cpp 的文件。

如果这个文件不存在,nano 会新建它。

它只是编辑文件,不是编译,也不是运行。


12. 运行自己的程序

现在:

复制代码
ros2 run my_first_pkg my_first_node

应该能看到生成程序的输出。

到这里其实已经非常重要了。

因为这是第一次:

复制代码
你自己的源码

        ↓

ros2 pkg create

        ↓

my_first_pkg

        ↓

colcon build

        ↓

install

        ↓

source install/setup.bash

        ↓

ros2 run

        ↓

程序运行

你已经走完 ROS2 C++ 开发最基本的一整圈。

相关推荐
life码农1 小时前
python框架Flask多语言配置示例
python·flask
苏离~Hack1 小时前
SL-crawler:一个可视化配置的通用网页与 API 数据采集工具
python
小白学大数据1 小时前
Python 小工具实战:用问财接口搭建金融数据采集器
开发语言·人工智能·python
j7~1 小时前
【Linux网络加餐】(篇七)网络版计算器(中):协议落地、报文分隔与完整链路
linux·c++·网络编程·tcp·报文分割·网络计算器·协议落地
青少儿编程课堂1 小时前
多源最短路与最小环(Floyd 算法图论解析)
c++·python·算法·bfs·信息学竞赛
PiaoKe___1 小时前
从端云解耦到可编程 Android 实例:云手机架构解析与 Python 批量管控实战
arm开发·python·架构·自动化
6Hzlia1 小时前
【Classic 150 刷题计划】 LeetCode 228. 汇总区间 | C++ 锚点游标与断点检测法
c++·算法·leetcode
浪淘沙jkp2 小时前
全程无人值守完成ubuntu22.04到xubuntu 24.04.5的升级
ubuntu
计算机源码社2 小时前
基于Hadoop+Spark的商家优惠券营销效果数据分析与可视化-基于Python的商家优惠券营销效果检测与评估分析系统
大数据·hadoop·python·数据挖掘·spark·毕业设计·数据可视化