前言:目前还在学习ROS+无人机框架中,,,
更多更新文章详见我的个人博客主页【前往】
文章目录
-
- [1. CMakeLists.txt与package.xml的作用](#1. CMakeLists.txt与package.xml的作用)
- [2. 生成CMakeLists.txt](#2. 生成CMakeLists.txt)
-
- [2.1 ROS1](#2.1 ROS1)
- [2.2 ROS2](#2.2 ROS2)
- [3. CMakeLists.txt编写](#3. CMakeLists.txt编写)
-
- [3.1 ROS1](#3.1 ROS1)
- [3.2 ROS2](#3.2 ROS2)
- [4. package.xml编写](#4. package.xml编写)
- [5. 其他--Setup.py的修改](#5. 其他--Setup.py的修改)
1. CMakeLists.txt与package.xml的作用
在ROS 系统的功能包中 要包含 CMakeLists.txt 与 package.xml 文件来编译功能包的内容
CMakeLists.txt 原本是Cmake 编译系统的规则文件,而Catkin 编译系统基本沿用了CMake 的编译风格,只是针对ROS 工程添加了一些宏定义。所以在写法上,catkin 的 CMakeLists.txt 与CMake 的基本一致。用cmake 命令创建功能包 时,会自动生成CMakeList.txt文件,已配置了多数编译选项,且包含详细的注释,只需稍作修改便可编译自己的文件。
而package.xml 文件是描述功能包清单的文件,包括功能包的名称 、版本号 、作者信息 、许可信息 、编译依赖 和运行依赖等。
所以 CMakeLists.txt 非常重要,它指定了由源码到目标文件的规则,catkin 编译系统在工作时首先会找到每个package 下的 CMakeLists.txt ,然后按照规则来编译构建
2. 生成CMakeLists.txt
2.1 ROS1
ROS1 可通过用catkin_create_pkg 命令创建功能包 ,这会自动生成CMakeLists.txt 和package.xml文件的。
sh
# 创建工作空间
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
# 注:std msgs rospy roscpp为创建功能时指定的铱赖,test为包名
# 也可以先不指定,后面在CMakeLists.txt和package.xmL中手动添加
catkin_create_pkg test std_msgs rospy roscpp
# 查看一下在~/catkin_ws/src目录下自动生成了哪些文件夹和文件
tree
通过上面的命令生成的工作空间如下
include
:存放**.h**的头文件
src
:可同时存放**.cpp或 .py的源文件,但一般 .py**文件存放在scripts
目录中
scripts
:习惯存放**.py的python**文件,需要自己创建注:python代码和c++代码不分家,可同时存放在同一功能包中
2.2 ROS2
ROS2 可通过如下的命令来创建功能包 以及必要的CMakeList.txt 和package.xml文件
sh
# 创建工作空间
mkdir -p ~/dev_ws/src
cd ~/dev_ws/src
# ament_cmake和ament_python分别代表c++和python两种代码的功能包
# test_c和test_python代表包名
ros2 pkg create --build-type ament_cmake test_c
ros2 pkg create --build-type ament_python test_python
# 查看一下在~/dev_ws/src目录下自动生成了哪些文件夹和文件
tree
通过以上命令生成的工作空间如下:
test_c/include
:存放**.h**的头文件
test_c/src
:存放**.cpp的C++**源文件
test_python/test_python
:存放**.py的python**文件注:与ROS1不同,同一功能包内只能同时包含python文件或者C++文件中的一种
3. CMakeLists.txt编写
3.1 ROS1
- 常用的ROS1 中CMakeLists.txt架构如下
视频解析参考:中科院软件所-机器人操作系统入门(ROS入门教程)
cmake
cmake_minimum_required() #CMake的最低版本号
project() #项目名称
find_package() #找到编译需要的其他CMake/Catkin package
catkin_python_setup() #catkin新加宏,打开catkin的Python Module的支持
add_message_files() #catkin新加宏,添加自定义Message文件
add_service_files() #catkin新加宏,添加自定义Service文件
add_action_files() #catkin新加宏,添加自定义Action文件
generate_message() #catkin新加宏,生成不同语言版本的msg/srv/action接口
catkin_package() #catkin新加宏,生成当前package的cmake配置,供依赖本包的其他软件包调用
add_library() #生成库
add_executable() #生成可执行二进制文件
add_dependencies() #定义目标文件依赖于其他目标文件,确保其他目标已被构建
target_link_libraries() #链接
catkin_add_gtest() #catkin新加宏,生成测试
install() #生成可安装目标
需要自己配置的项目一般就下面几种:
-
include_directories
- 用于设置头文件的相对路径
- 全局路径默认为功能包所在目录,功能包的头文件一般放在功能包根目录下的include文件夹,
所以需要此处添加此文件夹 - 还包含catkin编译器默认的其他头文件路径,如:ROS默认安装路径、Linux系统路径等
-
add_exectuable
- 用于设置需要编译的代码和可执行文件
- 第一个参数为期望生成的可执行文件(节点)名称
- 后面的参数为参与编译的源文件(.cpp),若需要多个代码文件,可依次列出,空格分隔
-
target_link_libraries
- 用于设置链接库
- 有些功需要使用系统或第三方库函数,通过该选项可以配置执行文件链接的库文件
- 第一个参数与add_exectuable相同,为可执行文件(节点)名称
- 后面的参数为需要链接的库,依次列出,空格分隔
-
add_dependencies
- 用于设置依赖
- 有时候需要自定义消息类型,消息类型会在编译过程中产生相应语言的代码。若编译的可执行文
件依赖这些动态生成的代码,则需要添加${PROJECT NAME}generate messages_cpp配置
-
自定义数据类型:消息msg 、服务srv 、动作action
- find_package(catkin REQUIRE COMPONENTS message_generation)
- catkin_package(CATKIN_DEPENDS message_runtime)
- add_message_files(FILES xxx.msg)
- add_service_files(FILES xxx.srv)
- add_action_files(FILES xxx.action)
- generate_messages(DEPENDENCIES std_msgs)
CMakeLists.txt模板参考:CMakeLists.txt
3.2 ROS2
常用的ROS2 中CMakeLists.txt架构如下
cmake
cmake_minimum_required() #CMake的最低版本号
project() #项目名称
find_package() #查找系统中的依赖项
ament_target_dependencies() #依赖于其他目标文件,确保其他目标已被构建
add_executable() #生成可执行二进制文件
install() #生成可安装目标
ament_package() #生成功能包
rosidl_generate_interfaces() # 自定义消息类型接口
示例模板如下
cmake
cmake_minimum_required(VERSION 3.5)
project(test_c)
# Default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
add_executable(talker src/publisher_member_function.cpp) # 修改2
ament_target_dependencies(talker rclcpp std_msgs) # 修改3
install(TARGETS
talker # 修改4
DESTINATION lib/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
# 添加自定义消息类型需要添加项
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/Num.msg" # 自定义1
"msg/Sphere.msg" # 自定义2
"srv/AddThreeInts.srv" # 自定义3
DEPENDENCIES geometry_msgs
)
ament_package()
相较于基于catkin 的CMake 文件,基于ament的明显简洁很多
假设你编写了~/dev_ws/src/test.cpp
文件后,需要修改的步骤如下:
- 链接源代码
cmake
add_executable(test src/test.cpp) # test为你输入节点后执行的名称,如ros2 run test_c test(前一个test_c为包名,后一个test则为这里的设置的名称,代表具体执行的代码)
ament_target_dependencies(test rclcpp) # 添加依赖项
- 添加下面这两行代码的目的是让编译器编译
~/dev_ws/src/test_c/test.cpp
这个文件
cmake
install(TARGETS
test
DESTINATION lib/${PROJECT_NAME}
)
当你自定义消息类型时还需要消息类型文件
cmake
# 添加自定义消息类型需要添加项
# 下面两项是固定的,geometry_msgs是用于生成消息依赖包
find_package(geometry_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/Num.msg" # 自定义1
"msg/Sphere.msg" # 自定义2
"srv/AddThreeInts.srv" # 自定义3
DEPENDENCIES geometry_msgs
)
4. package.xml编写
package.xml的框架如下
xml
<package format="3">
<name>..</name>
<version>0.0.0</version>
<description>...</description>
<maintainer email="lanhanba@todo.todo">...</maintainer>
<license>...</license>
<buildtool_depend>...</buildtool_depend>
<exec_depend>...</exec_depend>
<exec_depend>...</exec_depend>
<export>
<build_type>...</build_type>
</export>
</package>
相较于CMakeList.txt ,package.xml 的语法就简单许多,且ROS1 和ROS2的标签语法通用
- <build_depend></build_depend>: 标签定义了功能包中代码编译时所依赖的其他功能包
- <exec_depend><exec_depend>: 标签定义了功能包中可执行程序运行时所依赖的其他功能包
- 自定义数据类型 :话题消息msg 、服务数据srv 、动作数据action
模板如下
xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>test_c</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="lanhanba@todo.todo">lanhanba</maintainer>
<license>TODO: License declaration</license>
<!-- ROS1 -->
<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>
<!-- ROS2_C++ -->
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
<!-- ROS2_python -->
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
<!-- ROS2中C++功能包添加自定义消息类型还需添加下面三行(固定形式,和上面的CMake修改搭配使用,python不需要) -->
<depend>rosidl_default_generators</depend>
<depend>geometry_msgs</depend>
<member_of_group>rosidl_interface_packages</member_of_group>
</package>
5. 其他--Setup.py的修改
在ROS2-Python 功能包中,如果添加类似~/dev_ws/src/test_python/test.py
的python 文件,则需要对功能包中的Setup.py进行如下的修改
python
from setuptools import setup
package_name = 'test_python'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='lanhanba',
maintainer_email='lanhanba@todo.todo',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
# 结构如下:节点名 = 功能包名.代码文件.执行入口函数名(一般执行入口函数名都是main,也就是说python代码中一般要有main函数)
# 通过ros2 run test_python test 来执行test_python.test:main下的函数
# 如果有多个python代码文件都需要一一添加,名称不能一样
"test = test_python.test:main",
"test2 = test_python.test2:main"
],
},
)
参考: