Skip to content

ROS 2 包的Python开发与构建基础

创建Workspace

类似于 ROS2 文件安装在 /opt/ros/{ROS_DISTRO} 中以便我们可以同时安装多个发行版的方式,我们也可以在系统中拥有许多单独的工作区(workspace)。在 ROS2 中,工作区只不过是一个包含所有包的文件夹。

我们只需要创建一个文件夹,例如我们将在这些教程中使用的文件夹。

zsh
cd ~
mkdir -p ros2_tutorial_workspace/src

通常的做法是将所有源文件都放在 src 文件夹中,因此对于这些教程,我们也会这样做——尽管这并不是一个严格的要求。

无论它当前是否是一个空的项目,我们都会运行一次 colcon 来设置环境并说明一些事情。(程序 colcon 是 ROS2 的构建系统,稍后将更详细地描述。)

zsh
cd ~/ros2_tutorial_workspace
colcon build

上述命令的输出将类似于:

zsh
Summary: 0 packages finished [0.09s]

由于我们的工作区中没有包,因此 colcon 什么也没有构建,这是正常的。

文件夹 buildinstalllog 已由 colcon 自动生成。项目结构如下所示:

zsh
~/ros2_tutorial_workspace/ 
└── src/ 
└── build/ 
└── install/ 
└── log/

install文件夹内包含项目生成的所有程序等,用户可以访问。

我们需要通过source命令加载工作区的环境变量,以便我们可以使用工作区中的程序。

zsh
source ~/ros2_tutorial_workspace/install/setup.zsh

目前,由于我们的工作区目前是空的,因此我们不能对它做太多事情。让我们添加一些内容。

创建ROS2包的脚手架命令

ROS2 有一个工具可以帮助创建包模板。我们可以通过运行:

zsh
ros2 pkg create -h

上述命令将显示所有可用选项。我们一般重点关注四个命令选项及其使用方法:

zsh
 --build-type {cmake,ament_cmake,ament_python}
 --dependencies DEPENDENCIES [DEPENDENCIES ...]
 --node-name NODE_NAME
 --library-name LIBRARY_NAME

创建ROS2的Python包

ROS2 中的包可以依赖 CMake 或直接使用 Python 中提供的设置工具。对于纯 Python 项目,使用 ament_python 可能更容易,因此我们从它开始本教程。

让我们构建最简单的 Python 包并从那里开始。

zsh
cd ~/ros2_tutorial_workspace/src
ros2 pkg create the_simplest_python_package \
--build-type ament_python

这将导致以下输出,表示包已成功生成:

zsh
going to create a new package
package name: the_simplest_python_package
destination directory: /home/kyle/ros2_tutorial_workspace/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['kyle <s***********[email protected]>']
licenses: ['TODO: License declaration']
build type: ament_python
dependencies: []
creating folder ./the_simplest_python_package
creating ./the_simplest_python_package/package.xml
creating source folder
creating folder ./the_simplest_python_package/the_simplest_python_package
creating ./the_simplest_python_package/setup.py
creating ./the_simplest_python_package/setup.cfg
creating folder ./the_simplest_python_package/resource
creating ./the_simplest_python_package/resource/the_simplest_python_package
creating ./the_simplest_python_package/the_simplest_python_package/__init__.py
creating folder ./the_simplest_python_package/test
creating ./the_simplest_python_package/test/test_copyright.py
creating ./the_simplest_python_package/test/test_flake8.py
creating ./the_simplest_python_package/test/test_pep257.py

[WARNING]: Unknown license 'TODO: License declaration'.  This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identifiers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0

我们可以使用 colcon 构建现在包含此空包的工作空间:

zsh
cd ~/ros2_tutorial_workspace
colcon build

这将现在输出:

zsh
Starting >>> the_simplest_python_package
Finished <<< the_simplest_python_package [1.55s]          

Summary: 1 package finished [1.68s]

这意味着 colcon 成功构建了包the_simplest_python_package

利用模板创建Python 节点

注意:我们依然是基于 ament_python 脚手架工具进行构建。

