单个功能包的组织形式

一个功能包必须包含如下的两个文件:

  • package.xml

  • CMakeLists.txt
    并且,每一个功能包必须拥有自己的文件夹。
    一般而言,我们会在功能包下面再创建一个src文件夹用于存放源代码,这一步骤不一定是必须手动操作的,因为如果你是通过catkin_create_pkg命令创建的package,那么该命令会自动创建好src文件夹,而如果你是在Qt Creator中通过ros-qtc-plugin插件进行package开发的话,那么就需要用户手动创建src文件夹了,虽然这一步不是必须的,但是从规范化的角度来看还是很有必要的,特别是当项目比较复杂的时候,节点比较多的时候,源文件是比较多的,各种文件糅合在一个文件夹中是非常难看,不方便管理的。

package01/
		package.xml
		CMakeLists.txt
		src/
		    node01.cpp
		    node02.cpp
		  ...

过个功能包在工作空间中的组织形式

catkin_ws/
		src/
			CMakeLists.txt
			package01/
					CMakeLists.txt
					package.xml
					src/
						node01.cpp
						node02.cpp
						...
			package02/
					CMakeLists.txt
					package.xml
					src/
						node01.cpp
						node02.cpp
						...
			...
			package0n/
					CMakeLists.txt
					package.xml
					src/
						node01.cpp
						node02.cpp
						...

创建一个功能包并构建它

创建一个功能包的前提是必须创建了一个catkin工作空间,而我们的功能包就是在工作空间中创建的,因此在进行如下操作的时候,默认是已经创建好了一个catkin功能包:

cd catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
cd ..
catkin_make

创建功能包的命令格式如下:

catkin_create_pkg package_name [depends1] [depends2] [pdends3] ...

其中package_name是我们要创建的功能包的名称,而depends1, depends2, ...等是该功能包的依赖包。
最后,别忘了source一下的你工作空间中的devel/setup.bash文件,这样就把当前的工作空间添加进ROS的环境中。
执行如下的命令,source一下catkin_ws工作空间,前提是你的当前终端停留在~/catkin_ws下:

source devel/setup.bash

功能包的依赖关系

就上面的我们创建的功能包为例,我们来学习功能包的依赖关系。

我们用rospack depends1来输出上面创建的功能包的第一层次依赖关系,也叫作直接依赖关系:

cd ~/Desktop/catkin_ws
source devel/setup.bash
rospack depends1 beginner_tutorials

输出结果为:

liuqiang@liuqiang-pc:~/Desktop/catkin_ws$ rospack depends1 beginner_tutorials
roscpp
rospy
std_msgs

检测直接依赖关系roscpp的直接依赖关系:

rospack depends1 roscpp

输出结果为:

liuqiang@liuqiang-pc:~/Desktop/catkin_ws$ rospack depends1 roscpp
cpp_common
message_runtime
rosconsole
roscpp_serialization
roscpp_traits
rosgraph_msgs
rostime
std_msgs
xmlrpcpp

假如,我们需要检测我们创建的功能包beginner_tutorials的所有依赖关系(包括直接和间接的依赖关系),那么,我们需要使用如下的命令,幸运的是rospack可以递归地检测出所有嵌套的依赖关系并通过列表输出:

rospack depends beginner_tutorials

输出结果为:

liuqiang@liuqiang-pc:~/Desktop/catkin_ws$ rospack depends beginner_tutorials
cpp_common
rostime
roscpp_traits
roscpp_serialization
catkin
genmsg
genpy
message_runtime
gencpp
genlisp
message_generation
rosbuild
rosconsole
std_msgs
rosgraph_msgs
xmlrpcpp
roscpp
rosgraph
rospack
roslib
rospy

定制我们创建的功能包

可以看出,我们前面通过catkin_create_pkg创建的功能包里面包含了package.xml和CMakeLists.txt文件,而我们要创建自己特定功能的功能包,就需要按照自己的需求来改写这两个文件。

.
├── CMakeLists.txt
├── include
│   └── beginner_tutorials
├── package.xml
└── src

首先,我们来认识一下package.xml文件的内容及其各部分的含义:

<?xml version="1.0"?>
<package>
  <name>beginner_tutorials</name>
  <version>0.0.0</version>
  <description>The beginner_tutorials package</description>
# 上面一句是功能包的描述标签
  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="liuqiang@todo.todo">liuqiang</maintainer>
# 上面一句是功能包维护者邮箱的标签

  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>
# 上面是许可证标签

  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/beginner_tutorials</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


  <!-- The *_depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use build_depend for packages you need at compile time: -->
  <!--   <build_depend>message_generation</build_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use run_depend for packages you need at runtime: -->
  <!--   <run_depend>message_runtime</run_depend> -->
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <buildtool_depend>catkin</buildtool_depend>
  # 上面是构建工具依赖包
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  # 上面是构建依赖功能包
  <run_depend>roscpp</run_depend>
  <run_depend>rospy</run_depend>
  <run_depend>std_msgs</run_depend>
 # 上面是运行依赖功能包

  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

