编写新的恢复插件 [待校准@2180]

概述

本教程演示如何创建自己的恢复插件。恢复插件位于恢复服务器中。与规划器和控制器服务器不同,每个恢复都将托管自己独特的操作服务器(action server)。规划器和控制器在完成相同任务时具有相同的API。但是,恢复可用于执行各种各样的任务,因此每个恢复都可以有自己独特的操作消息定义和服务器。这允许恢复服务器的巨大灵活性,实现任何可想象的不需要其他重用的恢复操作。 [校准@混沌无形]

必要条件

教程步骤

1-创建一个新的恢复插件 [待校准@2182]

我们将创建一个简单的呼救恢复行为。它将使用Twilio通过短信向远程操作中心发送消息。本教程中的代码在 navigation_tutorialsnav2_sms_recovery 。这个软件包可以被认为是编写恢复插件的参考。 [校准@混沌无形]

我们例子插件实现了 nav2_core::Recovery 的插件类。然而,我们在 nav2_recoveries 中有一个很好的动作包装器,所以我们在这个应用中使用 nav2_recoveries::Recovery 基类来代替。此包装类来自 nav2_core 类,可以作为一个插件,但处理绝大多数的ROS 2行动服务器所需的锅炉板。 [校准@小鱼]

基类 nav2_core 提供4种纯虚拟方法执行恢复插件。插件将使用恢复服务器主机插件,但每个插件提供自己独特动作服务器接口。让我们了解更多关于编写恢复插件所需的方法 * * 如果你没有使用 nav2_recoveries 包装 * *[校准@混沌无形]

Virtual method

方法描述

必须重写?

configure()

当服务器进入on_configure状态时,方法被调用。理想情况下,这个方法应该执行ROS参数的声明和恢复的成员变量的初始化。这个方法需要4个输入参数:父节点的共享指针、恢复名称、TF缓冲区指针和碰撞检查器的共享指针。 [校准@混沌无形]

[校准@小鱼]

activate() [待校准@2110]

当恢复服务器进入on_activate状态时,方法被调用。理想情况下,这个方法应该实现恢复到活动状态前的必要操作。 [校准@混沌无形]

[校准@小鱼]

deactivate()

当恢复服务器进入on_deactivate状态时,方法被调用。理想情况下,这个方法应该实现恢复进入非活动状态前的必要操作。 [校准@混沌无形]

[校准@小鱼]

cleanup()

当恢复服务器进入on_cleanup状态时,方法被调用。理想情况下,这个方法应该清理为恢复所创建的资源。 [校准@混沌无形]

[校准@小鱼]

对于提供ROS 2动作接口和模板的 ``nav2_recoveries``包装器,我们有4个虚拟方法需要实现。本教程使用这个包装器,所以这些是我们要解决的主要内容。 [校准@混沌无形]

Virtual method

方法描述

必须重写?

onRun() [待校准@2191]

当收到一个新的恢复行动请求时,方法被立即调用。给出要处理的行动目标,并应开始恢复初始化/进程。 [校准@混沌无形]

[校准@小鱼]

onCycleUpdate() [待校准@2193]

方法在恢复更新率时被调用,应该完成任何必要的更新。一个旋转的例子是计算当前周期的指令速度,发布它并检查是否完成。 [校准@混沌无形]

[校准@小鱼]

Onconfiguration() [待校准@2195]

当恢复服务器进入on_configure状态时,方法被调用。理想情况下,这个方法应该实现恢复进入配置状态前的必要操作(获取参数等)。 [校准@混沌无形]

[校准@小鱼]

onCleanup() [待校准@2197]

当恢复服务器进入on_cleanup状态时,方法被调用。理想情况下,这个方法应该清理为恢复所创建的资源。 [校准@混沌无形]

[校准@小鱼]

在本教程中,我们将使用``onRun()`` 、 onCycleUpdate()onConfigure()``方法来创建SMS恢复。为了简洁起见,将跳过 ``onConfigure() ,但只包括参数声明。 [校准@混沌无形]

在恢复中,onRun() 方法必须设置任何初始状态并启动恢复行为。对于我们调用帮助恢复行为的情况,我们可以在这个方法中琐碎地计算我们所有的需求。 [校准@混沌无形]

Status SMSRecovery::onRun(const std::shared_ptr<const Action::Goal> command)
{
  std::string response;
  bool message_success = _twilio->send_message(
    _to_number,
    _from_number,
    command->message,
    response,
    "",
    false);

  if (!message_success) {
    RCLCPP_INFO(node_->get_logger(), "SMS send failed.");
    return Status::FAILED;
  }

  RCLCPP_INFO(node_->get_logger(), "SMS sent successfully!");
  return Status::SUCCEEDED;
}

我们收到一个行动目标, command ,我们想在其中进行处理。 command 包含一个 message 字段,其中包含我们想要传达给我们母舰的信息。这是我们想通过短信发送给行动中心的战友的 "call for help" 信息。 [校准@混沌无形]

我们使用Twilio服务来完成这项任务。请 创建一个账户 和所有相关信息需要创建服务 (例如 account_sidauth_token ,电话号码)。你可以在你的配置文件中把这些值设置为对应于``onConfigure()``参数声明的参数。 [校准@混沌无形]

我们使用``_twilio``对象来发送我们的消息,其中包括你在配置文件中的账户信息。我们发送消息并在屏幕上记录消息是否发送成功。我们返回 FAILEDSUCCEEDED,这取决于返回给行动客户端的值。 [校准@混沌无形]

