ROS2 CmakeList如何正确引入第三方.so文件

2023-05-16

在使用ros2开发的时候难免会需要引入第三方的厂家提供的.so文件库。注意这里说的并不是自己写的cpp文件转成.so然后再自己的工程项目中使用。例如经常使用的ICANCmd.h头文件和libCanCmd.so库还有onnx推理的时候onnxruntime_c_api.h头文件和libonnxruntime.so库文件。ros1中使用如下代码添加:

target_link_libraries(${PROJECT_NAME}_node
  ${CMAKE_CURRENT_SOURCE_DIR}/lib/libonnxruntime.so      # 微软公司的runntime库
)

但在ROS2中直接使用这种方式添加的话会报找不到 xx.so文件库。这是因为ROS2的.so需要将库引入到指定的文件路径下才能使用。

下面以电机CAN包为例一步步实现电机的.so库调用

mkdir can_test_ws      #  创建can_test_ws工作空间 

cd can_test_ws           #  进入到can_test_ws

mkdir src                    #  创建src文件

cd src

创建一个test_can包依赖rclcpp 节点名称为can_node

ros2 pkg create test_can --build-type ament_cmake --dependencies rclcpp --node-name can_node  

 使用tree查看下文件结构

└── src
    └── test_can
        ├── CMakeLists.txt
        ├── include
        │   └── test_can
        ├── package.xml
        └── src
            └── can_node.cpp

5 directories, 3 files

 添加一个lib文件 拷贝libCanCmd.so文件并且在include/test_can文件中添加一个ICANCmd.h头文件(和libCanCmd.so配套由厂家提供)和一个motorControl.h使用文件和一个motorControl.cpp实现,添加完以后如下: (这里并没有按照hpp头文件cpp源文件的C++创建方式,而是沿用了ICANCmd.h的C语言写法。

└── src
    └── test_can
        ├── CMakeLists.txt
        ├── include
        │   └── test_can
        │       ├── ICANCmd.h
        │       └── motorControl.h
        ├── lib
        │   └── libCanCmd.so
        ├── package.xml
        └── src
            ├── can_node.cpp
            └── motorControl.cpp

6 directories, 7 files

编译

colcon build

source install/setup.bash

ros2 run test_can can_node

输出 hello world test_can package

到这里为止都并没有使用.so文件

我们打开can_node.cpp,添加自己写的motorControl.h文件

#include <cstdio>

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

  printf("hello world test_can package\n");
  return 0;
}

 motorControl.h文件文件中使用了ICANCmd.h文件

#ifndef __MOTER_CONTROL_H__
#define __MOTER_CONTROL_H__

#include "ICANCmd.h"       // CAN通信头文件

#include <iostream>
#include <cstdlib>        // 主要使用exit(0) 退出程序 
#include <unistd.h>       // uninx系统主要用usleep功能
#include <memory>        //  智能指针



#define __countof(a)  (sizeof(a)/sizeof(a[0]))     // 定义宏
#define D_PI 2 * acos(0.0)                         // math库中计算弧度的反余弦

// 接受信号结构体
typedef struct {
   bool Run;
   DWORD ch;
}rcv_thread_arg_t;



int Init_CAN();          // 初始化CAN 经过 CAN_DeviceOpen CAN_ChannelStart CAN_GetDeviceInfo 后成功返回0
void PDO_map();          // PDO映射通过PDO传输数据
void *send_func(DWORD id, char nDataLen, unsigned int *arryData); // 发送功能
void disableMotor();     // 电机失能
void enableMotor();      // 电机使能
void CloseCAN();         // 关闭通道后在关闭CAN 使用了 CAN_ChannelStop CAN_DeviceClose
void fastStopMotor();    // 电机快速停止
void motorAtVelMode();   // 速度指令
void ReadLoadRate();     // 读取电机的负债率

void SigintHandler(int sig);
void Set_DownCurrent();         // 设定最小电流
void Set_UpCurrent();           // 设置最大电流

void MotorFaultClear();         // 驱动器故障清除

void StartNodeCommunication();  // 开始连接
void StopNodeCommunication();   // 停止连接
void SendSync();                // 发送80帧同步

void Motor_modelSet();          // 发送伺服电机模式

void createPthread();           // 创建线程
void Stop_Rec_pthread();        // 关闭线程

#endif  // end __MOTER_CONTROL_H__ 

