行为树BehaviorTree学习记录2_简单顺序控制实例

(为免误导,特免责声明如下:本文所有内容,只是基于个人当前理解和实际做法,后面亦会有更正和修订,但任何版本都不免有个人能力有限、理解有误或者工作环境不同的状况,故文中内容仅供参考。任何人都可以借鉴或者直接使用代码片段,但对任何直接引用或者借鉴产生的技术问题等后果,作者不承担任何责任。)

1 BT tree结构

在这里插入图片描述
一个顺序控制节点下面4个子节点:第一个是条件判断节点,后三个动作节点
就是会判断电池状态,如果正常,依次执行打开夹具,靠近物体,闭合夹具的动作,如果某一子节点返回失败,则直接返回失败,不再继续。

2 创建自己的动作节点

  • 类继承
// Example of custom SyncActionNode (synchronous action)
// without ports.
class ApproachObject : public BT::SyncActionNode
{
public:
  ApproachObject(const std::string& name) :
      BT::SyncActionNode(name, {})
  {}

  // You must override the virtual function tick()
  BT::NodeStatus tick() override
  {
    std::cout << "ApproachObject: " << this->name() << std::endl;
    return BT::NodeStatus::SUCCESS;
  }
};

上面代码创建了一个自己的动作节点类,继承自同步动作节点。必须要重载的虚函数是tick(),本例子只是输出对象的名称。其返回值必须是RUNNING, SUCCESS或FAILURE三者之一。

  • 行为绑定简单动作类

除了这种从动作节点继承来生成自己的动作节点类的方法,还有简单的生成动作节点的方法,就是dependency injection(依赖注入?依赖绑定,就是用具有一下结构的函数去绑定到BT自己的类上(它的tick函数被替代了)
BT::NodeStatus myFunction(BT::TreeNode& self)
例如:

using namespace BT;

// Simple function that return a NodeStatus
BT::NodeStatus CheckBattery()
{
  std::cout << "[ Battery: OK ]" << std::endl;
  return BT::NodeStatus::SUCCESS;
}

// We want to wrap into an ActionNode the methods open() and close()
class GripperInterface
{
public:
  GripperInterface(): _open(true) {}
    
  NodeStatus open() 
  {
    _open = true;
    std::cout << "GripperInterface::open" << std::endl;
    return NodeStatus::SUCCESS;
  }

  NodeStatus close() 
  {
    std::cout << "GripperInterface::close" << std::endl;
    _open = false;
    return NodeStatus::SUCCESS;
  }

private:
  bool _open; // shared information
};

可以用
CheckBattery()
GripperInterface::open()
GripperInterface::close()
任意一个函数创建简单动作节点SimpleActionNode。

3实例

如果行为树的XML文件my_tree.xml为如下(与页面头部的图片一致):

<root BTCPP_format="4" >
     <BehaviorTree ID="MainTree">
        <Sequence name="root_sequence">
            <CheckBattery   name="check_battery"/>
            <OpenGripper    name="open_gripper"/>
            <ApproachObject name="approach_object"/>
            <CloseGripper   name="close_gripper"/>
        </Sequence>
     </BehaviorTree>
 </root>

在代码中如果创建与xml文件定义的BT树结构一样的对象,并tick运行呢:

2.1) 注册类

首先必须把自定义的节点类注册到行为树工厂(BehaviorTreeFactory ),这样它读取xml文件后,才知道如何根据xml文件的名称去创建对应的类的对象。
从xml文件可以看出需要注册自己的类有CheckBattery ,OpenGripper ,ApproachObject 和CloseGripper 。
根据第2部分,注册方法有两种:

  • 第一种是类继承的ApproachObject 类,其注册方法是:factory.registerNodeType(“ApproachObject”);
    <>里面的C++的类名,“”里面的是这个类的标签,与xml文件里一致,这样读到xml文件的这个标签,它才知道去创建哪个类的对象。

  • 第二种是简单action类的注册,通过依赖注入的方式,绑定tick函数生成不同的简单动作类,如:
    factory.registerSimpleCondition(“CheckBattery”, & { return CheckBattery(); });
    第一个参数“”里的是类标签,与xml文件里的一致。后面的lambda函数会绑定作为这个简单动作类的tick回调。

    2.2) 读取树结构文件创建树对象
    auto tree = factory.createTreeFromFile(“./my_tree.xml”);

    2.3) 运行该树对象

