背景
1. What is a ROS 2 package?
Package是ROS2代码的组织单元。如果你想安装你的代码或与他人共享,那么你需要将其组织在一个package中。有了package,你可以发布您的ROS 2作品,并允许其他人轻松build和使用它。
ROS2中的package使用ament作为其构建系统,colcon作为其构建工具。你也可以使用CMake或Python创建package。
2. What makes up a ROS 2 package?
CMake packages
CMakeLists.txt
描述如何在package中build代码
include/<package_name>
包含package的公共header
package.xml
包含有关package的meta信息
src
包含package的源代码
package的结构如下:
my_package/
CMakeLists.txt
include/my_package/
package.xml
src/
Python packages
package.xml
包含有关package的meta信息
resource/<package_name>
包含package的标记文件
setup.cfg
当一个package有可执行文件时,setup.cfg是必需的,因此ros2 run可以找到它们
setup.py
包含如何安装程序package的说明
<package_name>
一个与您的
package同名的目录,ROS 2工具用来查找你的
package,包含__init__.py
package的结构如下:
my_package/
package.xml
resource/my_package
setup.cfg
setup.py
my_package/
3. Packages in a workspace
一个workspace可以包含任意多个包,每个package都位于各自的文件夹中。你也可以在一个workspace中有不同构建类型的package(CMake、Python等),但不能有嵌套的package。
最好是在workspace中有一个src文件夹,并在其中创建package。这样可以保持workspace的顶层干净整洁。
一般一个Workspace的结构如下:
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/
创建Package
1. Create a package
首先,要source我们ROS2的系统,然后进入src文件夹。
cd ~/ros2_ws/src
创建package的命令:
CMake
ros2 pkg create --build-type ament_cmake <package_name>
Python
ros2 pkg create --build-type ament_python <package_name>
在ROS 2中,ros2 pkg create
命令支持以下一些主要的参数:
--build-type
:指定构建系统类型。可以是ament_cmake
或ament_python
,分别用于C++和Python。例如,--build-type ament_cmake
表示使用C++的Ament CMake构建系统。
--node-name
:指定要创建的ROS节点的名称。例如,--node-name my_node
将创建一个名为 "my_node" 的ROS节点。
--dependencies
:指定软件包的依赖项。可以指定一个或多个依赖项,以逗号分隔。例如,--dependencies rclcpp, std_msgs
表示软件包依赖于RCLCpp和std_msgs。
--license
:指定软件包的许可证类型。可以是Apache-2.0
、BSD-2-Clause
、GPL-2.0
等。例如,--license Apache-2.0
表示使用Apache许可证。
--maintainer
:指定软件包的维护者信息。例如,--maintainer "John Doe <john.doe@example.com>"
。
--description
:指定软件包的简要描述。例如,--description "A ROS 2 package for my project"
。
如果用--node-name来创建一个Hello World的节点:
Cmake
ros2 pkg create --build-type ament_cmake --node-name my_node my_package
Python
ros2 pkg create --build-type ament_python --node-name my_node my_package
现在在src文件夹里就会出现一个my_package文件夹
Terminal里会返回:
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: ['TODO: License declaration']
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: ['TODO: License declaration']
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
将packages放在workspace中是有道理的,因为可以通过在workspace根目录中运行colcon build来同时构建多个包。否则,您将不得不单独构建每个包。
首先要回到根目录,然后运行colcon build:
cd ~/ros2_ws
colcon build
用colcon build会构建workspace中所有的packages,如果有很多packages会花费很长的时间,若要只build特定的package,可以使用--packages-select这个参数。
colcon build --packages-select my_package
3. Source the setup file
要使用您的新package和可执行文件,首先打开一个新的terminal并获取source主要ROS2安装。然后在Workspace的根目录里,source我们的Workspace:
source install/local_setup.bash
4. Use the package
运行在之前创建的node,用如下命令:
ros2 run my_package my_node
5. Examine package contents
现在package里的结构如下:
CMake
CMakeLists.txt include package.xml src
Python
my_package package.xml resource setup.cfg setup.py test
6. Customize package.xml
您可能已经注意到在创建package后的返回消息中,description和license字段包含TODO注释。这是因为程序包描述和许可声明不是自动设置的,但如果您想要发布程序包,则需要它们。可能还需要填写maintainer字段。
打开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>
<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>
将你的名字和邮箱填入到maintainer部分,在description填入包的简介,然后按实际情况填写license部分。
对于Python包来说,setup.py也需要填写这些内容:
from setuptools import setup
package_name = 'my_py_pkg'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
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'
],
},
)