ROS自定义动态链接库并调用
1 前言
在之前已经给出了创建共享库的方法,但是直接应用到ROS还是有一些问题。因此,本文主要解决ROS中创建及使用共享库的方法。包含以下内容:
- 原汁原味的catkin_make建立共享库以及调用;
- 使用catkin_simple来简化CMakeLists.txt,实现同样的效果,调试更简单。(推荐使用)
- 工程源码见:
2 创建共享库
2.1 使用原生 CMakeLists.txt
首先在工作空间创建包 creating_a_ros_library
:1
catkin_create_pkg creating_a_ros_library roscpp std_msgs std_srvs
然后添加以下文件到工程中,目录如下:1
2
3
4
5
6
7
8
9.
├── CMakeLists.txt
├── include
│ └── creating_a_ros_library
│ └── example_ros_class.h
├── package.xml
└── src
├── example_ros_class.cpp
└── example_ros_class_test_main.cpp
说明:
example_ros_class.cpp
是用来创建共享库的文件,而example_ros_class_test_main.cpp
则是在本工程中调用共享库的主程序。
点击查看`example_ros_class.h`文件内容
1 | // example_ros_class.h header file // |
点击查看`example_ros_class.cpp`文件内容
1 | //example_ros_class.cpp: |
CMakeLists.txt
中需要修改两处:
- 将
include_directories()
中的include
取消注释(大约120行); - 添加以下内容:
1
2
3add_library(example_ros_library SHARED src/example_ros_class.cpp) # 生成的库在devel/lib目录下
add_executable(${PROJECT_NAME} src/example_ros_class_test_main.cpp)
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} example_ros_library)
点击查看`example_ros_class_test_main.cpp`文件内容
1 |
|
编译方法:1
2cd catkin_ws
catkin_make
在编译完成后,会在catkin_ws/devel/lib/
目录下生成libexample_ros_library.so
;在在catkin_ws/devel/lib/creating_a_ros_library/
目录下生成creating_a_ros_library
可执行文件(node)。
测试:1
2
3roscore
# open a new terminal
rosrun creating_a_ros_library creating_a_ros_library
输出结果:1
2
3
4
5
6[ INFO] [1661084062.326018473]: main: instantiating an object of type ExampleRosClass
[ INFO] [1661084062.326405817]: in class constructor of ExampleRosClass
[ INFO] [1661084062.326451901]: Initializing Subscribers
[ INFO] [1661084062.327675835]: Initializing Publishers
[ INFO] [1661084062.327898970]: Initializing Services
[ INFO] [1661084062.328322949]: main: going into spin; let the callbacks do all the work
2.2 其他工程调用共享库
创建一个新包using_a_ros_library
用来调用共享库。先说一下思路:直接调用creating_a_ros_library
包,但是这里用using_a_ros_library
来调用,因此需要将creating_a_ros_library
先导出,导出的方法就是,在creating_ros_library/CMakeLists.txt
中取消注释.1
2
3
4
5
6catkin_package(
# creating_a_ros_library中的这里要取消注释,非常重要!大约106行
INCLUDE_DIRS include
# LIBRARIES creating_a_ros_library
CATKIN_DEPENDS roscpp std_msgs std_srvs
# DEPENDS system_lib
再进行编译及生成新包。1
2
3
4cd ~/catkin_ws
catkin_make
cd ~/catkin_ws/src
catkin_create_pkg using_a_ros_library roscpp std_msgs std_srvs creating_a_ros_library
注意这里直接将包creating_a_ros_library
添加进去,就不用在package.xml
中再添加依赖项了。
将上一小节的example_ros_class_test_main.cpp
复制到该包中,无需修改。该包的目录如下:1
2
3
4
5
6
7
8
9using_a_ros_library
├── CMakeLists.txt
├── include
│ └── using_a_ros_library
├── package.xml
└── src
└── example_ros_class_test_main.cpp
3 directories, 3 files
CMakeLists.txt
中需要修改的地方:1
2
3
4
5
6
7
8
9
10catkin_package(
# INCLUDE_DIRS include
# LIBRARIES using_a_ros_library
# 取消下一行注释,非常重要!!!大约106行
CATKIN_DEPENDS creating_a_ros_library roscpp std_msgs std_srvs
# DEPENDS system_lib
)
add_executable(${PROJECT_NAME} src/example_ros_class_test_main.cpp)
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} example_ros_library)
修改完成后,编译及运行:1
2
3
4
5cd ~/catkin_ws
catkin_make
roscore
# open a new terminal
rosrun using_a_ros_library using_a_ros_library
输出结果如下:1
2
3
4
5
6[ INFO] [1661091625.379485178]: main: instantiating an object of type ExampleRosClass
[ INFO] [1661091625.380032496]: in class constructor of ExampleRosClass
[ INFO] [1661091625.380056233]: Initializing Subscribers
[ INFO] [1661091625.381107898]: Initializing Publishers
[ INFO] [1661091625.381327092]: Initializing Services
[ INFO] [1661091625.381558026]: main: going into spin; let the callbacks do all the work
可以看到结果与上节一致。
3 使用catkin_simple来创建库
3.1 catkin_simple使用
catkin_simple
是ETH为了简化ROS的冗余CMakeLists.txt
而开发的工具。关于该工具的说明可以参考:
1 | cd catkin_ws/src |
上述代码的最后一行会让当前终端识别cs_create_pkg
,为了能在所有终端中都能使用,采用以下方法:
1 | sudo gedit ~/.bashrc |
打开上述文件后添加alias cs_create_pkg='~/catkin_ws/src/learning_ros_external_packages/cs_create_pkg.py'
,最后再进行1
source ~/.bashrc
3.2 创建库并调用
1 | cs_create_pkg cs_creating_a_ros_library roscpp std_msgs std_srvs |
向工程中添加文件,目录为:1
2
3
4
5
6
7
8
9
10.
├── CMakeLists.txt
├── include
│ └── cs_creating_a_ros_library
│ └── example_ros_class.h
├── package.xml
├── README.md
└── src
├── example_ros_class.cpp
└── example_ros_class_test_main.cpp
其中,example_ros_class.h
和 example_ros_class.cpp
第2节中的一致,直接复制即可。将2.1节中example_ros_class_test_main.cpp
首行修改如下,即调用自己的包。1
点击查看`CMakeLists.txt`的内容
1 | cmake_minimum_required(VERSION 2.8.3) |
值得注意的有:
- 上述代码的catkin_simple()会调用find_package(),并将本文件夹下的include 和 catkin包含的头文件目录include_directories调用,等价于第二节。
- 值得一提的是,cs_export() 对应到原CMakeLists.txt中的 catkin_package(),所以这里已经直接导出了cs_creating_a_ros_library包。
编译:1
2cd ~/catkin_ws
catkin_make
编译完成后,在~/catkin_ws/devel/lib/
目录下生成了libcs_example_ros_library.so
,在~/catkin_ws/devel/lib/cs_creating_a_library/
目录下生成了cs_ros_library_test_main
节点。
测试:
执行1
2roscore
rosrun cs_creating_a_ros_library cs_ros_library_test_main
输出结果如下:1
2
3
4
5
6[ INFO] [1661085557.379182902]: main: instantiating an object of type ExampleRosClass
[ INFO] [1661085557.379707676]: in class constructor of ExampleRosClass
[ INFO] [1661085557.379718645]: Initializing Subscribers
[ INFO] [1661085557.380861942]: Initializing Publishers
[ INFO] [1661085557.381083735]: Initializing Services
[ INFO] [1661085557.381317748]: main: going into spin; let the callbacks do all the work
可见,结果与上一节的一致。
3.3 外部工程调用共享库
1 | cd ~/catkin_ws/src |
注意最后包含了 cs_creating_a_ros_library,这里导致在
package.xml
中包含了对cs_creating_a_ros_library
的依赖,这使得在CMakeLists.txt中无须再通过cs_target_link()来添加已经生成的libcs_example_ros_library.so
。
工程目录:1
2
3
4
5
6
7cs_creating_a_ros_library
├── CMakeLists.txt
├── include
├── package.xml
├── README.md
└── src
└── example_ros_class_test_main.cpp
直接将 3.2 节的example_ros_class_test_main.cpp
复制即可,无需修改。在CMakeLists.txt
中,仅需添加1
cs_add_executable(cs_ros_library_extern_test src/example_ros_class_test_main.cpp)
编译及测试:1
2
3
4
5cd ~/catkin_ws
catkin_make
roscore
# open a new terminal
rosrun cs_using_a_ros_library cs_ros_library_extern_test
结果如下:1
2
3
4
5
6[ INFO] [1661086647.935522480]: main: instantiating an object of type ExampleRosClass
[ INFO] [1661086647.936067988]: in class constructor of ExampleRosClass
[ INFO] [1661086647.936079118]: Initializing Subscribers
[ INFO] [1661086647.937107125]: Initializing Publishers
[ INFO] [1661086647.937326156]: Initializing Services
[ INFO] [1661086647.937551842]: main: going into spin; let the callbacks do all the work
可以看到结果与前述结果一致。
4 总结
本文第2.1节创建了一个动态链接库,并在自己的package中进行了调用;第2.2节创建了一个新pkg来调用2.1节的pkg中的动态链接库。
而第3节则简介了catkin_simple
,并用气实现了自定义链接库的生成和调用。经过对比,建议使用catkin_simple
来管理CMakeLists.txt,确实可以大幅简化,对于不熟悉的开发人员可以提速。