从ROS 1迁移指南 [待校准@799]

有两种不同的包迁移: [待校准@800]

  • 将现有包的源文件代码从ROS 1迁移到ROS 2,目的是使源文件代码的很大一部分保持不变或至少保持相似。这方面的一个例子可以是 pluginlib ,其中源文件代码保存在同一仓库的不同分支中,并且通常在必要时可以在这些分支之间移植补丁。 [待校准@801]

  • 为ROS 2实现ROS 1包的相同或相似功能,但假设源文件将有很大的不同。这方面的一个例子可能是ROS 2中的 roscpp in ROS 1 and rclcpp ,它是独立的仓库,不共享任何代码。 [待校准@802]

本文重点介绍前一种情况,并介绍将ROS 1包迁移到ROS 2的高级步骤。它的目标不是一步一步的迁移指令,也不被认为是最终的 "solution" 。未来的版本将旨在使迁移更加顺畅,减少工作量,从而为ROS 1和ROS 2维护来自同一分支的单个包。 [待校准@803]

先决条件

在能够将ROS 1包迁移到ROS 2之前,其所有依赖项必须在ROS 2中可用。 [待校准@805]

迁移步骤 [待校准@806]

包装清单 [待校准@807]

ROS 2不支持包规格的格式1,只支持更新的格式版本 (2和更高版本)。因此,如果 package.xml 文件使用格式1,它必须至少更新为格式2。因为ROS 1支持所有格式,所以在ROS 1包中执行转换是安全的。 [待校准@808]

某些包在ROS 2中可能具有不同的名称,因此可能需要相应地更新依赖项。 [待校准@809]

元包 [待校准@810]

ROS 2没有元包的特殊包类型。元包仍然可以作为仅包含运行时依赖项的常规包存在。从ROS 1迁移元包时,只需删除包清单中的 <metapackage /> 标签。 [待校准@811]

消息、服务和动作定义 [待校准@812]

消息文件必须以 .msg 结尾,并且必须位于子文件夹 msg 。服务文件必须以 .srv 结尾,并且必须位于 srv 子文件夹中。Action文件必须结束 .action 必须位于子文件夹 action[待校准@813]

这些文件可能需要更新以符合 ROS Interface definition 。一些原始类型已被删除,ROS 1中内置类型的 durationtime 类型已被普通消息定义替换,必须从 builtin_interfaces 包中使用。此外,一些命名约定比ROS 1更严格。 [待校准@814]

在你的 package.xml 里: [待校准@815]

  • 加入 <buildtool_depend>rosidl_default_generators</buildtool_depend>[待校准@816]

  • 加入 <exec_depend>rosidl_default_runtime</exec_depend>[待校准@817]

  • 对于每个依赖消息包,添加 <depend>message_package</depend>[待校准@818]

在你的 CMakeLists.txt 里: [待校准@819]

set(CMAKE_CXX_STANDARD 14)
  • 添加 find_package(rosidl_default_generators REQUIRED) [待校准@821]

  • 对于每个依赖消息包,添加 find_package(message_package REQUIRED) ,并用 rosidl_generate_interfaces 替换调用 generate_messages 的CMake函数。 [待校准@822]

这将取代所有可以删除的消息和服务文件的 add_message_filesadd_service_files 列表。 [待校准@823]

构建系统 [待校准@824]

ROS 2中的构建系统被调用 ament ,构建工具是 colcon. ,Ament建立在CMake上: ament_cmake 提供CMake功能,使编写 CMakeLists.txt 文件更容易。 [待校准@825]

构建工具 [待校准@826]

而不是使用 catkin_makecatkin_make_isolatedcatkin build ROS 2使用命令行工具 colcon 建立和安装一组包。 [待校准@827]

纯Python包 [待校准@828]

如果ROS 1包仅使用CMake调用 setup.py 文件,并且不包含除Python代码之外的任何内容 (例如g.也没有消息、服务等。) 它应该在ROS 2中转换为纯Python包: [待校准@829]

  • 更新或添加 package.xml 文件中的构建类型: [待校准@830]

    <export>
      <build_type>ament_python</build_type>
    </export>
    
  • 删除 CMakeLists.txt 文件 [待校准@831]

  • setup.py 文件更新为标准Python安装脚本 [待校准@832]

