前言
本系列文章是由笔者翻译自ROS 2 官方教程。笔者水平有限,如有错误,还请读者指正。
本节教程中部分代码为 Liunx下,请使用其他操作系统的读者前往原文查看。
本节教程同时列出 Cmake 和 Python 代码,读者可任选其一(中途不可更换)。
背景
1 What is a ROS 2 package? (什么是 ROS 2 包)
Package(包)是你的 ROS 2 代码的一种组织形式。如果你想安装你的代码或是与他人分享,那么你就会需要使用包的形式来组织代码。有了包,你可以发布你的 ROS 2 作品并允许他人便利地构建以及使用它们。
在 ROS 2 中创建包需要使用ament作为构建系统,colcon作为构建工具。你可以使用Cmake或是Python来创建包,尽管其他工具存在,他们任受官方支持。
2 What makes up a ROS 2 package? (什么构成了 ROS 2 包)
ROS 2 Python和Cmake包有他们各自的最小构成:
Cmake | Python |
---|---|
CMakeLists.txt 文件描述如何在包中构建代码 | package.xml 文件存放包的元信息 |
include/<package_name> 目录存放包的公共头文件 | resource/<package_name> 标记包中的文件 |
package.xml 文件存放包的元信息 | setup.cfg 在包有可执行文件时候被需要,通过此文件ros2 run 可以找到它们 |
src 目录存放包的源代码 | setup.py 包含如何安装此包的说明 |
<package_name> 是与包名相同的目录,被 ROS 2 工具用来寻找包,包含_init_.py |
最简单的包可能有如下的文件结构:
Cmake:
my_package/
CMakeLists.txt
include/my_package/
package.xml
src/
Python:
my_package/
package.xml
resource/my_package
setup.cfg
setup.py
my_package/
3 Packages in a workspace (工作空间中的包)
一个工作空间可以包含任意数量的包,每一个在它们自己的文件夹中。一个工作空间中也可以有不同构建类型的包(Cmake,Python 等等)。包不可以被嵌套。
较好的应用实例是在你的工作空间内创建src
文件夹,然后在此创建你的包。这保持工作空间根目录“干净”的状态。
一个普通工作区可能如下所示:
workspace_folder/
src/
cpp_package_1/
CMakeLists.txt
include/cpp_package_1/
package.xml
src/
py_package_1/
package.xml
resource/py_package_1
setup.cfg
setup.py
py_package_1/
...
cpp_package_n/
CMakeLists.txt
include/cpp_package_n/
package.xml
src/
先决条件
你应该在跟随上节教程后有了一个 ROS 2 工作空间,你将会在工作空间中创建包。
任务
1 Create a package (创建一个包)
首先,添加你的 ROS 2 安装。
让我们使用上一节教程中创建的工作空间,ros2_ws
,来创建包。
在你运行创建包命令前,确保你在src
文件夹中。
cd ~/ros2_ws/src
在 ROS 2 中创建新包的命令结构是:
Cmake:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 <package_name>
Python:
ros2 pkg create --build-type ament_python --license Apache-2.0 <package_name>
在本节教程中,你将会使用可选参数--node-name
和--license
。--node-name
选项在包中创建一个简单的Hello World类型可执行文件,--license
申明包的许可证信息。
在终端中输入如下命令:
Cmake:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 --node-name my_node my_package
Python:
ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name my_node my_package
在工作空间的src
目录下将会有一个新文件夹叫做my_package
。
在运行命令后,终端将会返回:
Cmake:
going to create a new package
package name: my_package
destination directory: /home/user/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['<name> <email>']
licenses: ['Apache-2.0']
build type: ament_cmake
dependencies: []
node_name: my_node
creating folder ./my_package
creating ./my_package/package.xml
creating source and include folder
creating folder ./my_package/src
creating folder ./my_package/include/my_package
creating ./my_package/CMakeLists.txt
creating ./my_package/src/my_node.cpp
Python:
going to create a new package
package name: my_package
destination directory: /home/user/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['<name> <email>']
licenses: ['Apache-2.0']
build type: ament_python
dependencies: []
node_name: my_node
creating folder ./my_package
creating ./my_package/package.xml
creating source folder
creating folder ./my_package/my_package
creating ./my_package/setup.py
creating ./my_package/setup.cfg
creating folder ./my_package/resource
creating ./my_package/resource/my_package
creating ./my_package/my_package/__init__.py
creating folder ./my_package/test
creating ./my_package/test/test_copyright.py
creating ./my_package/test/test_flake8.py
creating ./my_package/test/test_pep257.py
creating ./my_package/my_package/my_node.py
你可以看到包中自动生成的文件。
2 Build a package (构建一个包)
将包放入工作空间中是十分有用的,因为你通过在工作空间根目录中运行colcon build
来一次构建多个包。不然的话,你将会需要单独构建每个包。
回到工作空间根目录:
cd ~/ros2_ws
现在,你可以构建你的包:
colcon build
回忆一下,在上节教程中,你在ros2_ws
中也存放了ros_tutorials
包。你可能已经注意到,运行colcon build
也构建了turtlesim
包。当你的工作空间中仅仅只有少数包时是无伤大雅的,但当其中有许多包是,colcon build
可能会花很长时间。
为了在下次仅仅构建my_package
包,你可以运行:
colcon build --packages-select my_package
3 Source the setup file (添加启动文件)
为了使用你的新包和其中的可执行文件,首先打开一个新终端并添加你的主 ROS 2 安装。
然后,在ros2_ws
目录中,运行如下命令来添加你的工作空间:
source install/local_setup.bash
现在,你的工作空间被加入你的path,你将可以使用新包中的可执行文件。
4 Use the package (使用包)
为了运行你在创建包时使用--node-name
参数创建的可执行文件,云心如下命令:
ros2 run my_package my_node
终端将会返回:
Cmake:
hello world my_package package
Python:
Hi from my_package.
5 Examine package contents (检查包内容)
在ros2_ws/src/my_package
下,你将会看到由ros2 pkg create
自动创建的文件和文件夹:
Cmake:
CMakeLists.txt include package.xml src
my_node.cpp
在src
目录下,该目录也是存放你的未来C++节点的位置。
Python:
my_package package.xml resource setup.cfg setup.py test
my_node.py
在src
目录下,该目录也是存放你的未来Python节点的位置。
6 Customize package.xml (修改 package.xml)
你可能注意到在创建包返回的消息中的description
和license
字段含有TODO
标注。这是因为包的描述和许可证申明并不会被自动设置,但在你发布包的时候被需要。maintiner
字段也需要被填写。
在ros2_ws/src/my_package
中,使用你喜爱的文本编辑器打开package.xml
:
Cmake:
<?xml version="1.0"?>
<?xml-model
href="http://download.ros.org/schema/package_format3.xsd"
schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>my_package</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="user@todo.todo">user</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Python:
<?xml version="1.0"?>
<?xml-model
href="http://download.ros.org/schema/package_format3.xsd"
schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>my_package</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="user@todo.todo">user</maintainer>
<license>TODO: License declaration</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
在maintainer
行输入你的姓名和email如果此行没有自动填充。随后,编辑description
行来为包填写摘要:
<description>Beginner client libraries tutorials practice package</description>
随后,更新license
行,你可以 在此 阅读更多开源协议。既然这个包是用于练手,使用任何协议都可。我们将会使用Apache License 2.0
:
<license>Apache License 2.0</license>
不要忘记在完成编辑之后立即保存。
在license
标签下,你将会看到一些以_depend
结尾的标签。这里是你的package.xml
列出它的依赖的地方,让colcon
来搜寻。my_package
是简单,并不需要任何依赖,但你将会在后续教程中看到这部分的使用。
Python:
setup.py
也含有与package.xml
相同的description
,maintainer
和license
字段,所以你也需要同时设置它们。它们在两个文件中需要完全匹配,version
和name
也需要被完全匹配,在两个文件中,它们是被自动填充的。
使用你喜欢的文本编辑器打开setup.py
:
from setuptools import find_packages, setup
package_name = 'my_py_pkg'
setup(
name=package_name,
version='0.0.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='TODO',
maintainer_email='TODO',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'my_node = my_py_pkg.my_node:main'
],
},
)
编辑maintainer
,maintainer_email
和description
行来与package.xml
匹配,最后不要忘记保存。
总结
我们已经创建了一个包来组织我们的代码,并使其易于其他人使用。
包自动填充了必要的文件,然后我们使用 colcon 构建它,以便我们可以在本地环境中使用其可执行文件。