ROS2学习(三)colcon编译某个包并提供给其他包依赖使用

这篇具有很好参考价值的文章主要介绍了ROS2学习(三)colcon编译某个包并提供给其他包依赖使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

    简单的ROS2的例子学习可能不会遇到这个问题。但是我们仍然难免会思考为什么ROS2官方提供的包比如rclcpp,这些包我们使用的时候可以直接添加依赖,使用find_package(rclcpp REQUIRED),就可以找到。我们自己编译的包是否也可以提供给其他包使用。
    如果稍微大一些的工程,会有很多人开发,那么就有可能自己开发的包是一个共通的包,希望提供您给其他人使用,如何才能做的那?
    本文通过一个例子来说明如何解决这种依赖问题。例子是在一个ROS2的工程中做了两个包一个common包,一个sample包,sample包依赖于common的库。

要实现这样的效果,就要考虑几个问题。

  1. 如何将common的包编译通过
  2. ROS2并行编译,如何保证common包在sample包之前编译出来
  3. 在sample包使用的时候如何知道应该包含common包的头文件路径和动态库路径

     上面的第一个问题,也就是最基本的,我们要提供给别人使用,肯定是要自己编译通过才可以。

     第二个问题,如果在稍微大一些得工程,有很多个包的时候,使用colcon build 就会看到,几个包会同时编译,这样是为了编译的更快。但是这就没有办法保证自己的包会在其他人使用之前编译出来。当然即使不是并行编译,使用默认的方法,也没有办法保证所有的包能够按顺序的编译。
     为解决这个问题,就需要在包的package.xml中添加依赖关系。比如sample包依赖common包,那么就在sample包的package.xml中添加

<depend>common</depend>

    告诉编译器,编译B包的时候依赖A包,A包需要先编译出来。其实从package.xml中也可以看到依赖rclcpp

  <depend>rclcpp</depend>

只不过rclcpp早就编译好,安装到系统里了。

    对于第三个问题,因为sample包里的实现是需要包含common包中的头文件和链接动态库,如何让sample包知道common包的头文件路径和动态库路径?对于CMake有所了解的人,肯定会知道,要么通过下面这种方式直接设置变量解决。

set(COMMON_INCLUDE_DIR xxx/xxx/include)
set(COMMON_LIBRARY_PATH xxx/xxx/lib)

    如果对Cmake比较了解,并且对工程的相对目录比较了解的话,是可以写出来的。不过感觉这种方式比较粗暴。而且往往会写成绝对路径,当目录一变化就找不到了。

    Cmake提供了find_package()函数可以找到对应的包,并把相关的头文件和库的环境变量加进去。
    find_package(xxxx)如何实现的那?原理是在CMake的查找目录下找到xxx包的的cmake文件夹,一般都会存在,xxxConfig.cmake,或者Findxxx.cmake文件,只要找到其中一个文件就能够定位xxx所有的环境变量,然后加载到cmake中。详细的细节不在这里说了,知道大概原理即可,因为我们也很少会自己去写一个这样的Findxxx.cmake文件,大部分我们安装的库,执行install的时候都会生成这个文件。
使用find_package()的方式感觉上比直接设置环境变量更优雅一些,而且我们依赖ROS2库的时候,也是这样做的,比如我们写ROS2的程序的时候会经常看到下面这样使用

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

    现在我们要思考的就是如何把自己的包打包成一个像rclcpp一样的包,能够让其他人使用的时候直接使用find_package()就可以找到。
    其实道理也很简单,就是怎么导出头文件路径和动态库路径。这样其他包就能够使用了。
这里用到了ROS2的ament两个函数。

ament_export_include_directories(include)
ament_export_libraries(your_library)

    这两个函数一个是导出头文件的,一个是导出动态库的。这样colcon编译这个包的时候,就会生成xxxConfig.cmake文件。其他包就可以通过find_package()找到了。

实现原理讲清楚了,下面就是例子。
代码结构如下,