ROS 2仅支持Python 3。虽然每个包可以选择也支持Python 2,但如果它使用其他ROS 2包提供的任何API,则必须使用Python 3调用可执行文件。 [待校准@833]

更新 * CMakeLists.txt * 以使用 * ament _ cmake * [待校准@834]

应用以下更改以使用 ament_cmake 代替 catkin : [待校准@835]

  • package.xml 文件导出部分设置构建类型: [待校准@836]

    <export>
      <build_type>ament_cmake</build_type>
    </export>
    
  • find_package 的调用改为 catkin ,将 COMPONENTS 的调用改为: [待校准@837]

    find_package(ament_cmake REQUIRED)
    find_package(component1 REQUIRED)
    # ...
    find_package(componentN REQUIRED)
    
  • 使用以下命令移动和更新 catkin_package 调用: [待校准@838]

    • 而是在所有目标都注册后调用 ament_package[待校准@839]

    • [需手动修复的语法] ament_package 唯一有效的论据是 CONFIG_EXTRAS 。所有其他参数都包含在单独的函数中,这些函数都需要在 * ament_package 之前调用: [待校准@840]

      • 而不是之前通过 CATKIN_DEPENDS ... 调用 ament_export_dependencies(...)[待校准@841]

      • 而不是之前通过 INCLUDE_DIRS ... 调用 ament_export_include_directories(...)[待校准@842]

      • 而不是之前通过 LIBRARIES ... 调用 ament_export_libraries(...)[待校准@843]

    • TODO document ament_export_targets (``ament_export_interfaces`` in Eloquent and older)?

  • rosidl_generate_interfaces 代替 add_message_filesadd_service_filesgenerate_messages 的调用。 [待校准@845]

    • 第一个论点是 target_name 。如果您是're building just one library it' ${PROJECT_NAME}'' [待校准@846]

    • 后跟相对于包根目录的消息文件名列表。 [待校准@847]

      • 如果您将多次使用文件名列表,建议编写一个消息文件列表,并将该列表传递给函数以使其清晰。 [待校准@848]

    • 最终的多值关键字参数fpr generate_messagesDEPENDENCIES ,它需要从属消息包的列表。 [待校准@849]

      rosidl_generate_interfaces(${PROJECT_NAME}
        ${msg_files}
        DEPENDENCIES std_msgs
      )
      
  • 删除出现的 * devel空间 *。像 CATKIN_DEVEL_PREFIX 这样的相关CMake变量已经不存在了。 [待校准@850]

单元测试 [待校准@861]

如果您正在使用gtest: [待校准@862]

BUILD_TESTING 代替 CATKIN_ENABLE_TESTING 。用 ament_add_gtest 代替 catkin_add_gtest[待校准@863]

-   if (CATKIN_ENABLE_TESTING)
-     find_package(GTest REQUIRED)  # or rostest
-     include_directories(${GTEST_INCLUDE_DIRS})
-     catkin_add_gtest(${PROJECT_NAME}-some-test src/test/some_test.cpp)
-     target_link_libraries(${PROJECT_NAME}-some-test
-       ${PROJECT_NAME}_some_dependency
-       ${catkin_LIBRARIES}
-       ${GTEST_LIBRARIES})
-   endif()
+   if (BUILD_TESTING)
+     find_package(ament_cmake_gtest REQUIRED)
+     ament_add_gtest(${PROJECT_NAME}-some-test src/test/test_something.cpp)
+     ament_target_dependencies(${PROJECT_NAME)-some-test
+       "rclcpp"
+       "std_msgs")
+     target_link_libraries(${PROJECT_NAME}-some-test
+       ${PROJECT_NAME}_some_dependency)
+   endif()

在你的 package.xml 中加入 <test_depend>ament_cmake_gtest</test_depend>[待校准@864]

-   <test_depend>rostest</test_depend>
+   <test_depend>ament_cmake_gtest</test_depend>

林特 [待校准@327]

