ROS教程二------创建Package及自定义CMakeList.txt

    创建Packages

1、Packages组成

      catkin工作区的包必须包含三部分:package.xml、CMakeLists.txt以及每个包单独的目录(文件夹)

      最简单的包如下所示的结构:

my_package/
  CMakeLists.txt
  package.xml

 2、CatkinWorkspace中的包

      创建catkin软件包的可以使用catkin工作区自带方法,也可以独立构建catkin软件包。一个简单的工作空间如下所示:

workspace_folder/        -- WORKSPACE
  src/                   -- SOURCE SPACE
    CMakeLists.txt       -- 'Toplevel' CMake file, provided by catkin
    package_1/
      CMakeLists.txt     -- CMakeLists.txt file for package_1
      package.xml        -- Package manifest for package_1
    ...
    package_n/
      CMakeLists.txt     -- CMakeLists.txt file for package_n
      package.xml        -- Package manifest for package_n

     在继续本教程之前,假设按照catkin教程创建一个空的catkin工作区。

 3、创建catkin Package

       本教程将演示使用catkin_create_pkg脚本创建一个新的catkin包,以及在创建之后可以用来做什么。

        首先进入创建的catkin工作区的源空间(src)目录:

$ cd ~/catkin_ws/src

       现在可以使用catkin_create_pkg脚本创建一个名为'beginner_tutorials'的新包,它依赖于std_msgs,roscpp和rospy:

$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

       这将创建一个beginner_tutorials文件夹,其中包含package.xml和CMakeLists.txt,这些文件已填写了给出的依赖信息。

      catkin_create_pkg需要提供package_name以及可选的依赖项列表:

# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]

     catkin_create_pkg还有更高级的功能,这些功能在catkin/commands/catkin_create_pkg中有描述。

  4.构建catkin工作区及获取安装文件 

     首先您需要在catkin工作区中构建包:

$ cd ~/catkin_ws
$ catkin_make

     在构建工作空间之后,在devel子文件夹中创建了一个类似的结构,类是/opt/ros/kinetic(或其他分支)下找到的那样。 

    其次使用生成的安装文件,将工作区添加到ROS环境: 

$ . ~/catkin_ws/devel/setup.bash

  5、package 依赖选项 

    5.1 一阶依赖

             第4步使用catkin_create_pkg创建beginner_tutorials包,提供了一些依赖。可以使用rospack工具查看这些依赖:

$ rospack depends1 beginner_tutorials 

      roscpp
      rospy
      std_msgs

          这些依赖关系存储在package.xml文件中:   

$ roscd beginner_tutorials
$ cat package.xml
    
     <package format="2">
     ...
       <buildtool_depend>catkin</buildtool_depend>
       <build_depend>roscpp</build_depend>
       <build_depend>rospy</build_depend>
       <build_depend>std_msgs</build_depend>
     ...
     </package>

       5.2 间接依赖

             在许多情况下,依赖项也会有自己的依赖项。例如,rospy有其他依赖关系。

$ rospack depends1 rospy
    
     genpy
     roscpp
     rosgraph
     rosgraph_msgs
     roslib
     std_msgs

           一个包有时候会有很多的间接依赖包。可以使用rospack递归地查看所有嵌套依赖项。

$ rospack depends beginner_tutorials

    cpp_common
    rostime
    roscpp_traits
    roscpp_serialization
    catkin
    genmsg
    genpy
    message_runtime
    gencpp
    geneus
    gennodejs
    genlisp
    message_generation
    rosbuild
    rosconsole
    std_msgs
    rosgraph_msgs
    xmlrpcpp
    roscpp
    rosgraph
    ros_environment
    rospack
    roslib
    rospy

     6、自定义包

               本部分将以分析catkin_create_pkg生成的每个文件,逐行解释这些文件的每个组件以及如何自定义包。

            6.1 自定义package.xml

                浏览package.xml,注意需要修改的元素。为了减少篇幅累赘,截取相关部分描述    

            6.1.1 描述标签

 <description>The beginner_tutorials package</description>

                可以将描述标签<description>...<description>的内容改为需要的内容,按照惯例,应该简短,同时涵盖包的范围。

            6.1.2 维护者标签

 <!-- One maintainer tag required, multiple allowed, one person per tag --> 
 <!-- Example:  -->
 <!-- <maintainer email="liqfqq@163.com">飞越疯人院</maintainer> -->
 <maintainer email="liqfqq@163.com">飞越疯人院</maintainer>

             这是package.xml的必需且重要的标记,因为它允许其他人知道有关该包的联系人。至少需要一个维护者,可以有很多。

           6.1.3 许可证标签

<!-- 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>以上的许可即可</license>

           6.1.4 依赖标签

             标记描述了包的依赖关系。依赖项分为build_depend,buildtool_depend,exec_depend,test_depend。有关这些标记的更详细说明,请参阅有关Catkin依赖关系的文档。由于我们将std_msgs,roscpp和rospy作为catkin_create_pkg的参数传递,因此依赖关系将如下所示:

  <!-- 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>genmsg</build_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <!--   <exec_depend>python-yaml</exec_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>

            除了catkin上的默认buildtool_depend之外,我们列出的所有依赖项都已添加为build_depend。在这种情况下,我们希望所有指定的依赖项在构建和运行时都可用,因此我们也将为每个依赖项添加一个exec_depend标记: 

 <buildtool_depend>catkin</buildtool_depend>

  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

      6.1.5 最后 package.xml

          最终package.xml:

<?xml version="1.0"?>
<package format="2">
  <name>beginner_tutorials</name>
  <version>0.1.0</version>
  <description>The beginner_tutorials package</description>

  <maintainer email="liqfqq@163.com">飞越疯人院</maintainer>
  <license>BSD</license>
  <url type="website">http://wiki.ros.org</url>
  <author email="liqfqq@163.com">飞越疯人院</author>

  <buildtool_depend>catkin</buildtool_depend>

  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

</package>

  6.2 自定义CMakeLists.txt

       CMakeLists.txt是用于构建软件包的CMake构建系统的输入文件。任何符合CMake的包都包含一个或多个CMakeLists.txt文件,该文件描述了如何构建代码以及将代码安装到何处。

     6.2.1 整体结构和自定义

        CMakeLists.txt文件必须遵循此格式,否则您的包将无法正确构建。配置中按以下顺序配置:

  1. Required CMake Version (cmake_minimum_required)

  2. Package Name (project())

  3. Find other CMake/Catkin packages needed for build (find_package())

  4. Enable Python module support (catkin_python_setup())

  5. Message/Service/Action Generators (add_message_files(), add_service_files(), add_action_files())

  6. Invoke message/service/action generation (generate_messages())

  7. Specify package build info export (catkin_package())

  8. Libraries/Executables to build (add_library()/add_executable()/target_link_libraries())

  9. Tests to build (catkin_add_gtest())

  10. Install rules (install())

     6.2.2  CMake版本 

         每个catkin的CMakeLists.txt文件必须以所需的CMake版本开头。Catkin需要cmake的版本至少是2.8.3或更高版本。

cmake_minimum_required(VERSION 2.8.3)

    6.2.3 Package name

         CMake项目函数指定的包的名称。现在以robot_brain的软件包为例:

project(robot_brain)

    6.2.4 寻找相关的CMake包    

         使用find_package函数指定需要找到哪些包来构建项目。catkin总是至少有一个依赖:

find_package(catkin REQUIRED)

      如果项目依赖于其他wet packages,它们会自动变成catkin的组件(就CMake而言)。而不是在这些包上使用find_package,如果将它们指定为组件,它将使构建系统快速构建。例如使用包nodelet:

find_package(catkin REQUIRED COMPONENTS nodelet)

     相当于:这样是相当麻烦的

