ROS 编译package ,Cmakelist 等一些笔记

时隔几个月重新回来写一篇笔记,总结一下

主要几个部分: Cmakelist的一些用法和小技巧,ROS 名称 和remap的概念理解


安装依赖

rosdep install --from-paths src --ignore-src --rosdistro=kinetic -y

CMakeList 输出全部的参数

有些时候在调试的时候需要查看Cmake的一些变量的值,可以在CMakeList文件中定义一个宏 print_all_variables,在CmakeList文件最后使用,就可以在编译的时候输出所有的变量的值,方便调试

macro(print_all_variables)
    message(STATUS "print_all_variables------------------------------------------{")

    get_cmake_property(_variableNames VARIABLES)
    foreach (_variableName ${_variableNames})
        message(STATUS "${_variableName}=${${_variableName}}")
    endforeach()
    message(STATUS "print_all_variables------------------------------------------}")
endmacro()

关于CMakeList文件中的Catkin_make()宏

https://docs.ros.org/groovy/api/catkin/html/dev_guide/generated_cmake_api.html#catkin-package

我相信不少小伙伴初次看ROS wiki的教程时会对这个Cmakelist文件中定义的宏catkin_package()有疑问,有的时候你会发现,这个宏里面写不写东西好像我的package都能正常编译和运行,那么这个宏到底是干嘛用的呢,什么时候非用它不可呢?

很简单,只要记住一点,这个宏不是为了你正在编写的包存在的,而是为了其他要使用你这个包的包而存在的,也就是说只有其他包在使用你的这个包时,里面定义的东西才会起作用

你可以把它简单理解成一个导出的关于你这个包的一些配置文件的宏,用来定义和描述你的这个包

The catkin_package macro generates cmake config files for your package
Declare things to be passed to dependent projects
# 为你的package 生成cmake config文件(方便其他使用你的包的程序),声明要传递给依赖这个包的项目的一些信息
INCLUDE_DIRS: 如果你的package中有头文件的话
LIBRARIES:  如果你在这个package中生成了某些lib,而其他包在使用你的包时,又必须使用这个lib,那么就要添加这一项
CATKIN_DEPENDS: 其他包在使用你的包时必须要依赖的一些catkin_package,同时也是你这个包需要的依赖
DEPENDS: 其他包在使用你的包时必须要依赖的一些系统依赖,同时也是你这个包需要的依赖

CmakeList中的find_package是用来查找你的包中要用的依赖,而查找的东西就是cmake 的配置文件,假设现在有其他人想要用你的包,那么他肯定要用 find_package(catkin REQUIRED your_package),而这条语句要查找的就是你用catkin_make()宏生成的config文件

必须不能为空的情况之一:生成自定msg,srv等

find_package(catkin REQUIRED COMPONENTS message_generation std_msgs sensor_msgs)
generate_messages(DEPENDENCIES std_msgs sensor_msgs)
catkin_package(
   CATKIN_DEPENDS message_runtime std_msgs sensor_msgs
  )
 # define executable using MyMessage1 etc. 如果你的package要用到你在包中自定义的message,那么要添加 ${${PROJECT_NAME}_EXPORTED_TARGETS} #
  add_executable(message_program src/main.cpp)
  add_dependencies(message_program ${${PROJECT_NAME}_EXPORTED_TARGETS} 
  ${catkin_EXPORTED_TARGETS})

  # define executable not using any messages/services provided by this package
  add_executable(does_not_use_local_messages_program src/main.cpp)
  add_dependencies(does_not_use_local_messages_program ${catkin_EXPORTED_TARGETS})

假如你的包A定义了msg,通过message_generation 生成了你要的message,包B要用A,则包B要有find_package(A),但是包B不需要知道一些A的message的相关消息,B也不需要生成message,但是只要涉及到message存在,就必须要有message_runtime这个包,此时就需要A中定义catkin_package(message_runtime),这样,B在find_package(A)的时候,自动的把message_runtime包含进去,这样就不需要在B中显示的引入这个包.

CMakeList 的一般理解