在ROS 2中,我们正在努力使用linters维护干净的代码。不同语言的风格在我们的 Developer Guide. 中定义 [待校准@865]

如果你从头开始一个项目,建议遵循风格指南,通过在 if(BUILD_TESTING) 下面添加这些线来打开自动linter单元测试 (直到阿尔法5,这是 AMENT_ENABLE_TESTING )。 [待校准@866]

find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()

您还需要将以下依赖项添加到您的 package.xml 中: [待校准@867]

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

继续在CMake中使用 catkin [待校准@868]

ROS 2使用ament作为构建系统,但为了向后兼容,ROS 2有一个调用ed catkin 的包,它提供了与ROS 1catkin几乎相同的API。为了使用这个向后兼容的应用编程接口, CMakeLists.txt 只能更新到在所有目标之后调用函数 catkin_ament_package() *[待校准@869]

NOTE注意: 这尚未实施,目前只是一个想法。由于与依赖项相关的更改数量,尚未确定此兼容性API是否足够有用以证明努力的合理性。** [待校准@870]

更新源文件 [待校准@871]

消息、服务和动作 [待校准@872]

ROS 2消息、服务和动作的命名空间在包名称后使用子命名空间 (分别为 msgsrvaction )。因此,一个包含看起来像: #include <my_interfaces/msg/my_message.hpp> 。然后将ctype类型命名为: “my_interface::msg:: mymessage”。 [待校准@873]

共享指针类型在消息结构中作为typedefs提供: “我的接口::msg::MyMessage::SharedPtr `` as well as `` 我的接口::msg::MyMessage:: constsharedptr”。 [待校准@874]

有关更多详细信息,请参阅有关 generated C++ interfaces 的文章。 [待校准@875]

迁移要求包含更改方式: [待校准@876]

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// # include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/msg/point_stamped.hpp>

// geometry_msgs::PointStamped point_stamped;
geometry_msgs::msg::PointStamped point_stamped;

迁移需要代码才能将 msg 命名空间插入所有实例。 [待校准@880]

服务对象的使用 [待校准@881]

ROS 2中的服务调用没有boolean返回值。建议抛出异常,而不是在失败时返回false。 [待校准@882]

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// #include "nav_msgs/GetMap.h"
#include "nav_msgs/srv/get_map.hpp"

// bool service_callback(
//   nav_msgs::GetMap::Request & request,
//   nav_msgs::GetMap::Response & response)
void service_callback(
  const std::shared_ptr<nav_msgs::srv::GetMap::Request> request,
  std::shared_ptr<nav_msgs::srv::GetMap::Response> response)
{
  // ...
  // return true;  // or false for failure
}

ros的用法:: 时间 [待校准@883]

对于 “ros:: time” 的用法: [待校准@884]

  • 替换 “ros::Time `` with `` rclcpp::Time” 的所有实例 [待校准@885]

  • 如果您的消息或代码使用std_msgs::Time: [待校准@886]

    • 将std_msgs::Time的所有实例转换为builtin_interface::msg::Time [待校准@887]

    • 转换所有 “# 包含” std_msgs/time.h `` to `` # 包含 “构建接口/msg/time.hpp” [待校准@888]

    • 使用std_msgs:: 时间字段 nsec 将所有实例转换为builtin_interface::msg:: 时间字段 nanosec [待校准@889]

ros的用法:: 费率 [待校准@890]

有一个等效类型 “rclcpp::Rate `` object which is basically a drop in replacement for `` ros:: rate”。 [待校准@891]

提升 [待校准@295]

以前由Boost提供的许多功能已经集成到cstandard标准库中。因此,我们希望利用新的核心功能,并在可能的情况下避免对boost的依赖。 [待校准@894]

共享指针 [待校准@895]

要将共享指针从boost切换到标准creplace,请替换以下实例: [待校准@896]

也可能有一些变体,如 weak_ptr ,你也想转换。 [待校准@899]

此外,建议使用 using 代替 typedefusing 有能力在模板化逻辑中更好地工作。详情请参见 see here [待校准@900]

线程/互斥体 [待校准@901]