find_package(catkin REQUIRED)
find_package(nodelet REQUIRED)

   6.2.4.1 find_package()的作用

      如果CMake通过find_package找到包,则会导致创建多个CMake环境变量,这些变量提供有关包的信息。然后可以在CMake脚本中使用这些环境变量。

    环境变量描述了包导出头文件所在的位置,源文件所在的位置,包所依赖的库以及这些库的路径。名称遵循<PACKAGE NAME> _ <PROPERTY>的约定:

  • <NAME>_FOUND - Set to true if the library is found, otherwise false

  • <NAME>_INCLUDE_DIRS or <NAME>_INCLUDES - The include paths exported by the package

  • <NAME>_LIBRARIES or <NAME>_LIBS - The libraries exported by the package

  • <NAME>_DEFINITIONS - ?

6.2.4.2 为什么Catkin包被指定为组件

    Catkin包不是catkin的真正组成部分。相反,CMake的组件功能被用于catkin的设计,以节省大量的编程时间。

     对于catkin包,如果使用find_package包含所需要的包,作为catkin的组件,这是有利的,因为使用catkin_前缀创建了一组环境变量,以便将这些包包含到环境变量中去,节省时间。例如,假设您在代码中使用了包nodelet。寻找包的推荐方法是:

find_package(catkin REQUIRED COMPONENTS nodelet)

       这样做的好处是nodelet导出的包含路径,库等也会附加到catkin_变量。例如,catkin_INCLUDE_DIRS不仅包含catkin的包含路径,还包含nodelet的包含路径!这将在后续使用中提供便利。 

       当然我们也可以手动find_package nodelet:

find_package(nodelet)

        如果手动添加的话不会将nodelet路径,库等添加到catkin_变量中。

  6.2.4.3 Boost线程

       如果使用C ++和Boost,则需要在Boost上调用find_package()并指定您正在使用的Boost的哪些方面作为组件。例如,如果你想使用Boost线程,例如:

find_package(Boost REQUIRED COMPONENTS thread)

6.2.5 catkin_package()

    catkin_package()是一个catkin提供的CMake宏。为构建系统指定catkin信息所必需的,catkin又用于生成pkg-config和CMake文件。

     在使用add_library()或add_executable()声明任何目标之前,必须调用此函数。该函数有5个可选参数:

  • INCLUDE_DIRS - The exported include paths (i.e. cflags) for the package

  • LIBRARIES - The exported libraries from the project

  • CATKIN_DEPENDS - Other catkin projects that this project depends on

  • DEPENDS - Non-catkin CMake projects that this project depends on. For a better understanding, see this explanation.

  • CFG_EXTRAS - Additional configuration options

  • 完整的宏文档here.

catkin_package(
   INCLUDE_DIRS include
   LIBRARIES ${PROJECT_NAME}
   CATKIN_DEPENDS roscpp nodelet
   DEPENDS eigen opencv)

  CMake环境变量$ {PROJECT_NAME}是之前传递给project()函数的内容

6.2.6 指定构建目标

    构建目标可以采用多种形式,但通常它们代表两种可能性之一:

  • Executable Target - programs we can run
  • Library Target - libraries that can be used by executable targets at build and/or runtime

  6.2.6.1 目标命名

     catkin中的构建目标的名称必须是唯一的。这是CMake的要求。但是,目标的唯一名称仅在CMake内部是必需的。可以使用set_target_properties()函数将目标重命名为其他目标:

set_target_properties(rviz_image_view
                      PROPERTIES OUTPUT_NAME image_view
                      PREFIX "")

      构建和安装输出中将目标rviz_image_view的名称更改为image_view。 

  6.2.6.2 自定义输出目录

       一般可执行文件和库的默认输出目录通常设置为合理的值,特殊情况下必须自定义。如包含Python绑定的库必须放在不同的文件夹中,以便可以在Python中导入:

