文章目录
1.一个catkin程序包由什么组成?
一个程序包要想称为catkin程序包必须符合以下要求:
该程序包必须包含 catkin compliant package.xml文件
这个package.xml文件提供有关程序包的元信息。
程序包必须包含一个catkin 版本的CMakeLists.txt文件,而Catkin metapackages中必须包含一个对CMakeList.txt文件的引用。
每个目录下只能有一个程序包。
这意味着在同一个目录下不能有嵌套的或者多个程序包存在。
最简单的程序包也许看起来就像这样:
my_package/
CMakeLists.txt
package.xml
2.在catkin工作空间中的程序包
开发catkin程序包的一个推荐方法是使用catkin工作空间,但是你也可以单独开发(standalone)catkin 软件包。一个简单的工作空间也许看起来像这样:
workspace_folder/ -- 工作空间
src/ -- 资源空间
CMakeLists.txt -- 由catkin提供的“顶级” CMake文件
package_1/
CMakeLists.txt -- package_1的CMakeLists.txt文件
package.xml -- package_1的软件包清单
...
package_n/
CMakeLists.txt -- package_n的CMakeLists.txt文件
package.xml --package_n的软件包清单
3.创建一个catkin程序包
本部分教程将演示如何使用catkin_create_pkg命令来创建一个新的catkin程序包以及创建之后都能做些什么。
首先切换到之前通过创建catkin工作空间教程创建的catkin工作空间中的src目录下:
cd ~/catkin_ws/src
现在使用catkin_create_pkg命令来创建一个名为’beginner_tutorials’的新程序包,这个程序包依赖于std_msgs、roscpp和rospy:
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
这将会创建一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,这两个文件都已经自动包含了部分你在执行catkin_create_pkg命令时提供的信息。
catkin_create_pkg命令会要求你输入package_name,如果有需要你还可以在后面添加一些需要依赖的其它程序包:
catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
4.程序包依赖关系
4.1一级依赖
之前在使用catkin_create_pkg命令时提供了几个程序包作为依赖包,现在我们可以使用rospack命令工具来查看一级依赖包。
rospack depends1 beginner_tutorials
结果像这样:
std_msgs
rospy
roscpp
就像你看到的,rospack列出了在运行catkin_create_pkg命令时作为参数的依赖包,这些依赖包随后保存在package.xml文件中。
roscd beginner_tutorials
cat package.xml
结果像这样:
<package>
...
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
...
</package>
4.2间接依赖
在很多情况中,一个依赖包还会有它自己的依赖包,比如,rospy还有其它依赖包。
rospack depends1 rospy
结果像这样:
genpy
rosgraph
rosgraph_msgs
roslib
std_msgs
一个程序包还可以有好几个间接的依赖包,幸运的是使用rospack可以递归检测出所有的依赖包。
rospack depends beginner_tutorials
结果像这样:
cpp_common
rostime
roscpp_traits
roscpp_serialization
genmsg
genpy
message_runtime
rosconsole
std_msgs
rosgraph_msgs
xmlrpcpp
roscpp
rosgraph
catkin
rospack
roslib
rospy
5.自定义你的程序包
本部分教程将剖析catkin_create_pkg命令生成的每个文件并详细描述这些文件的组成部分以及如何自定义这些文件。
5.1自定义 package.xml
自动生成的package.xml文件应该在你的新程序包中。现在让我们一起来看看新生成的package.xml文件以及每一个需要你注意的标签元素。
5.1.1描述标签
首先更新描述标签:
<description>beginner_tutorials软件包</description>
将描述信息修改为任何你喜欢的内容,但是按照约定第一句话应该简短一些,因为它覆盖了程序包的范围。如果用一句话难以描述完全那就需要换行了。
5.1.2维护者标签
接下来是维护者标签:
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
<maintainer email="[email protected]">user</maintainer>
这是package.xml中要求填写的一个重要标签,因为它能够让其他人联系到程序包的相关人员。至少需要填写一个维护者名称,但如果有需要的话你可以添加多个。除了在标签里面填写维护者的名称外,还应该在标签的email属性中填写邮箱地址:
<maintainer email="[email protected]">Your Name</maintainer>
5.1.3许可标签
再接下来是许可标签,同样的也需要:
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>TODO</license>
你应该选择一种许可协议并将它填写到这里。一些常见的开源许可协议有BSD、MIT、Boost Software License、GPLv2、GPLv3、LGPLv2.1和LGPLv3。你可以在Open Source Initiative中阅读其中的若干个许可协议的相关信息。对于本教程我们将使用BSD协议,因为ROS核心组件的剩余部分已经使用了该协议:
<license>BSD</license>
5.1.4依赖项标签
接下来的标签用来描述程序包的各种依赖项,这些依赖项分为build_depend、buildtool_depend、run_depend、test_depend。在之前的操作中,因为我们将 std_msgs、 roscpp、 和 rospy作为catkin_create_pkg命令的参数,所以生成的依赖项看起来如下:
<!-- The *_depend tags are used to specify dependencies -->
<!-- Dependencies can be catkin packages or system dependencies -->
<!-- Examples: -->
<!-- Use build_depend for packages you need at compile time: -->
<!-- <build_depend>genmsg</build_depend> -->
<!-- Use buildtool_depend for build tool packages: -->
<!-- <buildtool_depend>catkin</buildtool_depend> -->
<!-- Use exec_depend for packages you need at runtime: -->
<!-- <exec_depend>python-yaml</exec_depend> -->
<!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> -->
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
除了catkin中默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签中。在本例中,因为在编译和运行时我们需要用到所有指定的依赖包,因此还需要将每一个依赖包分别添加到run_depend标签有些为build_depend标签中:
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
5.1.5最后完成的 package.xml
现在看下面最后去掉了注释和未使用标签后的package.xml文件就显得更加简洁了:
<?xml version="1.0"?>
<package format="2">
<name>beginner_tutorials</name>
<version>0.1.0</version>
<description>The beginner_tutorials package</description>
<maintainer email="[email protected]">Your Name</maintainer>
<license>BSD</license>
<url type="website">http://wiki.ros.org/beginner_tutorials</url>
<author email="[email protected]">Jane Doe</author>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
</package>
文件CMakeLists.txt是CMake构建系统的输入,用于构建软件包。任何兼容CMake的软件包都包含一个或多个CMakeLists.txt文件,这些文件描述了如何构建代码以及将代码安装到何处。用于柳絮项目的CMakeLists.txt文件是标准的香草CMakeLists.txt文件,带有一些其他约束。
5.2自定义 CMakeLists.txt
5.2.1概述
文件CMakeLists.txt是CMake构建系统的输入,用于构建软件包。任何符合CMake的包都包含一个或多个CMakeLists.txt文件,该文件描述如何构建代码以及将代码安装到何处。catkin项目使用的CMakeLists.txt文件是一个标准的vanilla CMakeLists.txt文件,带有一些附加约束。
5.2.2总体结果及其排序
您的CMakeLists.txt文件必须遵循此格式,否则您的包将无法正确生成。
配置中的顺序确实有效。
- 必需的CMake版本(CMake_minimum_Required)
- 包名称(project())
- 查找生成所需的其他CMake/Catkin包(Find_Package())
- 启用Python模块支持(Catkin_Python_setup())
- 消息/服务/操作生成器(add_Message_files(),add_Service_files(),add_action_files())
- 调用消息/service/action generation(generate_messages())
- 指定要生成的包生成信息导出(catkin_package())
- 库/可执行文件(add_library()/add_executable()/target_link_Libraries())
- 要生成的测试(catkin_add_gtest())
- 安装规则(Install())
5.2.3CMake版本
每个catkin CMakeLists.txt文件必须以所需的CMake版本开始。Catkin需要2.8.3或更高版本。
cmake_minimum_required(VERSION 2.8.3)
5.2.4包名
下一项是由CMake项目函数指定的包的名称。假设我们正在制作一个名为“机器人大脑”的软件包。
project(robot_brain)
注意在CMake中,您可以在以后的CMake脚本中的任何地方引用项目名称,方法是在需要时使用变量${project_name}。
5.2.5查找依赖的CMake包
然后,我们需要指定使用CMake find_package函数构建项目时需要找到的其他CMake包。
始终至少有一个依赖于catkin:
find_package(catkin REQUIRED)
如果您的项目依赖于其他包,则它们会自动转换为catkin的组件(就CMake而言)。如果将这些包指定为组件,则不会在这些包上使用find_pack,这将使生活更轻松。例如,如果使用包nodelet。
find_package(catkin REQUIRED)
find_package(nodelet REQUIRED)
但是,你会发现这是一种不方便的做事方式。
5.2.6find_package()能做什么?
如果CMake通过find_package找到一个包,则会创建几个CMake环境变量,这些变量提供有关找到的包的信息。这些环境变量可以在稍后的CMake脚本中使用。环境变量描述包导出头文件的位置、源文件的位置、包所依赖的库以及这些库的路径。名称始终遵循< PACKAGE NAME >的约定:
<NAME>_FOUND - 如果找到库,则设置为true,否则为false
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES - 包导出的包含路径
<NAME>_LIBRARIES or <NAME>_LIBS - 包导出的库
<NAME>_DEFINITIONS - ?
5.2.7为什么Catkin包被指定为组件?
Catkin包装并不是Catkin的真正组成部分。更确切地说,在catkin的设计中使用了CMake的components特性,以节省大量的输入时间。对于catkin包,如果您发现将它们打包为catkin的components,这是非常有利的,因为使用catkin前缀创建了一组环境变量。例如,假设您在代码中使用了包nodelet。查找包的推荐方法是:
find_package(catkin REQUIRED COMPONENTS nodelet)
这意味着nodelet导出的include路径、库等也被附加到 catkin_ variables中。例如,catkin_INCLUDE_DIRS不仅包含catkin的INCLUDE路径,还包含nodelet的INCLUDE路径!这将在以后派上用场。
我们也可以自己find_package nodelet:
find_package(nodelet)
这意味着nodelet路径、库等不会添加到catkin_ variables中,这会导致 nodelet_INCLUDE_DIRS, nodelet_LIBRARIES, 等。同样的变量也是使用
find_package(catkin REQUIRED COMPONENTS nodelet)
5.2.8 Boost
如果使用C++和Boost,则需要调用Booost上的FundPulkAuthor(),并指定您使用的Boost的哪些方面作为组件。
例如,如果您想使用Boost线程,您可以说:
find_package(Boost REQUIRED COMPONENTS thread)
5.2.9 catkin_package()
catkin_package()是catkin提供的CMake宏。这是为生成系统指定特定于catkin的信息所必需的,而生成系统又用于生成pkg config和CMake文件。在使用add_library()或add_executable()声明任何目标之前,必须调用此函数。该函数有5个可选参数:
- INCLUDE_DIRS-导出包的INCLUDE路径(即cflags)
- LIBRARIES-项目中导出的库
- CATKIN_DEPENDS-此项目所依赖的其他CATKIN项目
- DEPENDS-此项目依赖的非catkin CMake项目。
- CFG_EXTRAS-附加配置选项
列如:
catkin_package(
INCLUDE_DIRS include
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS roscpp nodelet
DEPENDS eigen opencv)
这表示包文件夹中的文件夹“include”是导出的标题所在的位置。CMake环境变量${PROJECT_NAME}的计算结果与前面传递给PROJECT()函数的结果相同,在本例中,它将是“robot_brain”roscpp“+”nodelet“是生成/运行此包所需的包,“eigen”+”opencv“是生成/运行此包所需的系统依赖项。
5.2.10 指定生成目标
生成目标可以有多种形式,但它们通常表示两种可能之一:
- Executable Target -我们可以运行的程序
- Library Target -可执行目标在生成或运行时使用的库
5.2.11 目标命名
需要注意的是,catkin中构建目标的名称必须是唯一的,而不管它们是构建/安装到哪个文件夹中的。这是CMake的要求。但是,目标的唯一名称仅在CMake内部是必需的。可以使用set_target_properties()函数将目标重命名为其他对象:
列如:
set_target_properties(rviz_image_view
PROPERTIES OUTPUT_NAME image_view
PREFIX "")
这将在生成和安装输出中将目标rviz_image_view的名称更改为image_view。