ROS代码库中使用的boost的另一个常见部分是 “boost:: 线程” 中的互斥体。 [待校准@902]

  • 替换 boost::mutex::scoped_lock乙甲std::unique_lock<std::mutex> [待校准@903]

  • 替换 “增强:: 互斥 `` with `` 标准:: 互斥” [待校准@904]

  • 替换 #include <boost/thread/mutex.hpp>乙甲#include <mutex> [待校准@905]

无序地图 [待校准@906]

替换: [待校准@907]

功能 [待校准@910]

替换: [待校准@907]

参数

在ROS 1中,参数与允许在运行时通过使用网络api检索参数的中央服务器相关联。在ROS 2中,参数与每个节点相关联,并且在运行时可通过ROS服务进行配置。 [待校准@914]

Launch档案 [待校准@918]

虽然ROS 1中的launch文件始终使用 .xml 文件指定,但ROS 2支持Python脚本以实现更大的灵活性 (见 launch package ) 以及XML和YAML文件。关于将launch文件从ROS 1迁移到ROS 2,请参见 separate tutorial[待校准@919]

示例: 将现有的ROS 1包转换为使用ROS 2 [待校准@920]

假设我们有一个简单的ROS 1包调用ed talker ,它在一个节点中使用 roscpp ,调用ed talker 。此包位于catkin工作区,位于 “~/ros1_talker”。 [待校准@921]

ROS 1代码 [待校准@922]

这是我们catkin工作区的目录布局: [待校准@923]

$ cd ~/ros1_talker
$ find .
.
./src
./src/talker
./src/talker/package.xml
./src/talker/CMakeLists.txt
./src/talker/talker.cpp

以下是这三个文件的内容: [待校准@924]

src/talker/package.xml: [待校准@925]

<package>
  <name>talker</name>
  <version>0.0.0</version>
  <description>talker</description>
  <maintainer email="gerkey@osrfoundation.org">Brian Gerkey</maintainer>
  <license>Apache 2.0</license>
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>std_msgs</run_depend>
</package>

src/talker/CMakeLists.txt: [待校准@926]

cmake_minimum_required(VERSION 2.8.3)
project(talker)
find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
add_executable(talker talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
install(TARGETS talker
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

src/talker/talker.cpp: [待校准@927]

#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;
  std_msgs::String msg;
  while (ros::ok())
  {
    std::stringstream ss;
    ss << "hello world " << count++;
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}

构建ROS 1代码 [待校准@928]

我们源文件环境设置文件 (在这种情况下,对于使用bash的Jade),然后我们使用 catkin_make install 构建包: [待校准@929]

. /opt/ros/jade/setup.bash
cd ~/ros1_talker
catkin_make install

运行ROS 1节点 [待校准@930]

如果还没有运行,我们启动一个 roscore ,首先从我们的 catkin 安装树采购安装文件 ( /opt/ros/jade/setup.bash 的系统安装文件也可以在这里工作): [待校准@931]

. ~/ros1_talker/install/setup.bash
roscore

在另一个外壳,我们运行节点 catkin 安装空间 rosrun ,再次采购安装文件 (在这种情况下必须从我们工作区): [待校准@932]

. ~/ros1_talker/install/setup.bash
rosrun talker talker

迁移到ROS 2 [待校准@933]

让我们从创建一个新的工作空间开始: [待校准@934]

mkdir ~/ros2_talker
cd ~/ros2_talker

我们将把源文件树从我们的ROS 1包复制到那个工作区,在那里我们可以修改它: [待校准@935]

mkdir src
cp -a ~/ros1_talker/src/talker src

现在,我们将修改节点中的ccode代码。调用ed rclcpp 的ROS 2 c library库提供了与 roscpp 提供的API不同的API。两个库之间的概念非常相似,这使得更改相当简单。 [待校准@936]

包含标题 [待校准@937]

取代 ros/ros.h ,它使我们能够访问 roscpp 库API,我们需要包括 rclcpp/rclcpp.hpp ,它使我们能够访问 rclcpp 库API: [待校准@938]

//#include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"

为了得到 std_msgs/String 信息定义,我们需要包括 std_msgs/msg/string.hpp ,而不是 std_msgs/String.h : [待校准@939]

//#include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"

更改clibrary库调用s [待校准@940]

我们进行初始化,而不是将节点的名称传递给库初始化调用,然后将节点名称传递给节点对象的创建 (我们可以使用 auto 关键字,因为现在我们需要一个c14 14编译器): [待校准@941]

//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
    rclcpp::init(argc, argv);
    auto node = rclcpp::Node::make_shared("talker");

发布者和速率对象的创建看起来非常相似,对命名空间和方法的名称进行了一些更改。 [待校准@942]

//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
  auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter",
    1000);
  rclcpp::Rate loop_rate(10);

为了进一步控制如何处理消息传递,可以传递服务质量 ( QoS ) 配置文件。默认配置文件为 rmw_qos_profile_default 。更多详情,请参见 design documentconcept overview. [待校准@943]

传出消息的创建在命名空间中不同: [待校准@944]

//  std_msgs::String msg;
  std_msgs::msg::String msg;

代替 “ros::ok()”,我们调用 “rclcpp::ok()”: [待校准@945]

//  while (ros::ok())
  while (rclcpp::ok())

在出版循环中,我们像以前一样访问 data 领域: [待校准@946]

msg.data = ss.str();

为了打印控制台消息,我们使用的不是 ROS_INFO() ,而是 RCLCPP_INFO() 及其各种表亲。关键的区别是 RCLCPP_INFO() 把一个日志记录器作为第一个参数。 [待校准@947]

//    ROS_INFO("%s", msg.data.c_str());
    RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());

