ROS cmake常见用法的记录
首先是最基本的语法,总体就像文本文件一样。不区分大小写,但是还是推荐指令要写大写,变量参数名推荐小写。变量可以通过${变量名}来索引变量的值。判断指令IF可以直接接变量名称,例如if(MVCC) ... endif()。
指令列表
-
find_package 寻找外部库,并记录这些库的路径
-
add_message_files、add_service_files指定自定义话题、服务数据类型文件位置
-
generate_messages指定自定义话题、服务数据类型依赖包
-
catkin_package 指定当前包的依赖、生成库等信息
-
include_directories 设置功能包依赖头文件的路径
-
add_library 生成库文件
-
set_target_properties 设置属性
-
target_link_libraries 链接依赖的库
-
add_dependencies 设置编译顺序
-
add_executable 设置可执行文件名称
-
target_link_libraries 设置可执行文件依赖库
-
catkin_install_python 设置python文件生成位置
find_package
find_package(<库的名字> [REQUIRED] [COMPONENTS <组件1> <组件2> ...])
# eg
find_package(catkin REQUIRED COMPONENTS
moveit_core
moveit_ros_planning_interface
moveit_ros_planning
geometric_shapes
roscpp
std_msgs
moveit_msgs
moveit_visual_tools
)
find_package是经常用到一个指令,作用就是去在硬盘里找到这些外部库,并把它们的路径记录下来,供后续编译使用。首先我们需要指定库的名称,例如OpenCV, PCL, Eigen3, 或者 catkin。REQUIRED: 这是一个可选参数,但通常都会加。意思是:“这个库是必须的,如果找不到,请直接报错停止编译,不要继续了。如果不加这个,CMake找不到库时只会警告,然后继续尝试编译。
COMPONENTS: 如果这个库很大(像 catkin 或 Boost),你可以指定只要其中的某几个部分。该指令会在系统路径进行扫描,去找(例如去找OpenCV则会找OpenCVConfig.cmake)配置文件,一旦找到会自动定义以下变量:
OpenCV_INCLUDE_DIRS: 告诉编译器头文件在哪里OpenCV_LIBRARIES: 告诉链接器库文件在哪里。例如:/usr/lib/libopencv_core.so; /usr/lib/libopencv_highgui.soOpenCV_FOUND: 一个布尔值(True/False),告诉你到底找没找到。
值得注意的是catkin,在ROS中他是命令行工具,可以创建文件夹、可以调用CMake、可以安排编译顺序。但同时他也是一个宏集合,提供ROS在CMakeList中的一些特殊操作,例如生成msg/srv等头文件(add_message_files、add_service_files、add_action_files)、生成.pc(pkg-config)文件供其他包查找、处理ROS特有的安装路径。
同时catkin可以作为一个代理中介,将各种库当成COMPONENTS,自动将COMPONENTS中的库自动查找,将COMPONENTS中的库的头文件路径加载到${catkin_INCLUDE_DIRS},库文件路径加到 ${catkin_LIBRARIES},减少我们重复的调用find_package。
msg、srv自定义数据配置
主要需要以下指令配置
- find_package
- add_message_files\add_service_files\action创建
- generate_messages
- catkin_package
对于CMakeList中的消息、服务、动作等自定义数据类型,需要以下内容进行设置:
- 依赖项:自定义数据类型需要依赖那些包,例如在创建自定义数据类型中除了用到一些像int32这种基本数据类型外,还使用了一些例如Header等数据类型。这时候就要依赖于std_msgs、actionlib_msgs等依赖项。产生这些数据类型需要message_generation生成消息的包。所以在CMakelist中,需要在find_package中设置这些依赖项。package中也应该做一些修改:编译依赖
<build_depend>例如message_generation、std_msgs等。运行依赖<exec_depend>例如message_runtime、std_msgs等。 - 声明要创建的源文件,例如add_message_files、add_service_files
- 生成消息对应的依赖,generate_messages列出所依赖的包
- 导出依赖,catkin_package,告诉其他功能包当前包的配置文件
catkin_package(
INCLUDE_DIRS include
LIBRARIES my_robot_lib
CATKIN_DEPENDS roscpp std_msgs message_runtime
DEPENDS Boost
)
一个标准的catkin_package包含以上内容:
- INCLUDE_DIRE:头文件放在哪里
- LIBRARIES:生成了那些库文件
- CATKIN_DEPENDS:依赖那些ROS包
- DEPENDS:依赖的非ROS包(如 Boost, Eigen, OpenCV)
写一个标准的msg配置的CMakelist的配置文件,可以看到需要先在查找编译的包message_generation和依赖的包std_msgs,同时设置源文件,设置消息依赖的包。最后在catkin_package定义执行依赖的包(注意这里是message_runtime)。
# 需要加入 message_generation,必须有 std_msgs
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
## 配置 msg 源文件
add_message_files(
FILES
Person.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
include_directories 头文件路径声明
include_directories 头文件的路径,主要有两种头文件:一种是自定义的头文件,用include表示在该功能包include文件夹下的头文件;另一种是所依赖的包的头文件,之前提到利用find_package找到所依赖功能包的头文件路径,这里直接使用find_package的查找结果,例如${catkin_INCLUDE_DIRS}。
同时include_directories也提供了一种特殊用法,引入SYSTEM忽略外部库得警告。
# 先包含当前包的头文件 (最高优先级)
include_directories(
include
)
# 包含系统库和 ROS 库 (使用 SYSTEM 屏蔽外部库的警告)
include_directories(
SYSTEM
${catkin_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${Eigen3_INCLUDE_DIRS}
)
add_library
将源代码编译成一个库文件(提供一些数据类型、方法的实现),在Linux下会生成一个共享对象文件 (Shared Object),后缀是 .so。值得注意的是系统会自动加上 lib 前缀和 .so 后缀。
add_library(moveit_lerp_planner_plugin
src/lerp/lerp_planner_manager.cpp
src/lerp/lerp_interface.cpp
src/lerp/lerp_planning_context.cpp)
set_target_properties(moveit_lerp_planner_plugin PROPERTIES VERSION "${${PROJECT_NAME}_VERSION}")
target_link_libraries(moveit_lerp_planner_plugin ${catkin_LIBRARIES} ${Boost_LIBRARIES})
例如以上实例会将三个源文件,(在工作空间devel/lib下)打包成一个libmoveit_lerp_planner_plugin.so的共享库文件。而set_target_properties、target_link_libraries的作用分别是设置变量和设置依赖库路径。
set_target_properties设置了版本,利用一个双嵌套的结构获取功能包的版本号作为该库的版本
target_link_libraries则是利用find_package查找到的库路径
同时需要注意的是在caktin_package的LIBRARIES变量中设置该库名字,使得可以被其他包的程序调用。
add_dependencies
解决 ROS 编译中最常见、也最让人头疼的“并行竞争”问题。这个问题确实我也遇到过,例如前面所说的自定义msg\srv,当没有设置该命令的时候,自定义msg\srv会和调用它的源程序同时编译。因为自定义msg\srv还没有编译好,导致源文件编译报错(找不到头文件)。
因此该指令的作用就是指定编译的顺序,强制被依赖项的线程先进行,依赖项的的线程后进行。
add_dependencies(YOUR_TARGET_NAME
${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS}
)
- YOUR_TARGET_NAME: 依赖于头文件的项目名称
- 后面的参数为等待的消息,主要分为两类。一类是当前包内生成的任务,使用的是
${${PROJECT_NAME}_EXPORTED_TARGETS}还是一个双嵌套结构,先索引当前包的名称,在索引包里定义的所有 .msg、.srv、.action 以及 dynamic_reconfigure 文件对应的代码生成目标。另一类是外部包的内容,使用的是${catkin_EXPORTED_TARGETS},在find_package中Catkin 会自动收集这些包里“需要优先完成的任务”(通常是生成消息头文件),并把它们打包进这个变量里。
同时也会见一些比较旧的用法,例如${PROJECT_NAME}_generate_messages_cpp 指的是当前包下的.msg
add_executable、target_link_libraries 源文件编译和依赖
add_executable就是告诉编译器,请把指定目录下的源文件进行编译生成一个可执行文件,指定可执行文件的名称。
target_link_libraries为可执行文件链接到所依赖的库,可以用前面所提到的find_package所找到的库路径(例如${catkin_LIBRARIES})
eg:
add_executable(robot_model_and_robot_state_tutorial src/robot_model_and_robot_state_tutorial.cpp)
target_link_libraries(robot_model_and_robot_state_tutorial ${catkin_LIBRARIES} ${Boost_LIBRARIES})
add_executable(planning_scene_tutorial src/planning_scene_tutorial.cpp)
target_link_libraries(planning_scene_tutorial ${catkin_LIBRARIES} ${Boost_LIBRARIES})
add_executable(planning_scene_ros_api_tutorial src/planning_scene_ros_api_tutorial.cpp)
catkin_install_python Python文件配置
catkin_install_python(PROGRAMS
scripts/talker_p.py
scripts/listener_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
这个指令就是将指定的Python文件安装到指定路径,方便ROS指令运行。因此主要有两个参数:Python文件列表和安装路径。分别对应PROGRAMS和DESTINATION。默认使用路径都是${CATKIN_PACKAGE_BIN_DESTINATION} 通常对应系统路径 lib/你的包名/.
5331



被折叠的 条评论
为什么被折叠?