can_node.cpp中添加#include "test_can/motorControl.h" ,由于motorControl.h中的使用到了ICANCmd.h,这个头文件需要调用一个闭源的libCanCmd.so,直接编译会报错未定义:

/usr/bin/ld: CMakeFiles/can_node.dir/src/can_node.cpp.o: in function `main':
can_node.cpp:(.text+0x14): undefined reference to `Init_CAN()'

#include <cstdio>
#include "test_can/motorControl.h"  // 添加自定义电机头文件
int main(int argc, char ** argv)
{
  (void) argc;
  (void) argv;

  Init_CAN();  // CAN 通信初始化

  printf("hello world test_can package\n");
  return 0;
}

出现这种情况是我们头文件motorControl.h中申明的Init_CAN()虽然在motorControl.cpp文件中实现了,但是ROS2并没有办法直接找到这个实现,因此需要配置下CMakeLists.txt,修改的地方已经给出。

cmake_minimum_required(VERSION 3.5)
project(test_can)

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

# ************* 以下内容为手动添加部分 *****************
include_directories(include) # 添加项目中的include文件夹路径
add_executable(can_node
  src/can_node.cpp
  src/motorControl.cpp
)
# ************* 以下内容为手动添加结束 *****************

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

# add_executable(can_node src/can_node.cpp)   # 手动注释
target_include_directories(can_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(
  can_node
  "rclcpp"
)

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

编译后不出意外还是会报错:

Starting >>> test_can
--- stderr: test_can                             
/usr/bin/ld: CMakeFiles/can_node.dir/src/motorControl.cpp.o: in function `Init_CAN()':
motorControl.cpp:(.text+0x123): undefined reference to `CAN_DeviceOpen'
/usr/bin/ld: motorControl.cpp:(.text+0x196): undefined reference to `CAN_ChannelStart'
/usr/bin/ld: motorControl.cpp:(.text+0x1b9): undefined reference to `CAN_GetDeviceInfo'
/usr/bin/ld: CMakeFiles/can_node.dir/src/motorControl.cpp.o: in function `send_func(unsigned int, char, unsigned int*)':
motorControl.cpp:(.text+0x5eb): undefined reference to `CAN_ChannelSend'
/usr/bin/ld: CMakeFiles/can_node.dir/src/motorControl.cpp.o: in function `receive_func(void*)':
motorControl.cpp:(.text+0x6b8): undefined reference to `CAN_ChannelReceive'
/usr/bin/ld: motorControl.cpp:(.text+0x7d7): undefined reference to `CAN_GetErrorInfo'
/usr/bin/ld: CMakeFiles/can_node.dir/src/motorControl.cpp.o: in function `CloseCAN()':
motorControl.cpp:(.text+0x891): undefined reference to `CAN_ChannelStop'
/usr/bin/ld: motorControl.cpp:(.text+0x8a3): undefined reference to `CAN_ChannelStop'
/usr/bin/ld: motorControl.cpp:(.text+0x8b0): undefined reference to `CAN_DeviceClose'
/usr/bin/ld: CMakeFiles/can_node.dir/src/motorControl.cpp.o: in function `Stop_Rec_pthread()':
motorControl.cpp:(.text+0xc3f): undefined reference to `CAN_ChannelStop'
/usr/bin/ld: motorControl.cpp:(.text+0xc4c): undefined reference to `CAN_DeviceClose'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/can_node.dir/build.make:146: can_node] Error 1
make[1]: *** [CMakeFiles/Makefile2:132: CMakeFiles/can_node.dir/all] Error 2
make: *** [Makefile:141: all] Error 2
---
Failed   <<< test_can [0.20s, exited with code 2]
                                
Summary: 0 packages finished [0.29s]
  1 package failed: test_can
  1 package had stderr output: test_can

 这一步是我们已经可以通过motorControl.h调用motorControl.cpp中的函数,但是我们不能使用ICANCmd.h关联的.so文件库导致无法实例化电机驱动。

还需要继续修改CMakeLists.txt添加如下一段

target_link_libraries(can_node
  ${PROJECT_SOURCE_DIR}/lib/libCanCmd.so
)

到这一步编译是不会报错的但是执行:

ros2 run test_can can_node

会报 /can_test_ws/install/test_can/lib/test_can/can_node: error while loading shared libraries: libCanCmd.so: cannot open shared object file: No such file or directory的错误

继续修改CMakeLists.txt(⊙﹏⊙)

install(
  DIRECTORY lib/                       # 发现你项目中的lib中所有的文件
  DESTINATION lib/${PROJECT_NAME}      # 拷贝到install目录中
)
install(TARGETS can_node
  RUNTIME DESTINATION lib/${PROJECT_NAME}    # 程序运行的时候调用install中的路径
)

再次编译执行即可调用,至此已经完成了C++版本的ROS2调用第三方.so文件库。

若本文有任何错误还请读者指出!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS2 CmakeList如何正确引入第三方.so文件 的相关文章

  • Jetson Xavier NX安装librealsense

    在nx上安装librealsense可以使用由jetsonhacks开源的安装脚本installRealSenseSDK 克隆仓库 xff0c 进入目录 git clone https github com jetsonhacks inst
  • Kubernetes(K8s)的简介及基础知识

    1 关于Kubernetes xff08 K8s xff09 的简介 Kubernetes xff0c 简称又叫K8s xff0c 为什么简称要叫K8s xff0c 据说是因为Kubernetes单词中K字母和S字母之间相隔8个字母 xff
  • 爬虫实战(三)

    随着互联网的不断发展 xff0c 网络数据的规模和价值也不断提升 在这个大数据时代 xff0c 如何从海量数据中提取有价值的信息并加以利用 xff0c 成为了数据科学 商业分析 金融预测 社会研究等领域中一个重要的问题 而网络爬虫作为一种数
  • 数据库连接

    一 连接数据库的方法和工具 数据库连接是访问数据库的关键步骤之一 xff0c 通过连接数据库 xff0c 我们可以进行数据的增删改查等操作 下面介绍几种连接数据库的方法和工具 命令行工具 在命令行中输入相应的命令即可连接数据库 常用的命令行
  • C语言之十进制转化为十六进制

    作者 xff1a 从未止步 博客主页 xff1a 从未止步的博客 专栏 xff1a 和我一起学C 语录 xff1a Every day is a second chance 行动是理想最高贵的表达 xff0c 给大家介绍一款超牛的斩获大厂o
  • 合肥工业大学机器人足球仿真robcup作业二(python实现)附代码有注释

    用面向对象的思维设计相关类 xff0c 从而实现直线与直线 直线与圆 直线与矩形的交点 要求各给出每个案例的至少一个示例的程序 这是第二次机器人足球的作业代码 xff0c 写的比较潦草 xff0c 但是用的方法还是通俗易懂的 xff0c 基
  • 合肥工业大学机器人足球仿真robcup作业三(python实现)附代码有注释

    第三次作业 题目 xff1a 已知2个点的信息 定位自己的绝对坐标 设图中C 0 0 P1 52 5 32 P2 52 5 32 P3 52 5 32 P4 52 5 32 P5 0 32 P6 0 32 P7 30 7 P8 30 7 P
  • 程序员一定要知道的10个网站,记得收藏

    为大家整理了对程序员超有用的网站合集 xff0c 今天主要分享知识社区 amp 学习刷题两大类 希望能助力各位早日成为码神 话不多说 xff0c 直接上干货 知识社区类 1 Github 程序员的Facebook 毋庸置疑 xff0c 首位
  • for in 和for of的区别

    文章目录 1 遍历数组通常用for循环2 for in遍历数组3 遍历对象总结 1 遍历数组通常用for循环 ES5的话也可以使用forEach xff0c ES5具有遍历数组功能的还有map filter some every reduc
  • win11打开移动热点显示“我们无法设置移动热点”

    解决方法 xff1a 以下方法是本人联系微软客服解决 xff0c 亲测有效 用管理员模式打开命令提示符 xff0c 输入netsh winsock reset xff08 按下Enter键 xff09 netsh int ip reset
  • 树莓派pico的软件安装及使用

    简介 xff1a 在些日子在芯查查积分商城兑换了一个树莓派pico xff0c 来教大家怎么安装Thonny软件 xff0c 并且使用Thonny编译运行树莓派pico 第一步 xff1a 安装固件 第二步 xff1a 在window上安装
  • Git分布式版本控制工具(linux)

    内容 xff1a Git 概述 Git 代码托管服务 Git 常用命令 在 IDEA 中使用 Git 目录 1 前言 xff1a 1 1 什么是Git xff1f 1 1 1 其他版本控制工具 xff1a 1 2 使用Git能做什么 xff
  • ADRC的simulink仿真实现与m代码实现

    本文章以最简单的二阶系统为例 xff0c 介绍其simulink仿真实现和m代码实现 案例中的二阶系统如下所示 经典ADRC的基本结构如下 xff1a 本案例中的simulink仿真整体结构 xff08 为便于理解 xff0c 结构图与上述
  • 安装ROS

    如何在电脑安装ROS 安装ROS环境是学习ROS的第一步 xff0c 本文将记录个人搭建的过程 xff0c 包括可能遇到的错误 解决办法 个人心得等 文章目录 如何在电脑安装ROS 前言一 在Windows系统下载VMware虚拟机并安装二
  • ROS命令行工具的使用

    一 命令行工具的使用 前言 在ROS里面 xff0c 命令行工具的使用能够使我们深入了解ROS xff0c 使我们操作ROS的时候更加方便 我们利用海龟作为示例进行命令行工具的学习 运行小海龟步骤 xff1a 终端输入 roscore 然后
  • ROS快捷操作键和话题记录与复现

    一 ROS快捷操作键 打开终端 xff1a Ctrl 43 alt 43 T 查看隐藏文件夹 xff1a Ctrl 43 H 结束终端的某个操作 xff1a Ctrl 43 C 启动运行ROS系统前必须的一个指令 xff1a roscore
  • ROS工作空间和功能包

    一 工作空间 工作空间 xff08 workspace xff09 xff08 缩写ws xff09 工作空间是存放工程开发相关文件的文件夹 代码空间 xff08 source space xff09 xff08 src xff09 是用来
  • ROS实现代码及已编译代码运行步骤

    目录 一 实现一个代码步骤1 C 43 43 代码实现步骤2 python代码实现步骤 二 已编译代码运行步骤 一 实现一个代码步骤 1 C 43 43 代码实现步骤 在catkin ws src 内创建功能包的步骤 其实可以任意创建工作空
  • 基于ROS的PX4+Gazebo仿真——PX4一键起飞及飞行控制

    一键起飞 参考及引用 1 CSDN博主 战争果子 的原创文章 xff0c 遵循CC 4 0 BY SA版权协议 原文 xff1a https blog csdn net EnthusiasmZing article details 7916
  • RT-Thread相比较于Freertos的优势在哪里

随机推荐

  • Up Board安装ROS及mavros

    Up Board安装ROS及mavros 目录 Up Board安装ROS及mavros一 在Up Board安装Ubuntu系统1 材料准备2 拿一个空的U盘作为驱动盘为Up Board安装系统3 安装Ubuntu系统 二 在Ubuntu
  • Unity和ROS通讯的机械臂

    Unity和ROS之间的通讯包 目录 Unity和ROS之间的通讯包参考及引用1 Github源码地址 Unity和ROS之间的通讯 一个ROS包 xff08 用于接收从Unity场景发送的ROS消息 xff09 两个导入到Unity的包
  • 虚拟机Ubuntu磁盘扩容个人记录

    虚拟机Ubuntu磁盘扩容个人记录 一 修改扩展大小 修改成功以后 xff0c 打开虚拟机Ubuntu 二 进入Ubuntu修改 打开终端 xff0c 输入 sudo gparted 右键点击后更改大小 然后确定修改 最后 xff0c 终端
  • 下载源码包后在Ubuntu编译

    下载源码包后在Ubuntu编译 学习使用Ubuntu过程中 xff0c 不免会尝试跑一遍别人的代码 xff0c 这时候要知道如何将源码下载后进行编译及运行 本文与以下两篇博客相关 xff1a ROS工作空间和功能包 ROS实现代码及已编译代
  • 利用科大讯飞语音合成模块SDK实现ROS语音交互

    利用科大讯飞语音合成模块SDK实现ROS语音交互 本文内容与CSDN博主 AI Chen 的原创文章相同 xff0c 可以直接参考原文 xff1a https blog csdn net qq 39400324 article detail
  • tts_subscribe.cpp代码

    tts subscribe cpp span class token comment 语音合成 xff08 Text To Speech xff0c TTS xff09 技术能够自动将任意文字实时转换为连续的 自然语音 xff0c 是一种能
  • FreeRTOS线程安全、中断安全的printf实现方式

    文章目录 前言一 问题描述二 解决方案1 线程安全 中断安全的printf实现方式 总结参考 前言 利用串口对基于FreeRTOS的多任务程序调试过程中 xff0c 时常出现数据交叉打印 xff0c 甚至出现乱码现象 这是因为通常情况下 x
  • 结构体空间对齐和结构体数组的使用

    今天在学习linux的platform总线时 xff0c 设备对资源的描述用到了结构体数组 xff0c 以前从没见过 如下 很明显用结构体数组主要是用来给一系列相同类型的结构体赋值 xff0c 主要是来看内存分配问题 首先是结构体的内存分配
  • ubuntu:出现bash: /opt/ros/melodic/setup.bash: 没有那个文件或目录 解决方法

    如图 xff0c 解决方法如下 xff1a 打开虚拟机终端 xff0c 输入 gedit bashrc 弹出一个文件 xff0c 找到最后一行 xff0c 如图所示 然后我roscore了一下 xff0c 看了一下我的ros版本 xff1a
  • STC单片机仿三菱FX2n方案 hex烧录进去就可以当plc用

    STC单片机仿三菱FX2n方案 hex烧录进去就可以当plc用 xff0c 成本低方便快捷id 61 643520282241 amp
  • 西门子S7-1200系列PLC定时器指令

    定时器指令是在PLC程序设计中非常常见的一种指令 xff0c S7 1200系列PLC的定时器的指令格式及使用方式都不同于S7 200系列PLC S7 1200系列PLC的采用的是IEC标准的定时器指令 xff0c 用户程序中可以使用的定时
  • 0基础学springboot之对数据库的增删改查

    1 xff1a 使用的是mysql数据库 xff0c 数据库中的表为student 2 xff1a 创建springboot项目 xff0c 在pom文件里加载mysql依赖 lt dependency gt lt groupId gt m
  • 平衡车Car_Balance(一)——电机

    目录 一 电机简要概述 二 常见电机种类 1 直流有刷电机 xff08 BDC xff0c 最最最常见的电机 xff09 2 直流无刷电机 xff08 BLDC xff09 3 舵机 4 步进电机 三 平衡小车选用电机及需要关注的参数 1
  • 用matlab进行xlsx表格的提取和操作

    用matlab进行xlsx表格的提取和操作 一 数据的提取二 垃圾数据的清除三 数据的分类四 图像的绘制 在学习数学建模时 xff0c 我们会碰到大数据的问题 xff0c 这类问题通常要进行数据预处理 xff0c 这是我用matlab进行预
  • Android 开发艺术探索笔记(5,我的头条面试经历分享

    public Messenger Handler target mTarget 61 target getIMessenger public Messenger IBinder target mTarget 61 IMessenger St
  • 穿越机F4飞控F405代码pcb文件,原理图

    穿越机F4飞控F405代码pcb文件 原理图 xff0c 源代码 xff0c 穿越机无人机 xff0c F4V3飞控PCB资料 xff0c AD格式原理图 PCB图 Bo可直接打板id 61 659104114509 amp
  • 【AD20学习笔记】网表导入及模块化布局设计(1)

    7 20 今天写完 本章快捷键总结 xff08 绿色是自己设的 xff09 Q可以切换单位 xff08 但是要右击按着欸 xff0c 有一定失败概率 xff09 JC可以查元件位号 F6可以进行矩形的元件摆放 按shift 是可以多选 TM
  • 【五一创作】微服务学习笔记

    微服务学习 写一个服务的步骤一般可以有 1 xff0c 在pom xml文件中导入相关的依赖 2 xff0c 编写相关的配置类 xff08 application yml xff09 配置类编写的三步 1 服务的端口 2 服务的名字 3 服
  • Win10启动或关闭windows功能,一直显示“请稍后”该怎么办?(win10请稍后)

    解决方法一 xff1a 1 按下 Win 43 R 组合键呼出运行 xff0c 输入 xff1a services msc 点击确定打开服务 xff1b 2 在服务界面中双击打开 Windows Modules Installer xff0
  • ROS2 CmakeList如何正确引入第三方.so文件

    在使用ros2开发的时候难免会需要引入第三方的厂家提供的 so文件库 注意这里说的并不是自己写的cpp文件转成 so然后再自己的工程项目中使用 例如经常使用的ICANCmd h头文件和libCanCmd so库还有onnx推理的时候onnx