如何在ROS功能包创建.h文件,并在另一个功能包里引用这个功能包的.h文件——详细说明及步骤

如何在ROS的一个功能包里引用另外一个功能包的.h文件

摸索了好几天,查阅了很多都没有一个准确的教程,经过我不断地测试,终于找到正确的打开方式了!!!比如我们现在要在B package 引用A package下的example.h文件

一、正确创建.h文件并编译生成链接库

.h文件的正确摆放

首先,因为在ROS的功能包里其实是可以同时存在多个节点的,但是你会发现自动生成功能包时,官方对于cmakelist.txt中的可执行文件的命名都是${PROJECT_NAME}_node,这其实已经在提示我们,你在src里面写的带main函数的.cpp文件应该是一个创建节点的包含ros::init的主入后。所以这里我对于网上所有关于ROS的教程中,在cmakelist.txt文件中的${PROJECT_NAME}_node名称改为实际.cpp文件的名字表示意见保留,我觉得你的某个ROS节点文件就命名为${PROJECT_NAME}_node挺好的。如果实在有多个节点,再额外带下标加以区分即可。
另外,在大型工程的src里,创建ROS节点的.cpp文件一般都不长,会在其中调用其他.cpp文件内的函数来进行相关操作,这其实形成了一种良好的生态,因为我可以直接把别人写好的实现某些操作的不带main函数的.cpp直接拷贝到我的src目录下,然后自己创建个简单的ros节点文件,就能够实现对相关函数的调用了。
这种调用,一般是通过#include来实现的。比如我们在功能包A_package中的src目录下,现在有一个example.cpp,我创建了一个test.cpp初始化ROS节点。接下来需要:

  1. 删除example.cpp文件的main函数,将其中内容改成子函数形式,包含头文件#include
  2. 创建一个example.h文件,必须放在A_package\include\A_package\路径下,example.h的编写规则这里省略,需注意声明需要使用到的example.cpp文件里的函数。

编辑cmakelist.txt文件

网上一般的教程都没考虑ROS可执行文件和链接库的区别,所以都统一命名了,但其实里面是有讲究的。
首先,对于一个不需要在其他功能包调用此功能包内容的情况下,我们只需要打开那两行注释即可

add_executable(${PROJECT_NAME}_node 
						src/test.cpp
				        src/example.cpp
						)
target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)

这里catkin_make编译通过后会出现一行

 [100%] Built target A_package_node

如果你引用了example.h文件,还需要额外加两行

catkin_package(
 INCLUDE_DIRS include
 CATKIN_DEPENDS roscpp rospy std_msgs
)
include_directories(
  SYSTEM
  include
  ${catkin_INCLUDE_DIRS}
	# ${OpenCV_INCLUDE_DIRS}
	# ${PCL_INCLUDE_DIRS}
	# ${Eigen3_INCLUDE_DIRS}
)

其中catkin_package的具体写法可以参照我的上一篇博客。

但是,当你想要在其他功能包里调用这个example.h文件时,你需要在额外生成一个c++的链接库。也就是最关键的一步。

  1. 额外添加两行
add_library( A_package
  src/example.cpp
)

target_link_libraries( A_package
  ${catkin_LIBRARIES}
  # ${PCL_LIBRARIES}
  # ${Eigen3_LIBRARIES}
  # ${OpenCV_LIBS}
)
  1. 命名是关键,你可以注意到我这里没有用example来命名,而使用了A_package,这是因为这个名字必须要和package.xml里面的The A_package package保持一致!
  2. 解释一下,add_library相当于将 src/example.cpp转换为一个链接库,库的名字是A_package,以方便别人的调用。target_link_libraries是这个将要生成的库所需要依赖的库,其中${catkin_LIBRARIES}是对应上面的
catkin_package(
 INCLUDE_DIRS include
 LIBRARIES A_package
 CATKIN_DEPENDS roscpp rospy std_msgs
)

此时catkin_make编译通过后会额外出现一行

 [100%] Built target A_package

二、正确的调用姿势

前面相当于对于test.cpp生成了一个名为A_package_node的可执行文件,对于example.cpp生成了一个链接库,通过这个链接库可以调用example.h

  1. 在B_package功能包中的某个.cpp或者.h中 #include
  2. 在B_package的cmakelist.txt中添加一行
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  A_package
)

这里的“A_package”就是对应前面生成的c++链接库的名字。

  1. 再添加一行
catkin_package(
 INCLUDE_DIRS include
  LIBRARIES B_package
 CATKIN_DEPENDS roscpp rospy std_msgs
 CATKIN_DEPENDS A_package
)

其中CATKIN_DEPENDS 就是说会依赖A_package,相当于调用了。

  1. B_package的package.xml中添加三行
 A_package
 A_package
 A_package

这里三个A_package对应上cmakelist.txt里新添的链接库名字。
如何在ROS功能包创建.h文件,并在另一个功能包里引用这个功能包的.h文件——详细说明及步骤_第1张图片

最后,这种调用最好放在同一个文件夹下以便于管理。我个人习惯一个功能包只有一个节点,查询起来比较清晰,也方便移植,我想要使用哪个节点,就直接拷贝相应的功能包就可以编译了。当然,弊端也很明显,就是数据类型的传递,在一个功能包下的src可以方便的include,以传递class,也就直接避开了本篇博客所解决的不同功能包之间互相调用的问题。

所以,如果你拿到了一份ROS包装的代码,那肯定是若干个功能包,可以在本篇博客的基础上二次开发;
如果你拿到了一份纯c++代码,那就可以在上一篇博客的基础上二次开发。

你可能感兴趣的:(ROS,机器人,c++,linux)