``onCycleUpdate()``由于我们的短时运行的恢复行为,所以是很简单的。如果恢复反而是更长时间的运行,如旋转,导航到安全区域,或离开一个糟糕的地方并等待帮助,那么这个函数将检查超时或计算控制值。对于我们的例子,我们只是简单地返回成功,因为我们已经在``onRun()``中完成了我们的任务。 [校准@混沌无形]

Status SMSRecovery::onCycleUpdate()
{
  return Status::SUCCEEDED;
}

其余的方法不使用,也不强制覆盖它们。 [校准@混沌无形]

2-导出恢复插件

现在我们已经创建了我们的自定义恢复,我们需要导出我们的恢复插件,这样它就可以在恢复服务器上看到。插件在运行时被加载,如果它们不可见,那么我们的恢复服务器将无法加载它。在ROS 2中,导出和加载插件是由``pluginlib``处理的。 [校准@混沌无形]

在我们的教程中,“nav2_sms_recovery::SMSRecovery `` 类被动态加载为 `` nav2_core:: recovery”,这是我们的基类。 [校准@混沌无形]

  1. 导出恢复插件,我们需要提供两行 [校准@混沌无形]

#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(nav2_sms_recovery::SMSRecovery, nav2_core::Recovery)

请注意,它需要pluginlib导出插件的类。Pluginlib将提供作为宏的 PLUGINLIB_EXPORT_CLASS ,它负责所有的导出工作。 [待校准@2167]

把这些行内容放在文件的末尾是很好的做法,但从技术上讲,你也可以写在顶部。 [校准@混沌无形]

  1. 下一步是在包的根目录中创建插件的描述文件。例如,我们的示例软件包中的 recovery_plugin.xml 文件。此文件包含以下信息 [校准@混沌无形]

<library path="nav2_sms_recovery_plugin">
  <class name="nav2_sms_recovery/SMSRecovery" type="nav2_sms_recovery::SMSRecovery" base_class_type="nav2_core::Recovery">
    <description>This is an example plugin which produces an SMS text message recovery.</description>
  </class>
</library>
  1. 下一步是使用cmake函数``pluginlib_export_plugin_description_file()``导出插件``CMakeLists.txt`。此函数将插件描述文件安装到 share 目录,并设置属性索引以使其可被发现。 [校准@混沌无形]

pluginlib_export_plugin_description_file(nav2_core recovery_plugin.xml)
  1. 插件描述文件也应添加到 package.xml [待校准@2171]

<export>
  <build_type>ament_cmake</build_type>
  <nav2_core plugin="${prefix}/recovery_plugin.xml" />
</export>
  1. 编译并注册。接下来,我们将使用这个插件。 [待校准@2172]

3-通过params文件传递插件名称

要启用插件,我们需要如下修改 nav2_params.yaml 文件以替换以下参数 [待校准@2210]

recoveries_server:
  ros__parameters:
    costmap_topic: local_costmap/costmap_raw
    footprint_topic: local_costmap/published_footprint
    cycle_frequency: 10.0
    recovery_plugins: ["spin", "backup", "wait"]
    spin:
      plugin: "nav2_recoveries/Spin"
    backup:
      plugin: "nav2_recoveries/BackUp"
    wait:
      plugin: "nav2_recoveries/Wait"
    global_frame: odom
    robot_base_frame: base_link
    transform_timeout: 0.1
    use_sim_time: true
    simulate_ahead_time: 2.0
    max_rotational_vel: 1.0
    min_rotational_vel: 0.4
    rotational_acc_lim: 3.2

[待校准@2175]

recoveries_server:
  ros__parameters:
    costmap_topic: local_costmap/costmap_raw
    footprint_topic: local_costmap/published_footprint
    cycle_frequency: 10.0
    recovery_plugins: ["spin", "backup", "wait", "call_for_help"]
    spin:
      plugin: "nav2_recoveries/Spin"
    backup:
      plugin: "nav2_recoveries/BackUp"
    wait:
      plugin: "nav2_recoveries/Wait"
    call_for_help:
      plugin: "nav2_sms_recovery/SMSRecovery"
      account_sid: ... # your sid
      auth_token: ... # your token
      from_number: ... # your number
      to_number: ... # the operations center number
    global_frame: odom
    robot_base_frame: base_link
    transform_timeout: 0.1
    use_sim_time: true
    simulate_ahead_time: 2.0
    max_rotational_vel: 1.0
    min_rotational_vel: 0.4
    rotational_acc_lim: 3.2

在上面文中,您可以观察到我们在 call_for_help ROS 2操作服务器名称下添加了SMS恢复。我们还告诉恢复服务器, call_for_helpSMSRecovery 类型的,并为您的Twilio帐户提供我们的参数。 [校准@混沌无形]

4- 运行恢复插件 [校准@混沌无形]

在启用Nav2的情况下运行Turtlebot3的模拟,详细的说明写在 入门 。以下是快捷键命令: [校准@混沌无形]

$ ros2 launch nav2_bringup tb3_simulation_launch.py params_file:=/path/to/your_params_file.yaml

在新的终端运行: [校准@混沌无形]

$ ros2 action send_goal "call_for_help" nav2_sms_recovery/action/SmsRecovery "Help! Robot 42 is being mean :( Tell him to stop!"