ros2中 CMakelist.txt究竟如何使用
ROS2的构建系统ament_cmake是基于CMake改进而来。
在工作空间的src目录项使用
ros2 pkg create <package_name>
可以生成一个功能包框架。
功能包中的构建信息往往包含在CMakelist.txt和package.xml这两个文件中。
CMakelist.txt
CMakelist.txt文件时CMake构建系统的规则文件,用于描述如何去构建ros2功能包。
它指定了功能包的编译规则、依赖项以及生成的目标文件等信息。
通过使用CMake工具和colcon编译系统,CMakelist文件指导它们的编译过程,确保按照正确的规则和依赖关系进行构建功能包。
他还定义了源码文件、头文件目录、链接库等构建要素、确保代码能够被正确的编译和链接。
不过好消息是在使用ros2 pkg create创建功能包时,相关的编译选择已经自动生成,并且包含较为详细的注释,只需要针对自己的需求进行添加即可。
package.xml
package.xml文件相比CMakelist.txt发挥的作用更像是详细的注释。描述功能包的文件,包括功能包的名称、版本号、作者信息、许可信息、编译依赖以及运行依赖等。
ROS2中CMakeList.txt整体使用构架
如上图,构建功能包使用的指令如下
ros2 pkg create serial_test --build-type ament_cmake --dependencies rclcpp
上图所示整体构架包含了
1. cmake_minimum_required() #CMake最低的版本号 2. project() #项目(包)的名称 3. find_package() #查找系统中的依赖项(库) 4. add_executable() #生成可执行的二进制文件 5. ament_target_dependencies() #依赖于其他的目标文件,确保其他目标已经被构建 6. install() #生成可安装文件 7. ament_package() #生成功能包 8. rosidl_generate_interfaces() #自定义消息类型接口
1、2、7都会自己默认生成,那直接从3开始看:
find_package()
find_package()就是你在编写ros节点的时候用到的相关的依赖以及其他的库,生成时使用的
--build-type ament_cmake --dependencies rclcpp,相应的生成了
find_package(ament_cmake REQUIRED)以及
find_package(rclcpp REQURED)这两行代码,我们在编写时使用
#include<rclcpp>
就是靠这句find_package(),编译系统才会去系统库中去寻找相应的依赖
所以你要使用相应的外加的库的时候就需要先
find_package(packagename REQUIRED) 然后才能在使用#include "package_name"
当然,也要注意#include时,<> 和 ""的区别。尤为重要
add_executable()
添加可执行文件para(node_name releative_pwd)执行名称,相对路径
例如上图中add_executable(topic_publisher_01 src/serial_test.cpp).
你在ros2 run packageName nodeName中的nodeName就取决于这个add语句的第一个参数。
其实就是给节点名称,第二个参数相对路径是从节点的src开始,
值得注意的是add_executable()、以及ament_target_dependencies()和install()中的名字需要统一,
即,要同时使用这三个语句来声明和编译一个节点,名字必然要统一,最好见名知意。
ament_target_dependencies()
这条语句十分重要,用于为可执行文件添加依赖项来一起编译。能不能正确使用外加库就取决于find_package()以及这条语句。
具体的执行过程分为:添加编译依赖,添加链接依赖,解析链接依赖。感兴趣可以自己了解
使用语法 ament_target_dependencies(nodeName packageName)
ament_target_dependencies(topic_publisher_01 rclcpp serial)
很简单,第一个参数,就是add中的要运行的节点名称,第二个以及三,四。。。分别是添加的依赖包,但是需要先find_package()。
install(TARGETS nodeName DESTNATION lib/${PROJECT_NAME})
该语句的最终目的就是让编译器安装该节点,使得节点可以运行,参数只需要动中间的,
输入自己的节点名称即可。
TARGETS参数指定要安装的目标,明显就是后面编译好的nodeName文件。
nodeName参数即需要被安装的目标
lib/${PROJECT_NAME}参数指定要安装的位置,这个一般直接照抄即可,具体哪里我没细找。
rosidl_generate_interfaces(${PROJECT_NAME} "interface.msg" DEPENDENCIES geometry_msgs)
这边我还没有具体用到,先简单总结一下,直接上代码解释把
# 添加自定义的消息类型的依赖项 # 这两项固定添加 find_package(geometry_mags REQUIRED) # geometry_mags用于生成消息的依赖包 find_package(rosidl_default_generators REAUIRED) #为自定义的msg,srv,action等生成头文件 rosidl_generator_interfaces(${PROJECT_NAME} "msg/" "srv/" "action/" DEPENDENCIES geometry_msgs )
关于自定义消息类型应该还有其他需要的,等用到了在添加。
ament_package()
最后进行安装该节点,因为需要从CMakeList.txt中读取大量信息,应当放在最后一个使用
ros2中package.xml(包清单)编写
package.xml更偏向于描述文件,语法简答且与ros1通用。
包含各个功能包的依赖信息,帮助colcon确定编译顺序。当我们单独要编译一个功能包时,必须确保编译的包的名字与package.xml中<name>name</name>的name相同
只需要注意以下几个标签:
<build_depend></build_depend>:标签定义了功能包中代码编译时所以以来的其他的功能包
# 比如我在该功能包的节点中#include <rclcpp> # 那么相应的修改CMakeList.txt以及package.xml # CMakelist.txt上面已经介绍过了,那就package.xml <depend>rclcpp</depend>
其他的标签用到了再加
生成时,基础模板已经出现,只需要注意添加的依赖以及自定义的消息类型即可
添加消息类型时,需要添加如下三行
<depend>rosidl_default_generators</depend> <depend>geometry_msgs</depend> <member_of_group>rosidl_interface_packages</member_of_group>
固定形式和上面的CMakeList.txt里的配合使用。
serial库的使用解决
虽然不能直接apt install 安装serial的库(也可能是我没找到)
但是网上其实有很多的可以直接用的包,具体难点就是如何添加,让ros找到它,
首先,搜索资料,到getihub或者其他源码开源平台找
这边挂一个链接,ros2 humble可用serial包
下载解压,查看README,使用说明
按照说明一直到install上一步,大多数的包作者都已经打包好了,其实不用进行安装过程就可以直接使用,
安装了之后CMakelist写起来可能会更麻烦。
直接将make之后的serial-foxy复制粘贴到工作空间下与功能包同目录的src下即可
最后,创建功能包的时候不使用--dependencies进行添加,而是自己编写CMakeList.txt文件添加依赖包
方法就和上面写的一样,package.xml最好也写上,
最后,最好使用#include " "使得系统自上而下搜索头文件,使用的就是我们copy的那个
自下而上容易找错,不过一般问题也不大
大多数外加依赖的使用过程都是如此,有错记得联系我,后期再改,再添加,加油!!!