发布消息与之前相同: [待校准@948]

chatter_pub->publish(msg);

旋转 (即让通讯系统处理任何待处理的传入/传出消息) 的不同之处在于,调用现在将节点作为参数: [待校准@949]

//    ros::spinOnce();
    rclcpp::spin_some(node);

使用rate对象的睡眠保持不变。 [待校准@950]

把它们放在一起,新的 talker.cpp 看起来像这样: [待校准@951]

#include <sstream>
// #include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"
// #include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"
int main(int argc, char **argv)
{
//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("talker");
//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
  auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter", 1000);
  rclcpp::Rate loop_rate(10);
  int count = 0;
//  std_msgs::String msg;
  std_msgs::msg::String msg;
//  while (ros::ok())
  while (rclcpp::ok())
  {
    std::stringstream ss;
    ss << "hello world " << count++;
    msg.data = ss.str();
//    ROS_INFO("%s", msg.data.c_str());
    RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());
    chatter_pub->publish(msg);
//    ros::spinOnce();
    rclcpp::spin_some(node);
    loop_rate.sleep();
  }
  return 0;
}

更换 package.xml [待校准@952]

ROS 2不支持包规格的格式1,只支持更新的格式版本 (2和更高版本)。我们首先在 package 标签中指定格式版本: [待校准@953]

<!-- <package> -->
<package format="2">

ROS 2使用 catkin 的新版本,调用 ament_cmake ,我们在 buildtool_depend 标签中指定: [待校准@954]

<!--  <buildtool_depend>catkin</buildtool_depend> -->
  <buildtool_depend>ament_cmake</buildtool_depend>

在我们的构建依赖项中,我们使用的不是 roscpp ,而是 rclcpp ,它提供了我们使用的c ++ API。 [待校准@955]

<!--  <build_depend>roscpp</build_depend> -->
  <build_depend>rclcpp</build_depend>

我们在运行依赖项中添加了相同的内容,并从 run_depend 标签更新到 exec_depend 标签 (包格式升级到版本2的一部分): [待校准@956]

<!--  <run_depend>roscpp</run_depend> -->
  <exec_depend>rclcpp</exec_depend>
<!--  <run_depend>std_msgs</run_depend> -->
  <exec_depend>std_msgs</exec_depend>

在ROS 1,我们使用 <depend> 简化指定依赖编译时和运行时。我们可以在ROS 2中做同样的事情: [待校准@957]

<depend>rclcpp</depend>
<depend>std_msgs</depend>