package.xml文件的关键内容提取出来就是:

<?xml version="1.0"?>
<package>
  <name>beginner_tutorials</name>
  <version>0.0.0</version>
  <description>The beginner_tutorials package</description>
  # 上面一句是功能包的描述标签
  <maintainer email="liuqiang@todo.todo">liuqiang</maintainer>
  # 上面一句是功能包维护者邮箱的标签
  <license>TODO</license>
  # 上面是许可证标签
  <buildtool_depend>catkin</buildtool_depend>
  # 上面是构建工具依赖包
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  # 上面是构建依赖功能包
  <run_depend>roscpp</run_depend>
  <run_depend>rospy</run_depend>
  <run_depend>std_msgs</run_depend>
 # 上面是运行依赖功能包
</package>

接着,我们来认识一下CMakeLists.txt,如果我们要构建我们自己的功能包,那么就要按需修改功能包的CMakeLists.txt文件

首先,我们来概览一下CMakeLists.txt文件的结构和顺序:

cmake_minimum_required(VERSION 2.8.3 FATAL_ERROR)
project(beginner_tutorials)
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)
find_package(Boost REQUIRED COMPONENTS thread)
catkin_python_setup()
add_message_files(Message1.msg Message2.msg)
add_service_files(Service1.srv Service2.srv)
add_action_files(Action1.action Action2.action)
generate_messages(DEPENDENCIES std_msgs sensor_msgs)
catkin_package(INCLUDE_DIRS include 
LIBRARIES ${PROJECT_NAME} 
CATKIN_DEPENDS roscpp nodelet 
DEPENDS eigen opencv)

include(${catkin_INCLUDE_DIRS})
add_libraries(${PROJECT_NAME} src/${PROJECT_NAME}/beginner_tutorials.cpp)
add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_executable(${PROJECT_NAME}_node src/beginner_tutorials_node.cpp)
set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(${PROJECT_NAME}_node ${catkin_LIBRARIES})
install(PROGRAMS scripts/my_python_script DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

详细操作,请参阅:http://wiki.ros.org/catkin/CMakeLists.txt

接着,我们来查看一下CMakeLists.txt文件中的内容:

cmake_minimum_required(VERSION 2.8.3)
# 上面指定Cmake最低的版本要求
project(beginner_tutorials)
# 上面给定项目名称
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)
# 上面查找依赖的功能包
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)


## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()

################################################
## Declare ROS messages, services and actions ##
################################################

## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
##   your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
##   * add a build_depend tag for "message_generation"
##   * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
##   * If MSG_DEP_SET isn't empty the following dependency has been pulled in
##     but can be declared for certainty nonetheless:
##     * add a run_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
##   * add "message_generation" and every package in MSG_DEP_SET to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * add "message_runtime" and every package in MSG_DEP_SET to
##     catkin_package(CATKIN_DEPENDS ...)
##   * uncomment the add_*_files sections below as needed
##     and list every .msg/.srv/.action file to be processed
##   * uncomment the generate_messages entry below
##   * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

## Generate messages in the 'msg' folder
# add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# )

## Generate services in the 'srv' folder
# add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# )

## Generate actions in the 'action' folder
# add_action_files(
#   FILES
#   Action1.action
#   Action2.action
# )

## Generate added messages and services with any dependencies listed here
# generate_messages(
#   DEPENDENCIES
#   std_msgs
# )

################################################
## Declare ROS dynamic reconfigure parameters ##
################################################

## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
##   * add a build_depend and a run_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
##   * add "dynamic_reconfigure" to
##     find_package(catkin REQUIRED COMPONENTS ...)
##   * uncomment the "generate_dynamic_reconfigure_options" section below
##     and list every .cfg file to be processed

## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
#   cfg/DynReconf1.cfg
#   cfg/DynReconf2.cfg
# )

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES beginner_tutorials
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
)
# 为功能包生成cmake配置文件
###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)
# 添加头文件
## Declare a C++ library
# add_library(${PROJECT_NAME}
#   src/${PROJECT_NAME}/beginner_tutorials.cpp
# )

## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/beginner_tutorials_node.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )

#############
## Install ##
#############

# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
#   scripts/my_python_script
#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark executables and/or libraries for installation
# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
#   ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
#   RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
#   DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
#   FILES_MATCHING PATTERN "*.h"
#   PATTERN ".svn" EXCLUDE
# )

## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
#   # myfile1
#   # myfile2
#   DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )

#############
## Testing ##
#############

## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_beginner_tutorials.cpp)
# if(TARGET ${PROJECT_NAME}-test)
#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()

## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

构建功能包

source devel/setup.bash
catkin_make

如果把catkin_make分解出来,可以执行如下的命令流:

mkdir build
cd build
cmake ..
make -j4