crabe@crabe-virtual-machine:~/Desktop/sample$ tree sample2/
sample2/
└── src
    ├── common
    │   ├── CMakeLists.txt
    │   ├── include
    │   │   └── common
    │   │       └── common.h
    │   ├── package.xml
    │   └── src
    │       └── common.cpp
    └── sample
        ├── CMakeLists.txt
        ├── include
        │   └── sample
        │       └── sample.h
        ├── package.xml
        └── src
            └── sample.cpp

就是建了两个包,一个common,一个sample。
common包里的cpp只做了一个简单的实现如下,头文件是这个类的定义:

#include "common/common.h"
#include <iostream>
using namespace std;

CommonLib::CommonLib()
{
        cout << "construct.."<<endl;
}

CommonLib::~CommonLib()
{
}

void CommonLib::Publish()
{
        cout << "this is common package func.."<< endl;
}

common包的CmakeList.txt如下:

cmake_minimum_required(VERSION 3.5)
project(common)

# 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)

#add_executable(common src/common.cpp)
add_library(common SHARED ${CMAKE_CURRENT_SOURCE_DIR}/src/common.cpp)

target_include_directories(common PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(
  common
  "rclcpp"
)

ament_export_include_directories(include)
install(DIRECTORY include/
  DESTINATION include
)

install(
        TARGETS common
        LIBRARY DESTINATION lib
        )

ament_export_libraries(${PROJECT_NAME})

#ament_export_targets(common)

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()

ament_package()

这个CMakeList.txt主要做了两个install,将头文件和动态库安装到了install目录。

install(DIRECTORY include/
  DESTINATION include
)
install(
        TARGETS common
        LIBRARY DESTINATION lib
        )

然后通过ament_export将目录导出到commonConfig.cmake中,这样,sample包就可以使用了。

ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})

sample包的写法

#include "sample/sample.h"
#include <iostream>

using namespace std;

Sample::Sample()
{
        lib_ = make_shared<CommonLib>();
}

Sample::~Sample()
{
}

void Sample::Publish()
{
        lib_->Publish();
}

int main(int argc, char ** argv)
{

  Sample sample;
  sample.Publish();

  return 0;
}

sample包,主要包含了头文件

#include "sample/sample.h"

还有使用了common中定义的类CommonLib,这些都是很常见的写法。
然后看sample的CMakeList.txt如何写

cmake_minimum_required(VERSION 3.5)
project(sample)

# 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 -std=c++11)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(common REQUIRED)

if(common_FOUND)
        message("find the lib common")
else()
        message("not find lib common")
endif()

add_executable(sample src/sample.cpp)
target_include_directories(sample PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>
  ${common_INCLUDE_DIRS})
ament_target_dependencies(
  sample
  "rclcpp"
  common
)

