编写新的行为树插件 [待校准@1988]

概述

本教程演示如何创建你自己行为树 (BT) 插件。BT插件作为节点行为树XML处理BT导航仪导航逻辑。 [待校准@1993]

必要条件

教程步骤

1创建新BT插件 [待校准@2000]

我们将创建一个简单的BT插件节点来在另一个服务器上执行操作。在这个例子中,我们将分析 nav2_behavior_tree 包中最简单的行为树动作节点, wait 节点。除了操作BT节点的示例之外,您还可以创建自定义装饰器、条件和控制节点。每个节点类型在行为树中都具有独特的作用,以执行诸如规划、控制BT流、检查条件状态或修改其他BT节点的输出之类的操作。 [待校准@2001]

本教程中的代码可以在 nav2_behavior_tree 包中找到,作为 wait_action 节点。可以将此操作节点视为编写其他操作节点插件的参考。 [待校准@2002]

我们的示例插件继承自基类 “nav2 _ 行为 _ 树::BtAction节点 . The base class is a wrapper on the BehaviorTree.CPP `` ::Action节点基本”,简化了利用ROS 2动作客户端的BT动作节点。 ``BTActionNode 既是BT动作,也是使用ROS 2动作网络接口调用远程服务器进行一些工作。 [待校准@2003]

与其它类型BT节点 (e。g.装饰、控制、状态) 使用相应BT节点,''BT: DecoratorNode'',''BT: ControlNode'',或 ''BT: ConditionNode''。BT动作节点 * 不 * 利用ROS 2动作接口,使用 ''BT: ActionNodeBase'' 基类本身。 [待校准@2004]

BTActionNode 类提供虚拟方法使用,除了信息提供构造函数。让学习更方法需要写BT动作插件。 [待校准@2005]

方法 [待校准@2006]

方法描述

Required需要吗?** [待校准@2008]

构造函数 [待校准@2009]

构造函数,用于指示与插件匹配的相应XML标记名称、使用插件调用的操作服务器的名称以及所需的任何行为树.CPP特殊配置。 [待校准@2010]

[校准@小鱼]

providedPorts() [待校准@2012]

函数定义输入和输出端口BT节点可能。这些类似于参数定义BT XML硬编码值或其他输出端口其他节点。 [待校准@2013]

[校准@小鱼]

On_tic() [待校准@2014]

方法当BT节点勾选行为时执行。这应该使用动态更新如新黑板值,输入端口,或参数。可能也复位状态动作。 [待校准@2015]

[校准@小鱼]

on_wait_for_result() [待校准@2017]

当行为树节点等待其调用的ROS 2操作服务器的结果时,将调用方法。这可用于检查更新以抢占当前任务、检查超时或等待操作完成时要计算的任何内容。 [待校准@2018]

[校准@小鱼]

on_success() [待校准@2019]

方法当ROS 2动作服务器返回成功结果。返回值BT节点报告树。 [待校准@2020]

[校准@小鱼]

on_aborted() [待校准@2021]

当ROS 2操作服务器返回中止结果时,将调用方法。返回BT节点将向树报告的值。 [待校准@2022]

[校准@小鱼]

on_cancelled() [待校准@2023]

MMethod当ROS 2动作服务器返回取消结果。返回BT节点将向树报告的值。 [待校准@2024]

[校准@小鱼]

在本教程中,我们将仅使用 on_tick() 方法。 [待校准@2025]

在构造函数中,我们需要获取应用于行为树节点的任何非变量参数。在此示例中,我们需要从行为树XML的输入端口获取睡眠时间的值。 [待校准@2026]

WaitAction::WaitAction(
  const std::string & xml_tag_name,
  const std::string & action_name,
  const BT::NodeConfiguration & conf)
: BtActionNode<nav2_msgs::action::Wait>(xml_tag_name, action_name, conf)
{
  int duration;
  getInput("wait_duration", duration);
  if (duration <= 0) {
    RCLCPP_WARN(
      node_->get_logger(), "Wait duration is negative or zero "
      "(%i). Setting to positive.", duration);
    duration *= -1;
  }

  goal_.time.sec = duration;
}

这里给出输入的 xml_tag_name 告诉BT节点插件stringXML中对应节点。这将看到后我们登记这BT节点插件。它也在string名称动作服务器将调用执行一些行为。最后,配置,我们可以忽略的最节点插件。 [待校准@2027]

然后我们调用 BTActionNode 构造函数。可以看出,它是由ROS 2操作类型模板化的,所以我们给它 “nav2_msgs::action:: wait” 操作消息类型,并转发我们的其他输入。 BTActionNode 作为 tick() 方法,当从树中调用该节点时,行为树直接调用该方法。然后, on_tick() 与行动客户目标一起被调用。 [待校准@2028]

在构造函数的主体,我们输入端口 getInput 参数 wait_duration 可独立配置的每个例证 wait 节点树。它是在 duration 参数插入 goal_ 。的 goal_ 类变量目标ROS 2行动客户端将发送到操作服务器。所以在这个例子,我们设置时间我们想等使动作服务器知道细节的请求。 [待校准@2029]

