一个符合catkin规范的package.xml文件
一个catkin版本的CMakeLists.txt文件
每个包必须有自己独立的目录,保存各种文件,package.xml和CMakeList.txt保存在根目录下
ROS_package/
CMakeLists.txt
package.xml
一个简单的catkin工作空间
catkin_workspace/ 工作空间
src/ 源码
CMakeLists.txt 顶层CMake文件,由cmake产生
ROS_package_1/ 第一个ROS包
CMakeLists.txt
package.xml
ROS_package_2/ 第二个ROS包
CMakeLists.txt
package.xml
首先切换到catkin工作空间中源文件空间目录
cd ~/catkin_ws/src
使用catkin_create_pkg命令创建一个名为beginner_tutorials的新ROS软件包,这个软件包依赖于std_msgs、roscpp、rospy
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
产生一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,这两个文件都已经部分填写了执行catkin_create_pkg命令时提供的信息。
构建软件包
cd ~/catkin_ws
catkin_make
在devel子目录下创建了一个通常在/opt/ros/kinetic/下看到的目录结构类似的结构
将这个工作空间添加到ROS环境中,通常需要source一下生成的配置文件
source ~/catkin_ws/devel/setup.bash
一级依赖
在catkin_create_pkg时提供了几个软件包作为依赖关系,可以使用rospack命令工具来查找这些一级依赖包
rospack depends1 beginner_tutorials
# 如下列出了在运行catkin_create_pkg命令时作为参数的依赖包,这些依赖关系存储在package.xml中
std_msgs
rospy
roscpp
间接依赖
一个依赖包还会有它自己的依赖关系,比如rospy就有其他依赖包
rospack depends1 rospy
# 以下列出rospy的依赖包
genpy
roscpp
rosgraph
rosgraph_msgs
roslib
std_msgs
自定义package.xml
剖析一下自动生成的package.xml文件
大体上,package.xml文件分为两个部分
描述标签
description
标签:
<description>The beginner_tutorials packagedescription>
可以将描述信息修改为任何你喜欢的内容,但是按照惯例,第一句话应该简短一些,因为它包含了软件包的范围。
维护者标签
maintainer
标签:
<maintainer email="[email protected]">usermaintainer>
这是package.xml文件要求填写的一个重要标签,它能够让其他人联系到软件包的相关人员。
许可证标签
license
标签:
<license>TODOlicense>
选择一个开源许可证填写到这里。常见的开源许可证:BSD、MIT、Boost Software License、GPLv2、GPLv3、LGPLv2.1和LGPLv3。
依赖项目标签
描述了依赖关系,这些依赖项分别为:build_depend、
buildtool_depend、
run_depend、
test_depend
除了catkin默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签中。
<buildtool_depend>catkinbuildtool_depend>
<build_depend>roscppbuild_depend>
<build_depend>rospybuild_depend>
<build_depend>std_msgsbuild_depend>
<build_export_depend>roscppbuild_export_depend>
<build_export_depend>rospybuild_export_depend>
<build_export_depend>std_msgsbuild_export_depend>
<exec_depend>roscppexec_depend>
<exec_depend>rospyexec_depend>
<exec_depend>std_msgsexec_depend>
最终的package.xml
<package format="2">
<name>beginner_tutorialsname>
<version>0.1.0version>
<description>The beginner_tutorials packagedescription>
<maintainer email="[email protected]">Your Namemaintainer>
<license>BSDlicense>
<url type="website">http://wiki.ros.org/beginner_tutorialsurl>
<author email="[email protected]">Jane Doeauthor>
<buildtool_depend>catkinbuildtool_depend>
<build_depend>roscppbuild_depend>
<build_depend>rospybuild_depend>
<build_depend>std_msgsbuild_depend>
<build_export_depend>roscppbuild_export_depend>
<build_export_depend>rospybuild_export_depend>
<build_export_depend>std_msgsbuild_export_depend>
<exec_depend>roscppexec_depend>
<exec_depend>rospyexec_depend>
<exec_depend>std_msgsexec_depend>
package>
自定义CMakeLists.txt
CMakeList.txt是CMake编译系统下用于描述代码的编译规则的文件,通过一系列的指令就可以完成一个项目的编译和安装,在ROS的catkin_make编译环境下,对cmake的这一工作流程做了很多封装
在使用catkin_make编译时,需要先确保系统中已经安装了package的所有依赖,否则编译过程中将因为没有找到相应的依赖而报错退出,还需要保证已经导入了ROS工作环境
这些文件描述了如何构建代码以及将代码安装到何处
编写CMakeList.txt最常用的功能就是调用其他的.h头文件和.so/.a库文件,将.cpp/.c/.cc文件编译成可执行文件或者新的库文件
整体结构和排序
CMakeLists.txt文件必须遵循固定格式,顺序很重要:
CMake版本
每个CMakeLists.txt文件都必须以所需的CMake版本开头,catkin需要2.8.3或者更高版本的CMake
cmake_minimum_required(VERSION 2.8.3)
包名
由CMake项目函数指定的包的名称,我以自己做的项目为例
project(visual)
会自动创建两个变量,PROJECT_SOURCE_DIR和PROJECT_NAME
查找构建所需的其他CMake/catkin包
使用find_package()函数指定需要找到哪些CMake/catkin包来构建我的项目,总是至少依赖一种对catkin的依赖
find_package(
catkin REQUIRED COMPONENTS
roscpp
rospy
sensor_msgs
std_msgs
tf
cotek_msgs
cv_bridge REQUIRED
geometry_msgs REQUIRED
image_geometry REQUIRED
image_transport REQUIRED
cotek_common
pluginlib
cotek_localizer
tf
message_generation
)
find_package()有什么作用?
如果CMake通过find_package()找到一个包,则会导致创建多个CMake环境变量,提供有关找到的包的信息,这些环境变量可以在稍后的CMake脚本中使用,环境变量描述了包导出头文件的位置、源文件的位置、包依赖的库以及这些库的路径。
名称规定:_
_FOUND #如果找到库,则设置为true,否则为false
_INCLUDE_DIRS 或 _INCLUDES #包导出的包含路径
_LIBRARIES 或 _LIBS #包导出的库
_DEFINITIONS
为什么catkin包被指定为组件?
catkin包并不是catin组件
使用catkin前缀创建了一组环境变量
假设代码中使用了nodelet包,查找包的方式是:
find_package(catkin REQUIRED COMPONENTS nodelet)
#这意味着 nodelet 导出的包含路径、库等也附加到 catkin_ 变量。例如,catkin_INCLUDE_DIRS 不仅包含 catkin 的包含路径,还包含 nodelet 的包含路径!这将在以后派上用场。
自行find_package nodelet:
find_package(nodelet)
#这意味着不会将nodelet路径、库等添加到catkin_变量中
boost
如果使用C++和boost,需要在 Boost 上调用 find_package() 并指定您使用 Boost 的哪些方面作为组件。 例如,如果你想使用 Boost 线程
find_package(Boost REQUIRED COMPONENTS thread)
指定包构建信息导出:catkin_package()
catkin_package()是catkin提供的CMake宏。这是为构建系统指定特定于catkin的信息所必须的,该信息又用于生成pkgconfig()和CMake文件
必须在使用add_library()
或add_executable()
声明任何目标之前调用此函数,该函数有5个可选参数
catkin
CMake 项目catkin_package(
INCLUDE_DIRS include
LIBRARIES visual
CATKIN_DEPENDS
roscpp
rospy
sensor_msgs
std_msgs
cotek_msgs
cv_bridge
geometry_msgs
image_transport
message_runtime
pluginlib
tf
DEPENDS
OpenCV
apriltag
)
这表示包文件夹中的文件夹include是导出的头文件所在的位置,库名为visual,CATKIN_DEPENDS下的是构建/运行这个包需要存在的包,DEPENDS下面是构建/运行这个包需要存在的系统依赖项
构建目标
构建目标可以采用多种形式,通常有多种
目标名:
需要注意的是,无论构建/安装到哪个文件夹,catkin 中构建目标的名称都必须是唯一的。 这是 CMake 的要求。 但是,目标的唯一名称仅在 CMake 内部是必需的。 可以使用 set_target_properties() 函数将目标重命名为其他目标:
set_target_properties(rviz_image_view
PROPERTIES OUTPUT_NAME image_view
PREFIX "")
这将在构建和安装输出中将目标 rviz_image_view 的名称更改为 image_view。
自定义输出目录:
可执行文件和库的默认输出目录通常设置为合理的值,但在某些情况下必须对其进行自定义。
set_target_properties(python_module_library
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})
Include路径和Library路径:
在指定目标之前,您需要指定可以在何处找到这些目标的资源,特别是头文件和库:
include_directories 的参数应该是由 find_package 调用生成的 *_INCLUDE_DIRS 变量以及需要包含的任何其他目录
规定.h头文件路径
include_directories(
include
include/visual
include/node
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${realsense2_INCLUDE_DIRS}
${apriltag_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIRS}
)
CMake link_directories() 函数可用于添加额外的库路径,但不建议这样做。 所有 catkin 和 CMake 包在 find_packaged 时都会自动添加链接信息。 只需链接到 target_link_libraries() 中的库
规定.so/.a库文件路径
link_directories(${apriltag_LIBDIR})
生成可执行目标:
要指定一个必须构建的可执行目标,必须使用add executable() CMake函数
将.cpp/.c/.cc文件生成可执行文件
add_executable(${PROJECT_NAME}_node src/visual_node.cc)
生成库目标:
add_library() CMake 函数用于指定要构建的库。 默认情况下,catkin 构建共享库
将.cpp/.c/.cc文件生成.a静态库,库文件名通常为libxxx.so,这里只要写xxx即可
add_library(${PROJECT_NAME}
src/d435_driver.cc
src/convert_image.cc
src/visual_calibration.cc
src/pedestrian_detect_driver.cc
src/device_manager.cc
src/pallet_avoid.cc
src/config_helper.cc
src/d435i_imu.cc
src/apriltag_common_functions.cc
src/apriltag_detector.cc
)
目标链接库:
使用 target_link_libraries() 函数指定可执行目标链接到哪些库。 这通常在 add_executable() 调用之后完成
对add_library或者add_executable生成的库文件或者可执行文件进行链接操作
#可执行文件进行链接
target_link_libraries(${PROJECT_NAME}_node
${OpenCV_LIBS}
${PROJECT_NAME}
${catkin_LIBRARIES}
${realsense2_LIBRARY}
${apriltag_LIBRARIES}
${YAML_CPP_LIBRARIES}
-lpthread
-lm
)
#库文件进行链接
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} )
消息、服务、动作:
ROS 中的消息 (.msg)、服务 (.srv) 和动作 (.action) 文件在被 ROS 包构建和使用之前需要一个特殊的预处理器构建步骤。 这些宏的目的是生成特定于编程语言的文件,以便人们可以使用他们选择的编程语言中的消息、服务和操作。 构建系统将使用所有可用的生成器(例如 gencpp、genpy、genlisp 等)生成绑定。
提供了三个宏分别处理消息、服务和动作:
add_message_files
add_service_files
add_action_files
启用 Python 模块支持:
ROS 包提供了一些 Python 模块
catkin_python_setup()
在调用 generate_messages() 和 catkin_package() 之前
单元测试:
有一个特定于 catkin 的宏用于处理基于 gtest 的单元测试,称为 catkin_add_gtest()。
catkin_python_setup()
在调用 generate_messages() 和 catkin_package() 之前
可选步骤:指定可安装目标
在构建时间之后,目标被放置到 catkin 工作区的开发空间中。 但是,通常我们希望将目标安装到系统(比如说我要把包安装在/opt/ros/kinetic/目录下),以便其他人可以使用它们或安装到本地文件夹以测试系统级安装。 换句话说,如果您希望能够对您的代码进行“make install”,您需要指定目标应该在哪里结束。
这是使用 CMake install() 函数完成的,该函数将参数作为参数:
TARGETS #要安装哪些目标
ARCHIVE DESTINATION #静态库和 DLL (Windows) .lib 存根
LIBRARY DESTINATION #非 DLL 共享库和模块
RUNTIME DESTINATION #可执行目标和 DLL (Windows) 风格的共享库
#标记可执行文件和/或库以供安装
install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
#标记cpp头文件进行安装
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
PATTERN ".git" EXCLUDE
)
#安装配置文件
install(FILES
config/settings.yaml
config/tags.yaml
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config
)
#安装 roslaunch 文件或其他资源
install(FILES
launch/visual.launch
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)