始终依赖ros2 pkg create中提供的模板是一个好习惯,主要是因为打包的最佳实践可能会在 ROS2 版本之间发生变化。

让我们使用模板创建一个包含节点的包,如下所示:

zsh
cd ~/ros2_tutorial_workspace/src
ros2 pkg create python_package_with_a_node \
--build-type ament_python \
--node-name sample_python_node

这将输出与之前示例中许多相同的内容,但有两个主要区别:

  1. 它生成一个 Node 模板,而不是一个空包。
  2. setup.py 包含了有关节点的信息。
zsh
going to create a new package
package name: python_package_with_a_node
destination directory: /home/kyle/ros2_tutorial_workspace/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['kyle <[email protected]>']
licenses: ['TODO: License declaration']
build type: ament_python
dependencies: []
node_name: sample_python_node
creating folder ./python_package_with_a_node
creating ./python_package_with_a_node/package.xml
creating source folder
creating folder ./python_package_with_a_node/python_package_with_a_node
creating ./python_package_with_a_node/setup.py
creating ./python_package_with_a_node/setup.cfg
creating folder ./python_package_with_a_node/resource
creating ./python_package_with_a_node/resource/python_package_with_a_node
creating ./python_package_with_a_node/python_package_with_a_node/__init__.py
creating folder ./python_package_with_a_node/test
creating ./python_package_with_a_node/test/test_copyright.py
creating ./python_package_with_a_node/test/test_flake8.py
creating ./python_package_with_a_node/test/test_pep257.py
creating ./python_package_with_a_node/python_package_with_a_node/sample_python_node.py

[WARNING]: Unknown license 'TODO: License declaration'.  This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identifiers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0

然后,我们可以像往常一样构建工作空间,以便也将新包考虑在内。

zsh
cd ~/ros2_tutorial_workspace
colcon build

上述命令将使我们遍历在前一个示例和当前示例中创建的包,并构建它们。输出应该类似于:

zsh
Starting >>> python_package_with_a_node
Starting >>> the_simplest_python_package
Finished <<< python_package_with_a_node [1.59s]                                                           
Finished <<< the_simplest_python_package [1.68s]          

Summary: 2 packages finished [1.83s]

当我们利用colcon build命令构建工作空间后,我们需要使用source命令加载工作空间的环境变量,以便我们可以使用工作空间中的程序。

思考:如果我们不用source命令加载工作空间的环境变量,我们将无法使用工作空间中的程序。这是因为我们的 shell 不知道工作空间中的程序在哪里。 尝试在没有运行source命令的情况下运行如下命令:

zsh
ros2 run python_package_with_a_node sample_python_node

看看会发生什么?

Tips: 所以我们最好每次运行完colcon build命令后,都要运行source命令。

zsh
cd ~/ros2_tutorial_workspace
source install/setup.zsh

然后,我们可以通过以下命令执行示例节点和包功能:

zsh
ros2 run python_package_with_a_node sample_python_node

现在将正确输出:

zsh
Hi from python_package_with_a_node.

总结

  1. 在本节中,我们学习了如何创建一个 ROS2 工作空间。
  2. 我们学习了如何使用 ros2 pkg create 命令创建一个空的 Python 包。
  3. 我们学习了如何使用 ros2 pkg create 命令创建一个包含节点的 Python 包。
  4. 我们学习了如何构建工作空间并使用source命令加载工作空间的环境变量。
  5. 我们学习了如何运行包中的节点。(课程回顾:请回到课程ROS2的基石:节点Node, 比较与本节内容的异同)

课后作业

  1. 总结通过ament_python创建包的步骤和流程;
  2. 并观察执行完主要步骤之后,文件夹发生了哪些变化。
  3. 解谜:程序输出Hi from python_package_with_a_node.,请找到这个输出的源代码在哪个文件。

作业执行人: 所有同学。

友情提示

  1. 本节的课后作业每个同学都要做。
  2. 因为下节课我们要开始动手裸写Python代码。
  3. 没有本次课后作业的经验,下节课你会感觉很酸爽。