providedPorts() 方法给我们机会定义输入或输出端口。端口可以认为参数行为树节点访问行为树本身。例如,只有一个输入端口, wait_duration 可以把它BT XML每个实例 wait 恢复。我们设置类型, int ,默认 1wait_duration ,描述港口 Wait time[待校准@2030]

static BT::PortsList providedPorts()
{
  return providedBasicPorts(
    {
      BT::InputPort<int>("wait_duration", 1, "Wait time")
    });
}

当行为树勾选特定节点时,将调用 on_tick() 方法。对于等待BT节点,我们只想通知黑板上的计数器,勾选了与恢复相对应的操作插件。这对于保持特定导航运行期间执行的恢复数量的度量很有用。如果是可变输入,您也可以记录或更新 goal_ 的等待时间。 [待校准@2031]

void WaitAction::on_tick()
{
  increment_recovery_count();
}

不使用其余方法,也不强制重写它们。只有一些BT节点插件需要覆盖 on_wait_for_result() 来检查抢占或检查超时。如果不重叠,成功、中止和取消的方法将分别默认为 SUCCESSFAILURESUCCESS[待校准@2032]

2-导出planner插件

现在我们创建定制BT节点,我们需要导出插件也能见的行为树时加载定制BT XML。插件加载运行时如果不可见,然后我们BT导航仪服务器将无法加载或使用它。在BehaviorTree.CPP,导出和加载插件由 BT_REGISTER_NODES 微距。 [待校准@2034]

BT_REGISTER_NODES(factory)
{
  BT::NodeBuilder builder =
    [](const std::string & name, const BT::NodeConfiguration & config)
    {
      return std::make_unique<nav2_behavior_tree::WaitAction>(name, "wait", config);
    };

  factory.registerBuilder<nav2_behavior_tree::WaitAction>("Wait", builder);
}

在此宏中,我们必须创建一个 NodeBuilder ,以便我们的自定义操作节点可以具有非默认构造函数签名 (用于操作和xml名称)。此lambda将返回指向我们创建的行为树节点的唯一指针。用相关信息填充构造函数,在函数参数中给出 nameconfig 。然后定义这个BT节点将调用的ROS 2动作服务器的名称,在这种情况下,是 wWait 的动作。 [待校准@2035]

我们最后给生成器工厂登记。 Wait 给工厂名称在行为树XML文件对应BT节点插件。可以看到一个示例下面, Wait BT XML节点指定非变量输入端口 wait_duration 5秒。 [待校准@2036]

<Wait wait_duration="5"/>

3-将插件库名称添加到配置 [待校准@2037]

为了使BT Navigator节点发现我们刚刚注册的插件,我们需要在configuration YAML文件的bt_navigator节点下列出插件库名称。配置应类似于下面显示的配置。请注意plugin_lib_names下列出的nav2_wait_action_bt_node。 [待校准@2038]

bt_navigator:
  ros__parameters:
    use_sim_time: True
    global_frame: map
    robot_base_frame: base_link
    odom_topic: /odom
    default_bt_xml_filename: "navigate_w_replanning_and_recovery.xml"
    plugin_lib_names:
    - nav2_back_up_action_bt_node # other plugin
    - nav2_wait_action_bt_node    # our new plugin

4运行定制插件 [待校准@2039]

现在,您可以在自定义BT节点上使用行为树。例如, navigate_w_replanning_and_recovery.xml 文件如下所示。 [待校准@2040]

选择此BT XML文件特定导航请求 NavigateToPose 或默认行为树BT导航仪配置yaml文件。 [待校准@2041]

<root main_tree_to_execute="MainTree">
  <BehaviorTree ID="MainTree">
    <RecoveryNode number_of_retries="6" name="NavigateRecovery">
      <PipelineSequence name="NavigateWithReplanning">
        <RateController hz="1.0">
          <RecoveryNode number_of_retries="1" name="ComputePathToPose">
            <ComputePathToPose goal="{goal}" path="{path}" planner_id="GridBased"/>
            <ClearEntireCostmap name="ClearGlobalCostmap-Context" service_name="global_costmap/clear_entirely_global_costmap"/>
          </RecoveryNode>
        </RateController>
        <RecoveryNode number_of_retries="1" name="FollowPath">
          <FollowPath path="{path}" controller_id="FollowPath"/>
          <ClearEntireCostmap name="ClearLocalCostmap-Context" service_name="local_costmap/clear_entirely_local_costmap"/>
        </RecoveryNode>
      </PipelineSequence>
      <ReactiveFallback name="RecoveryFallback">
        <GoalUpdated/>
        <SequenceStar name="RecoveryActions">
          <ClearEntireCostmap name="ClearLocalCostmap-Subtree" service_name="local_costmap/clear_entirely_local_costmap"/>
          <ClearEntireCostmap name="ClearGlobalCostmap-Subtree" service_name="global_costmap/clear_entirely_global_costmap"/>
          <Spin spin_dist="1.57"/>
          <Wait wait_duration="5"/>
        </SequenceStar>
      </ReactiveFallback>
    </RecoveryNode>
  </BehaviorTree>
</root>