1、一个ROS软件包由什么组成
-
一个符合catkin规范的package.xml文件
- 这个package.xml文件提供有关该软件包的元信息,包括作者信息、版权、依赖
-
一个catkin版本的CMakeLists.txt文件
- 如果ROS软件包是一个catkin元包的话,则需要有一个CMakeLists.txt文件的相关模板,是ROS的编译系统catkin需要使用的文件,描述了package的各种编译规则,需要的源文件、库文件、搜索路径等
-
每个包必须有自己独立的目录,保存各种文件,package.xml和CMakeList.txt保存在根目录下
- 这意味着在同一个目录下不能有嵌套的或者多个软件包存在
ROS_package/ CMakeLists.txt package.xml
2、catkin工作空间中的软件包
一个简单的catkin工作空间
catkin_workspace/ 工作空间
src/ 源码
CMakeLists.txt 顶层CMake文件,由cmake产生
ROS_package_1/ 第一个ROS包
CMakeLists.txt
package.xml
ROS_package_2/ 第二个ROS包
CMakeLists.txt
package.xml
3、创建catkin软件包
-
首先切换到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命令时提供的信息。
4、构建一个catkin工作区并生效配置文件
-
构建软件包
cd ~/catkin_ws catkin_make
在devel子目录下创建了一个通常在/opt/ros/kinetic/下看到的目录结构类似的结构
-
将这个工作空间添加到ROS环境中,通常需要source一下生成的配置文件
source ~/catkin_ws/devel/setup.bash
5、软件依赖关系
-
一级依赖
在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
6、自定义软件包
-
自定义package.xml
剖析一下自动生成的package.xml文件
-
大体上,package.xml文件分为两个部分
- 其中name,version,description等部分就是对package的各种描述,它们对于怎么编译package不起任何作用,就是一些描述信息
- buildtool_depend,build_depend,run_depend部分则描述了package对于其他工具的依赖关系,在编译和运行时,ROS会根据这些描述信息,在系统中查找对应的工具包,如果没有找到将会报错
-
描述标签
description
标签:<description>The beginner_tutorials package</description>
可以将描述信息修改为任何你喜欢的内容,但是按照惯例,第一句话应该简短一些,因为它包含了软件包的范围。
-
维护者标签
maintainer
标签:<!-- One maintainer tag required, multiple allowed, one person per tag --> <!-- Example: --> <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> --> <maintainer email="user@todo.todo">user</maintainer>
这是package.xml文件要求填写的一个重要标签,它能够让其他人联系到软件包的相关人员。
-
许可证标签
license
标签:<!-- 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。
-
依赖项目标签
描述了依赖关系,这些依赖项分别为:build_depend
、
buildtool_depend、
run_depend、
test_depend除了catkin默认提供的buildtool_depend,所有我们列出的依赖包都已经被添加到build_depend标签中。
<buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <build_depend>rospy</build_depend> <build_depend>std_msgs</build_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>rospy</build_export_depend> <build_export_depend>std_msgs</build_export_depend> <exec_depend>roscpp</exec_depend> <exec_depend>rospy</exec_depend> <exec_depend>std_msgs</exec_depend>
-
最终的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="you@yourdomain.tld">Your Name</maintainer> <license>BSD</license> <url type="website">http://wiki.ros.org/beginner_tutorials</url> <author email="you@yourdomain.tld">Jane Doe</author> <buildtool_depend>catkin</buildtool_depend> <build_depend>roscpp</build_depend> <build_depend>rospy</build_depend> <build_depend>std_msgs</build_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>rospy</build_export_depend> <build_export_depend>std_msgs</build_export_depend> <exec_depend>roscpp</exec_depend> <exec_depend>rospy</exec_depend> <exec_depend>std_msgs</exec_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版本:cmake_minimum_required
- 包名:project()
- 查找构建所需的其他CMake/catkin包:find_package()
- 启用python模块支持:catkin_python_setup()
- 消息、服务、动作生成器:add_message_files(), add_service_files(), add_action_files()
- 调用消息、服务、操作生成:generate_messages()
- 指定包构建信息导出:catkin_package()
- 需要构建的库/可执行文件:add_library()/add_executable()/target_link_libraries()
- 要构建的测试:catkin_add_gtest()
- 安装规则:install()
-
CMake版本
每个CMakeLists.txt文件都必须以所需的CMake版本开头,catkin需要2.8.3或者更高版本的CMake
cmake_minimum_required(VERSION 2.8.3)
-
包名
由CMake项目函数指定的包的名称,我以自己做的项目为例
project(visual)
会自动创建两个变量,PROJECT_SOURCE_DIR和PROJECT_NAME
- PROJECT_SOURCE_DIR:本CMakeList.txt所在的文件夹路径
- PROJECT_NAME:本CMakeList.txt的project名称
-
查找构建所需的其他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脚本中使用,环境变量描述了包导出头文件的位置、源文件的位置、包依赖的库以及这些库的路径。
名称规定:_
-
<NAME>_FOUND #如果找到库,则设置为true,否则为false <NAME>_INCLUDE_DIRS 或 <NAME>_INCLUDES #包导出的包含路径 <NAME>_LIBRARIES 或 <NAME>_LIBS #包导出的库 <NAME>_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个可选参数- INCLUDE_DIRS:包的导出,包含路径
- LIBRARIES:从项目导出的库
- CATKIN_DEPENDS:本项目依赖的其他catkin项目
- DEPENDS:该项目依赖的非
catkin
CMake 项目 - CFG_EXTRAS:附加配置选项
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 )