我们还需要告诉构建工具我们是什么样的包,以便它知道如何构建我们。因为我们使用的是 ament 和CMake,所以我们添加以下行来声明我们的构建类型为 ament_cmake : [待校准@958]

<export>
  <build_type>ament_cmake</build_type>
</export>

综上所述,我们的 package.xml 现在看起来像这样: [待校准@959]

<!-- <package> -->
<package format="2">
  <name>talker</name>
  <version>0.0.0</version>
  <description>talker</description>
  <maintainer email="gerkey@osrfoundation.org">Brian Gerkey</maintainer>
  <license>Apache License 2.0</license>
<!--  <buildtool_depend>catkin</buildtool_depend> -->
  <buildtool_depend>ament_cmake</buildtool_depend>
<!--  <build_depend>roscpp</build_depend> -->
<!--  <run_depend>roscpp</run_depend> -->
<!--  <run_depend>std_msgs</run_depend> -->
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

Totodo: 仅使用 <depend> 标签显示此文件的更简单版本,该标签由软件包格式的版本2启用 (也在 catkin 中支持,因此,严格来说,与ROS 2正交)。** [待校准@960]

更改CMake代码 [待校准@961]

ROS 2依赖于CMake的更高版本: [待校准@962]

#cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)

ROS 2依赖于c14 14标准。根据您使用的编译器,默认情况下可能不会启用对c14 14的支持。使用 gcc 5.3 (这是在Ubuntu Xenial上使用的),我们需要显式启用它,我们通过在文件顶部附近添加这一行来实现: [待校准@963]

set(CMAKE_CXX_STANDARD 14)

在所有平台上工作的首选方式是: [待校准@964]

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

使用 catkin ,我们指定包我们想建立反对通过他们 COMPONENTS 参数当最初找到 catkin 本身。对于 ament_cmake ,我们发现每个包装都是单独的,从 ament_cmake 开始: [待校准@965]

#find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

可以像以前一样找到系统依赖项: [待校准@966]

find_package(Boost REQUIRED COMPONENTS system filesystem thread)

我们调用 catkin_package() ,为使用我们包的其他包自动生成CMake配置文件。鉴于该调用在指定要构建的目标之前发生,我们现在在 * 目标之后调用类似的 ament_package() *: [待校准@967]

# catkin_package()
# At the bottom of the file:
ament_package()

唯一需要手动包含的目录是非ament包的本地目录和依赖项: [待校准@968]

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

更好的选择是为每个目标单独指定包含目录,而不是为所有目标包含所有目录: [待校准@969]

target_include_directories(target include ${Boost_INCLUDE_DIRS})

类似于我们分别找到每个依赖包的方式,我们需要将每个包链接到构建目标。为了与ament包的依赖包链接,而不是使用 target_link_libraries()ament_target_dependencies() 是处理构建标志的一种更简洁、更彻底的方法。它自动调用y处理 _INCLUDE_DIRS 中定义的包含目录和 _LIBRARIES 中定义的链接库。 [待校准@970]

#target_link_libraries(talker ${catkin_LIBRARIES})
ament_target_dependencies(talker
  rclcpp
  std_msgs)

要与不是ament包的包链接,例如系统依赖项,如 Boost ,或在同一 CMakeLists.txt 中构建的库,请使用 target_link_libraries() : [待校准@971]

target_link_libraries(target ${Boost_LIBRARIES})

对于安装, catkin 定义变量,如 CATKIN_PACKAGE_BIN_DESTINATION 。对于 ament_cmake ,我们只给出一个相对于安装根的路径,就像可执行文件的 bin : [待校准@972]

#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talker
  DESTINATION lib/${PROJECT_NAME})

(可选) 我们可以为下游包安装和导出包含的目录: [待校准@973]

install(DIRECTORY include/
  DESTINATION include)
ament_export_include_directories(include)

或者,我们可以导出下游包的依赖项: [待校准@974]

ament_export_dependencies(std_msgs)

把它们放在一起,新的 CMakeLists.txt 看起来像这样: [待校准@975]

#cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)
project(talker)
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()
#find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
#catkin_package()
#include_directories(${catkin_INCLUDE_DIRS})
include_directories(include)
add_executable(talker talker.cpp)
#target_link_libraries(talker ${catkin_LIBRARIES})
ament_target_dependencies(talker
  rclcpp
  std_msgs)
#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talker
  DESTINATION lib/${PROJECT_NAME})
install(DIRECTORY include/
  DESTINATION include)
ament_export_include_directories(include)
ament_export_dependencies(std_msgs)
ament_package()

Totodo: 展示 ament_auto 会是什么样子。** [待校准@976]

构建ROS 2代码 [待校准@977]

我们源文件环境安装文件 (在本例中是按照ROS 2安装教程生成的文件,该教程以 “~/ros2_ws” 构建,然后我们使用 colcon build 构建包: [待校准@978]

. ~/ros2_ws/install/setup.bash
cd ~/ros2_talker
colcon build

运行ROS 2节点 [待校准@979]

因为我们将 talker 可执行文件安装到 bin 中,在从安装树采购安装文件后,我们可以直接通过名称调用它 (也,还没有相当于 rosrun 的ROS 2): [待校准@980]

. ~/ros2_ws/install/setup.bash
talker

更新脚本 [待校准@981]

ROS CLI参数 [待校准@982]

因为 ROS Eloquent, ROS参数应该以 --ros-args 和尾随的 -- 为范围 (如果没有参数跟随它,尾随的doubledash可能会被省略)。 [待校准@983]

重新映射名称类似于ROS 1,采用 “from:= to” 的形式,不同之处在于它前面必须有一个 --remap (或 -r ) 旗。例如: [待校准@984]

ros2 run some_package some_ros_executable --ros-args -r foo:=bar

我们对参数使用类似的语法,使用 --param (或 -p ) 标志: [待校准@985]

ros2 run some_package some_ros_executable --ros-args -p my_param:=value

请注意,这不同于在ROS 1中使用前导下划线。 [待校准@986]

要更改节点名称,请使用 __node (ROS 1当量为 __name ): [待校准@987]

ros2 run some_package some_ros_executable --ros-args -r __node:=new_node_name

注意 -r 旗的使用。更改命名空间 __ns 需要相同的重映射标志: [待校准@988]

ros2 run some_package some_ros_executable --ros-args -r __ns:=/new/namespace

在ROS 2中,以下ROS 1键没有等效项: [待校准@989]

有关更多信息,请参见 design document[待校准@994]

快速参考 [待校准@995]

特征 [待校准@996]

ROS 1 [待校准@997]

ROS 2 [待校准@998]

重新映射 [待校准@999]

foo:= bar [待校准@1000]

-r foo:= bar [待校准@1001]

参数 [待校准@1002]

_ foo:= bar [待校准@1003]

-p foo:= bar [待校准@1004]

节点名称 [待校准@1005]

__Name := foo [待校准@1006]

-r __node:= foo [待校准@1007]

命名空间 [待校准@1008]

__Ns: = foo [待校准@1009]

-R__ns: = foo [待校准@1010]

更多示例和工具 [待校准@1011]

许可 [待校准@1014]

在ROS 2中,我们推荐的许可证是 Apache 2.0 License. In ROS 1 our recommended license was the 3-Clause BSD License[待校准@1015]

对于任何新项目,我们建议使用Apache 2.0许可证,无论是ROS 1还是ROS 2。 [待校准@1016]

但是,当将代码从ROS 1迁移到ROS 2时,我们不能简单地更改许可证。对于任何先前存在的贡献,必须保留现有许可证。 [待校准@1017]

为此,如果一个包正在迁移,我们建议保留现有的许可证,并在现有的OSI许可证下继续为该包做出贡献,我们希望该许可证是核心元素的BSD许可证。 [待校准@1018]

这将使事情清晰易懂。 [待校准@1019]

更改许可证 [待校准@1020]

可以更改许可证,但是您需要联系所有贡献者并获得许可。对于大多数包来说,这可能是一项巨大的努力,不值得考虑。如果包有一小部分贡献者,那么这可能是可行的。 [待校准@1021]