既然是为了要编译一个package,那么只要记住要干什么就行了

1:第一步,要用到什么包,要用到什么库,那么就需要寻找这些依赖,find_package(),经过此步,Cmake生成一些系统变量:

如果CMake通过find_package找到一个包,则会自动生成有关包所在路径的CMake环境变量,环境变量描述了包中头文件的位置,源文件的位置,包所依赖的库以及这些库的路径。
这些变量名称以< PACKAGE NAME >_< PROPERTY >的形式出现:
< NAME >_FOUND - 如果找到库,则设置为true,否则为false
< NAME > _INCLUDE_DIRS或 _INCLUDES - 包导出的包含路径
< NAME > _LIBRARIES或 _LIBS - 由包导出的库
< NAME > _DEFINITIONS - ?
- …

include_DIRS是用来找include文件的,而_LIBS是用来找库文件的,有了这两个,我们就可以进行下面的步骤

2:第二步 include_directories(include ${Boost_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS}) ,这样就将头文件都包括进去,

对连接库,cmakelist里面有link_directories(~/my_libs),但是这个一般不用,而直接用后面的targetlink(..)

3:第三步 要创建一些自定义的message,上面的find_package(message_generation std_msgs ...等等msg),这里调用宏来生成message,generate_messages(DEPENDENCIES std_msgs sensor_msgs)

4:第四步,定义导出信息catkin_package()

接下来就是实际的编译设置

5.加入我们有生成一个lib,那么我们首先有

add_library(${PROJECT_NAME} src/sth.cpp)
target_link_libraries(${PROJECT_NAME}
  ${XXX_LIBRARIES}
  ${XXX_LIBRARIES}
  ${catkin_LIBRARIES}
)

6.可执行文件

add_executable(${PROJECT_NAME}_node XXX.cpp  XXX2.cpp)
target_link_libraries(${PROJECT_NAME}_node
  ${PROJECT_NAME}   #自定义的包中的lib
  ${avcodec_LIBRARIES}
  ${swscale_LIBRARIES}
  ${catkin_LIBRARIES}
)

特别注意的是,对于涉及到生成message的package,一定要添加add_dependencies(),具体可参考上面的msg,srv情况,这是为了保证在编译时按正确的顺序编译,避免产生错误.通常这句是默认添加

add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

下面这些摘自ROS wiki

  • If you have a target which (even transitively) depends on some other target that needs messages/services/actions to be built, you need to add an explicit dependency on target catkin_EXPORTED_TARGETS, so that they are built in the correct order. This case applies almost always, unless your package really doesn't use any part of ROS. Unfortunately, this dependency cannot be automatically propagated. (some_target is the name of the target set by add_executable()):

 add_dependencies(some_target ${catkin_EXPORTED_TARGETS})
  • If you have a package which builds messages and/or services as well as executables that use these, you need to create an explicit dependency on the automatically-generated message target so that they are built in the correct order. (some_target is the name of the target set by add_executable()):

  add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS})
  • If you your package satisfies both of the above conditions, you need to add both dependencies, i.e.:

add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

ROS Name 和 Remap

nh("/name")==>/name/..  ns设置无效

---以/ns/node_name/作为前缀----

nh("~") ==>/ns/node_name/..

nh("~name") ==>/ns/node_name/name/...

私有名称对于通过参数服务器将参数传递到特定节点很有用

----以/ns/作为前缀

nh ==> /ns/..

nh("name") ==> /ns/name/.... 

ns默认为"/ ",可以用户自定义 

注意,这是以nh为函数句柄解析得得到的名称,  节点的名称为 只有/ns/node_name这一种

对于remap ,ROS采用的是在匹配前先进行解析的策略,也就是说你remap的是一个 full name(完整的名字)

一个node里面可以有几个nodehandle ,用nh("~")创建的参数是私有参数

在解析参数的时候同样遵循这些规则,所以在做重映射的时候要注意

http://wiki.ros.org/cn/ROS/Tutorials/UnderstandingNodes ROS 关于节点的概念的介绍


 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值