install(TARGETS sample
  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()

ament_package()

这里面就直接使用了

find_package(common REQUIRED)

来找common包,通过变量common_FOUND就可以知道是否找到包,然后下面使用的时候就可以添加 ${common_INCLUDE_DIRS}来扎到头文件路径,在链接依赖ament_target_dependencies中增加common,就可以正常链接了。
最后再sample的package.xml中如下增加依赖,这样就能保证编译的先后顺序了。文章来源地址https://www.toymoban.com/news/detail-612404.html

<?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>sample</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="yangcb258@163.com">yangcb</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>common</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

到了这里,关于ROS2学习(三)colcon编译某个包并提供给其他包依赖使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ros2交叉编译 x86到arm

    内容概括: 本篇文章记录了ros2 交叉编译(从x86_ubuntu到arm_ubuntu)过程,以及问题解决。 ros2官方文档 中给出了 三种交叉编译 编译的实现方法: ①提前在本地下载ros2源码然后创建docker ②直接自动下载ros2源码然后创建docker③不用ros2源码,在docker中安装预编译ros 因为交叉编译

    2024年04月17日
    浏览(53)
  • Ros2 自己修改的cartographer代码编译后不生效的解决办法

    原因是ros2在安装一些库的时候,在ros2的路径下生成了cartographer,默认找到了ros下,导致的,把这些库删掉即可 kobe@kobe-NUC11PAHi7:/opt/ros/humble/include$ sudo rm -R cartographer [sudo] kobe 的密码: kobe@kobe-NUC11PAHi7:/opt/ros/humble/include$ sudo rm -R cartographer_ros kobe@kobe-NUC11PAHi7:/opt/ros/humble/include

    2024年02月06日
    浏览(46)
  • 优化ROS2 Python编译环境,解决版本不匹配和C++配置错误

    在编译ROS2的Python环境时遇到的版本不匹配问题,并提供了解决方案。同时,还讨论了可能出现的C++配置错误,并给出了优化细节以确保同时支持C++11和C++14。通过遵循本文中的步骤,读者将能够优化ROS2编译环境,解决版本不匹配和C++配置错误,从而顺利进行开发工作。

    2024年02月07日
    浏览(152)
  • Ubuntu22.04源码安装ROS-noetic(ROS1非ROS2),编译运行VINS-MONO

    由于22.04默认安装ROS2,但很多仓库都是基于ROS1的,不想重装系统,参考这两个博客安装了ROS-noetic: 博客1. https://blog.csdn.net/Drknown/article/details/128701624 博客2. https://zhuanlan.zhihu.com/p/418227536 我的库版本(实测可行): eigen:3.3.7 ceres:1.14.0(用2.系列版本的编译时需要把C++版本设

    2024年02月02日
    浏览(57)
  • ROS2 学习--新建ros2工作空间和功能包

    简介:如何建立ros2的工作空间和功能包。 1. 创建新的工作空间 2. 新建功能包 功能包名:cpp_header 编译类型:build-type 编译工具:ament_cmake 3. 新建节点头文件 4. 头文件中类的定义 5. 新建ROS发布节点 6. 修改 package.xml文件 7. 修改配置文件 CMakeLists.txt 8. 安装相关依赖 参数rosdist

    2024年02月01日
    浏览(37)
  • ROS2系统学习番外篇2---用VSCode开发ROS2程序

    在ROS2系统学习3—第一个“Hello World”程序—即工作空间创建与包创建中已经介绍了如何创建ROS的工作空间以及包。在开发大型工程时,往往需要在IDE下面进行开发,因此本篇介绍使用VSCode来搭建ROS2开发环境的方法。 首先用VSCode打开ROS2的工作空间。 按Ctrl+shift+P进入命令模式

    2024年02月13日
    浏览(43)
  • ROS2学习(一):Ubuntu 22.04 安装 ROS2(Iron Irwini)

    一、ROS2(Iron Irwini)介绍 官方文档 Iron Irwini版本支持的平台如下: 二、ROS2(Iron Irwini)安装 1.设置编码 2.使能代码库 现在用apt添加带ROS 2 GPG 将存储库添加到源列表中 3.安装ROS2 Iron 三、ROS2测试 在terminal 1 运行下面的指令: 在terminal 2 运行下面的指令: 四、ROS2卸载 删除RO

    2024年02月10日
    浏览(44)
  • ROS2 学习(五)接口,动作

    通信双方统一规定好接口。比如图像 img,控制运动的线速度和角速度…… 我们也不用了解具体实现,基本就是了解接口会去用就行。 添加接口 不是说我们写一个接口文件就算添加好了,我们也要通过读取文件。 在 CMakeList.txt 中可以看到: 指从相应的相对目录文件中找接口

    2024年02月11日
    浏览(47)
  • ROS2学习笔记三:话题Topic

    目录 前言 1 话题简介 2 常用指令 3 RCLCPP实现实现话题 3.1 创建工作空间 3.2 代码编写 3.2.1 发布端编写 3.2.2 发布端编写 ROS2中的一个重要概念是话题(Topic)。话题是一种通过发布者和订阅者之间进行异步通信的机制。发布者(Publisher)将消息发布到特定的话题上,而订阅者(

    2024年01月20日
    浏览(44)
  • ros2官方文档(基于humble版本)学习笔记

    由于市面上专门讲ROS 2开发的书籍不多,近期看完了《ROS机器人开发实践》其中大部分内容还是基于ROS 1写的,涉及topic,service,action等一些重要的概念,常用组件,建模与仿真,应用(机器视觉,机器语音,SLAM,机械臂),最后一章写了ROS 2的安装,话题通信和服务通信的示

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包