set_target_properties(python_module_library
  PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION})

 6.2.6.3 Include Paths and Library Paths

   在编译目标之前,需要指定可以为所述目标找到资源的位置,特别是头文件和库:

  • Include Paths - Where can header files be found for the code (most common in C/C++) being built
  • Library Paths - Where are libraries located that executable target build against?
  • include_directories(<dir1>, <dir2>, ..., <dirN>)

  • link_directories(<dir1>, <dir2>, ..., <dirN>)

   6.2.6.3.1 include_directories()

      include_directories的参数是find_package调用生成的* _INCLUDE_DIRS变量以及需要包含的任何其他目录。如果使用catkin和Boost,则include_directories()调用应如下所示:

include_directories(include ${Boost_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS})

      第一个参数“include”表示包中的include /目录也是路径的一部分。

  6.2.6.3.2  link_directories()

      link_directories()函数可用于添加其他库路径,但不建议这样做。所有catkin和CMake软件包在find_packaged时自动添加其链接信息。只需链接到target_link_libraries()中的库

link_directories(~/my_libs)

Please see this cmake thread to see a detailed example of using target_link_libraries() over link_directories().

   6.2.7  Executable Targets

      构建可执行目标,必须使用add_executable()CMake函数

add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)

      构建一个名为myProgram的目标可执行文件,它由3个源文件构成:src / main.cpp,src / some_file.cpp和src / another_file.cpp。 

   6.2.8  Library Targets

      add_library()函数用于指定要构建的库。默认情况下,catkin构建共享库。

add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})

   6.2.9 target_link_libraries

      使用target_link_libraries()函数指定可执行目标链接的库。这通常在add_executable()调用之后完成。添加$ {catkin_LIBRARIES}

Syntax:
target_link_libraries(<executableTargetName>, <lib1>, <lib2>, ... <libN>)


add_executable(foo src/foo.cpp)
add_library(moo src/moo.cpp)
target_link_libraries(foo moo)  -- This links foo against libmoo.so

  注意,在大多数用例中不需要使用link_directories(),因为该信息是通过find_package()自动引入的。

 

   7、Messages, Services, and Action Targets

     ROS中的消息(.msg),服务(.srv)和操作(.action)文件在构建和使用ROS包之前需要特殊的预处理器进行预处理,将这些宏生成特定于编程语言的文件,以便所选编程语言中可以使用这些消息,服务和操作。构建系统将使用所有可用的生成器(例如gencpp,genpy,genlisp等)生成绑定。提供了三个宏来分别处理消息,服务和操作:

  • add_message_files

  • add_service_files

  • add_action_files

     必须在调用以上生成的宏之后,在调用下边的宏:

 generate_messages()

   7.1 Important Prerequisites/Constraints(重要的先决条件/限制)

       以上4个宏必须在catkin_package()宏之前,以便正常工作。

 find_package(catkin REQUIRED COMPONENTS ...)
 add_message_files(...)
 add_service_files(...)
 add_action_files(...)
 generate_messages(...)
 catkin_package(...)
 ...

     catkin_package( )宏必须对message_runtime具有CATKIN_DEPENDS依赖关系。

catkin_package(
 ...
 CATKIN_DEPENDS message_runtime ...
 ...)

  必须将find_package()包含messagesegeneration,可以单独使用,也可以作为catkin的一个组件使用:

