ROS2 基础概念
前置准备
首先在主目录下创建一个文件夹用于存放后续实验课程所编写的所有代码。例如创建一个名为 ros_code 的文件夹。
接着双击进入刚创建好的文件夹,在空白处右键,然后选择在终端中打开,然后输入 code . 这样就能在 VSCode 中打开这个文件夹用于编写代码了。
工作空间和功能包
说明重要概念 ROS 2 代码不是随便放的,而是放在工作空间里管理; 节点不是直接裸跑的脚本,而是作为功能包中的可执行入口来组织。
1. 什么是工作空间
工作空间(workspace) 可以理解为 ROS 2 工程的总目录。它不是一个单独的程序,而是一个用于统一管理多个功能包、统一构建、统一加载环境的开发目录。工作空间本质上就是一个文件夹。
一个典型的 ROS 2 工作空间至少会包含:
src/:存放源代码包的文件夹(重要)build/:构建过程中产生的中间文件install/:安装后的可执行文件与环境脚本log/:构建日志
2. 什么是功能包
功能包(package) 是 ROS 2 中组织代码的基本单位。一个包里可以包含:
- 节点程序
- 配置文件
- 启动文件
- 接口定义
- 测试代码
- 依赖声明
一个功能包的目录通常如下:
my_first_pkg/
├── package.xml
├── resource/
├── setup.cfg
├── setup.py
├── my_first_pkg/
│ └── __init__.py
└── test/package.xml:用于描述包的基本信息与依赖关系。它相当于 ROS 2 包的"身份证"。setup.py:用于 Python 包安装与入口配置。后续如果要让 ros2 run 找到节点,通常要在这里配置console_scripts- 和功能包同名的 Python 目录:这里面的 .py 文件才是实际的 Python 模块代码位置。后续节点的创建都要在这个文件夹下书写代码。
3. 工作空间与功能包的关系
- 一个 工作空间 里可以有多个 功能包
- 一个 功能包 里可以有一个或多个节点
- 节点运行前,通常要先完成包的构建,再 source 工作空间环境
4. 三者之间的层次关系
可以这样理解:
- 工作空间:总工程目录
- 功能包:工程中的模块
- 节点:模块中真正运行的程序
节点
1. 节点的概念
在 ROS 2 中,节点(Node) 是系统中的基本执行单元。一个节点通常负责完成一个相对独立的功能,例如数据采集、传感器处理、路径规划、运动控制等。多个节点共同组成一个完整的 ROS 2 应用系统。一个节点相当于一个可执行程序。
2. 节点的基本组成
一个典型的 ROS 2 节点通常包含以下要素:
- 节点名称(Node Name):唯一标识该节点(在同一命名空间下)。
- 发布者(Publisher):向某个话题发送消息。
- 订阅者(Subscriber):从某个话题接收消息。
- 服务端(Service Server):响应其他节点的服务请求。
- 客户端(Service Client):向其他节点发起服务请求。
- 参数(Parameters):可动态配置的变量(如速度上限、采样频率等)。
- 定时器(Timer):周期性执行某些操作(如每秒发布一次数据)。
说明提示 后续实验中会学到所有内容。
3. 节点常用命令
查看当前有哪些节点
ros2 node list作用:列出当前系统里所有正在运行的节点。
查看某个节点的详细信息
# ros2 node info <node_name> # 查看节点信息
ros2 node info /node_name学习内容1:工作空间
第一步:创建工作空间
首先,在 VSCode 中打开终端,执行以下指令:
mkdir -p workspace_name/src # 创建工作空间和存储源代码的文件夹
cd workspace_name # 进入工作空间之中,后续ROS包的构建与编译都要在这个路径下进行workspace_name:工作空间的命名,可以自定义。
例如,创建一个名为 lq_ws 的工作空间:
执行完上述命令后当前文件夹下出现了创建的文件夹。接着在终端中进入工作空间目录:
第二步:第一次构建工作空间
⚠️ 警告注意(重中之重) 构建工作空间一定要在上述提到的工作空间的目录下进行构建,不能在其他路径,一定要注意路径!!!
colcon build执行之后没有报错表示执行成功。现在可以看到工作空间的目录由原先的我们自己创建的只有源代码的文件夹,变为了上述提到的四个文件夹。说明工作包完全构建成功。
第三步:加载工作空间环境
⚠️ 警告 同理在工作目录的根路径下执行
source install/setup.bash- 构建完成后不执行这句指令:ROS 2 找不到你的包无法运行。
- 执行这句指令仅对当前终端会话有效(即只影响你运行该命令的那个 shell)。不会影响其他终端、系统全局环境或新打开的终端。
学习内容2:功能包
第一步:进入 src
由上述知识部分可知,我们构建的功能包以及代码都是存储在 src 文件夹下。
cd src执行后可以发现路径又发生了改变。
第二步:创建 Python 功能包
# 基本语法
ros2 pkg create package_name [选项]其中 package_name 是你希望创建的 ROS 2 包的名称,必须符合 ROS 2 的命名规范(通常使用小写字母、数字、下划线,不能以数字开头,不能包含连字符 - 等)。
一般我们只会使用 --build-type 和 --dependencies 参数。但由于我们使用 Python 去构建代码,因此 --build-type 要注意设为 ament_python。如果使用 C++ 构建代码,则该参数的值为 ament_cmake。--dependencies 参数表示这个包的依赖项,包括依赖的功能包或是 Python 的第三方库。
例如:
ros2 pkg create lq_pkg1 --build-type ament_python --dependencies rclpy终端输出的警告信息是因为没有添加开源依赖的许可证,这个可以忽略。
package.xml:定义包的元数据(metadata),如包名、版本、作者、许可证、依赖项等。setup.py:Python 包的标准安装脚本,用于构建和安装 Python 模块、节点、脚本、资源,除此之外,还有"entry_points"配置的程序入口。- 和功能包同名的子目录:存放代码文件。
一些参数说明
| 参数 | 说明 |
|---|---|
--build-type <type> | 指定构建类型,默认为 ament_cmake。可选值:ament_cmake(CMake 构建系统)、ament_python(纯 Python 包) |
--dependencies <pkg1> [pkg2 ...] | 指定该包依赖的其他 ROS 2 包(会自动写入 package.xml 和 CMakeLists.txt 或 setup.py)。 |
--license <license> | 指定开源许可证(如 MIT、Apache-2.0、BSD 等),默认为 TODO。 |
--maintainer-email <email> | 维护者邮箱(会写入 package.xml)。 |
--maintainer-name <name> | 维护者姓名(会写入 package.xml)。 |
--node-name <node> | 创建一个初始节点文件(仅对 ament_python 有效)。 |
--library-name <lib> | 创建一个初始 C++ 库(仅对 ament_cmake 有效)。 |
--description "<desc>" | 包的简短描述(写入 package.xml)。 |
学习内容3:构建并验证功能包
第一步:回到工作空间根目录
cd .. # ..表示回到上级目录第二步:构建工作空间
colcon build第三步:source 工作空间环境
source install/setup.bash第四步:查看包是否被识别
ros2 pkg list | grep lq_pkg1该命令用于查看 ROS2 中的包列表,grep 表示过滤。有输出即表示构建的功能包添加到了环境变量中。
对比实验
对比实验 A:不 source 时查询包
新开一个终端,不执行 source /install/setup.bash,直接输入:
ros2 pkg list | grep my_first_pkg对比实验 B:source 后再查询
说明结论 通过两个终端的对比可以发现不 Source 的话是查不到我们自己构建的包的。
学习内容4:编写一个 Hello World 节点
在上述创建的功能包下编写节点,注意是在和包名同名的文件夹下创建 py 文件:
编写代码
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
class HelloNode(Node):
def __init__(self):
super().__init__('hello_node') # ROS2节点父类初始化
self.get_logger().info('Hello World!') # ROS2日志输出
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化
node = HelloNode() # 创建ROS2节点对象并进行初始化
rclpy.spin(node) # 循环等待ROS2退出
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
if __name__ == '__main__':
main()平时调试节点时可以直接运行这份代码,但为规范流程,我们继续后续的学习。后续所有代码都可以以上述这份代码作为框架进行扩展。
说明提示 spin 方法会持续运行一个节点,除非在代码里设置关闭或手动关闭。
配置 setup.py
打开当前包下的 setup.py 文件,在 entry_points 中加入可执行入口。ROS 2 官方 Python 教程要求在 setup.py 中通过 console_scripts 配置入口,这样才能使用 ros2 run 启动节点:
entry_points={
'console_scripts': [
'hello_node = lq_pkg1.node_helloworld:main',
# 格式为:'自定义运行的节点名 = 包名.节点py文件名:入口函数名'
],
},注意上述内容在自己写代码时替换为自己的内容。
编译功能包
返回工作空间根目录,执行:
colcon build编译完成后,加载环境:
source install/setup.bash运行节点
执行以下命令运行节点:
# 命令格式为 ros2 run package_name node_name
ros2 run lq_pkg1 hello_node上述命令表示运行一个节点。
查看节点运行状态
保持这个终端不动,重新打开一个终端,加载环境后输入:
ros2 node list可以看到如下节点名:
还可进一步查看节点信息:
ros2 node info /hello_node