tree.tickWhileRunning();

#include "behaviortree_cpp/bt_factory.h"

// file that contains the custom nodes definitions
#include "dummy_nodes.h"
using namespace DummyNodes;

int main()
{
    // We use the BehaviorTreeFactory to register our custom nodes
  BehaviorTreeFactory factory;

  // The recommended way to create a Node is through inheritance.
  factory.registerNodeType<ApproachObject>("ApproachObject");

  // Registering a SimpleActionNode using a function pointer.
  // You can use C++11 lambdas or std::bind
  factory.registerSimpleCondition("CheckBattery", [&](TreeNode&) { return CheckBattery(); });

  //You can also create SimpleActionNodes using methods of a class
  GripperInterface gripper;
  factory.registerSimpleAction("OpenGripper", [&](TreeNode&){ return gripper.open(); } );
  factory.registerSimpleAction("CloseGripper", [&](TreeNode&){ return gripper.close(); } );

  // Trees are created at deployment-time (i.e. at run-time, but only 
  // once at the beginning). 
    
  // IMPORTANT: when the object "tree" goes out of scope, all the 
  // TreeNodes are destroyed
   auto tree = factory.createTreeFromFile("./my_tree.xml");

  // To "execute" a Tree you need to "tick" it.
  // The tick is propagated to the children based on the logic of the tree.
  // In this case, the entire sequence is executed, because all the children
  // of the Sequence return SUCCESS.
  tree.tickWhileRunning();

  return 0;
}

/* Expected output:
*
  [ Battery: OK ]
  GripperInterface::open
  ApproachObject: approach_object
  GripperInterface::close
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个更详细的 `KDTree.query_ball_tree` 的示例,该示例演示如何使用 `query_ball_tree` 函数来查找 k-d 树中距离给定点一定距离内的所有点。 ```python from sklearn.neighbors import KDTree, BallTree import numpy as np # 创建一个包含10个点的二维数组 X = np.array([[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]]) # 创建一个 KDTree 对象 tree = KDTree(X) # 创建一个 BallTree 对象 ball_tree = BallTree(X) # 定义一个查询点 query_point = np.array([[5, 5]]) # 使用 KDTree 和 BallTree 对象查询距离查询点 2.0 单位以内的所有点 indices1 = tree.query_ball_point(query_point, r=2.0) indices2 = ball_tree.query_radius(query_point, r=2.0)[0] # 输出查询结果 print("使用 KDTree 对象查询结果:", indices1) print("使用 BallTree 对象查询结果:", indices2) # 使用 BallTree 对象查询距离查询点 1.0 单位以内的所有点并返回距离 indices3 = ball_tree.query_radius(query_point, r=1.0, return_distance=True) # 输出查询结果 print("使用 BallTree 对象查询结果:", indices3) ``` 输出结果为: ``` 使用 KDTree 对象查询结果: [5, 6, 7, 8] 使用 BallTree 对象查询结果: [5 6 7 8] 使用 BallTree 对象查询结果: (array([[1.41421356, 1.41421356, 1.41421356, 1.41421356]]), array([[5, 6, 7, 8]], dtype=int64)) ``` 上述代码中,我们首先创建了一个包含 10 个点的二维数组 `X`,然后使用 `KDTree` 和 `BallTree` 类来创建对应的数据结构。接下来,我们定义了一个查询点 `query_point`,并使用 `tree.query_ball_point` 和 `ball_tree.query_radius` 函数来查询距离查询点一定距离内的所有点。`query_ball_point` 函数返回一个列表,其中包含了每个点的邻居的索引;`query_radius` 函数返回一个列表,其中包含了每个点的邻居的索引和距离。我们还可以使用 `query_radius` 函数的 `return_distance` 参数来控制是否返回距离。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值