find_package(catkin REQUIRED COMPONENTS message_generation)

   package.xml文件必须包含对message_generation的构建依赖关系以及对message_runtime的运行时依赖性。如果依赖性是从其他包传递的,那么这不是必需。

    构建的目标(或者传递)依赖于需要构建消息/服务/操作,则需要使用catkin_EXPORTED_TARGETS添加显式依赖项,以便它们以正确的顺序构建。除非软件包确实不使用ROS的任何部分,否则这种情况几乎总是适用。然而这种依赖关系不能自动传播。(some_target是add_executable()设置的目标的名称):

  add_dependencies(some_target ${catkin_EXPORTED_TARGETS})

   如果需要构建消息或服务的包以及使用这些消息的可执行文件,则需要在自动生成的消息目标上创建显式依赖项,以便以正确的顺序构建它们。(some_target是add_executable()设置的目标的名称):

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

 如果包满足上述两个条件,则需要添加两个依赖项

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

   7.2 Example

        软件包名为“msg”的目录中有名为“MyMessage1.msg”和“MyMessage2.msg”的两条消息,并且这些消息依赖于std_msgs和sensor_msgs;名为“srv”的目录中的有服务名为“MyService.srv”,定义使用这些消息和服务的有两个分别名为可执行message_program,以及可执行文件do_not_use_local_messages_program,它使用ROS的某些部分,但不包含此程序包中定义的消息/服务,那么您需要在CMakeLists.txt中使用以下内容:

   

  # Get the information about this package's buildtime dependencies
  find_package(catkin REQUIRED
    COMPONENTS message_generation std_msgs sensor_msgs)

  # Declare the message files to be built
  add_message_files(FILES
    MyMessage1.msg
    MyMessage2.msg
  )

  # Declare the service files to be built
  add_service_files(FILES
    MyService.srv
  )

  # Actually generate the language-specific message and service files
  generate_messages(DEPENDENCIES std_msgs sensor_msgs)

  # Declare that this catkin package's runtime dependencies
  catkin_package(
   CATKIN_DEPENDS message_runtime std_msgs sensor_msgs
  )

  # define executable using MyMessage1 etc.
  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})

     另外,如果要构建actionlib操作,并在“action”目录中有一个名为“MyAction.action”的操作规范文件,则必须将actionlib_msgs作为组件添加到find_packaged()列表中,并在generate_messages(...)之前添加以下调用:

add_action_files(FILES
  MyAction.action
)

      此外,包必须具有对actionlib_msgs的构建依赖性。

   8、 Enabling Python module support

         如果ROS包提供了一些Python模块,则创建一个setup.py文件并调用

catkin_python_setup()

        应该放在generate_messages()和catkin_package()之前。

    9、 Unit Tests

            有一个特定于catkin的宏用于处理名为catkin_add_gtest()的基于gtest的单元测试。

if(CATKIN_ENABLE_TESTING)
  catkin_add_gtest(myUnitTest test/utest.cpp)
endif()

    10、Optional Step: Specifying Installable Targets

         在以上构建时间之后,目标放置到catkin工作空间的开发空间中。通常希望在系统中安装目标,进行系统级安装测试。话句话说希望能够对代码进行“make install”,则需要指定目标应该结束的位置。使用CMake的install( )函数完成安装,该函数的参数 

  • TARGETS - which targets to install

  • ARCHIVE DESTINATION - Static libraries and DLL (Windows) .lib stubs

  • LIBRARY DESTINATION - Non-DLL shared libraries and modules

  • RUNTIME DESTINATION - Executable targets and DLL (Windows) style shared libraries

    install(TARGETS ${PROJECT_NAME}
      ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
      LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
      RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )

    以上是标准安装,以下是特定安装Python:

    install(TARGETS python_module_library
      ARCHIVE DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}
      LIBRARY DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}
    )

    10.1 Installing Python Executable Scripts

               对于Python代码,安装规则不同,没有使用add_library()和add_executable()函数,以便CMake确定哪些文件是目标以及是什么类型的目标。而是在CMakeLists.txt文件中使用以下内容: 

catkin_install_python(PROGRAMS scripts/myscript
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

有关安装python脚本和模块的详细信息,以及文件夹布局的最佳实践,请参阅 catkin manual.。 

     10.2 Installing header files

           头文件必须安装到“include”文件夹,通过安装整个文件夹的文件(可选择按文件名模式过滤并排除SVN子文件夹)来完成的。这可以通过如下安装规则来完成:

install(DIRECTORY include/${PROJECT_NAME}/
  DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
  PATTERN ".svn" EXCLUDE
)

或者如果include下的子文件夹与包名称不匹配:

install(DIRECTORY include/
  DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
  PATTERN ".svn" EXCLUDE
)

      10.3 Installing roslaunch Files or Other Resources

         Other resources like launchfiles can be installed to ${CATKIN_PACKAGE_SHARE_DESTINATION}:

install(DIRECTORY launch/
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
  PATTERN ".svn" EXCLUDE)

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值