行为树(BT)笔记(四):如何创建BehaviorTree

您主要有两种方法来创建行为树。

  • 静态地,在编译时。
  • 动态地,在运行时,即解析文件。

强烈建议你使用后一种方法,但为了完整性,我们将描述前者。

 

如何创建自己的ActionNodes

你能在这里找到源码:sample_nodes/dummy_nodes.h.

// Example of custom SyncActionNode (synchronous Action)
class ApproachObject: public BT::SyncActionNode
{
public:
    ApproachObject(const std::string& name):
        BT::SyncActionNode(name) {}

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

如你所见:

  • TreeNode的任何实例都有一个名称。该标识符旨在用户可读,并且不需要是唯一的。

  • tick()是实际Action发生的地方。它必须返回NodeStatus,即RUNNING,SUCCESS或FAILURE。

  • halt()用于停止异步Action。ApproachObject不需要它。

或者,我们可以使用依赖项注入来创建一个指定函数指针的TreeNode。

仿函数的唯一要求是具有以下任一特征:

    BT::NodeStatus myFunction()
    BT::NodeStatus myFunction(BT::TreeNode& self) 

例如:

using namespace BT;

NodeStatus SayHello() {
    std::cout << "Robot says Hello" << std::endl;
    return NodeStatus::SUCCESS;
}

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;
};

我们可以从以下这些仿函数构建一个SimpleActionNode

  • SayHello()
  • GripperInterface::open()
  • GripperInterface::close()

静态树

让我们创建TreeNodes的实例并将它们组成一个树。

  • BT::SequenceNode 是库提供的内置ControlNode。
  • BT::SimpleActionNode 是一个通过仿函数创建的同步ActionNode。
  • DummyNodes::ApproachObject 是我们用户定义的ActionNode。
#include "dummy_nodes.h"

int main()
{
    using namespace BT;
    using namespace DummyNodes;

    GripperInterface gi;

    SequenceNode sequence_root("sequence");
    SimpleActionNode say_hello("action_hello", std::bind(SayHello) );
    SimpleActionNode open_gripper("open_gripper",   
                                  std::bind( &GripperInterface::open,  &gi) );
    SimpleActionNode close_gripper("close_gripper", 
                                   std::bind( &GripperInterface::close, &gi) );
    ApproachObject approach_object("approach_object");

    // Add children to the sequence. 
    // They will be executed in the same order they are added.
    sequence_root.addChild(&say_hello);
    sequence_root.addChild(&open_gripper);
    sequence_root.addChild(&approach_object);
    sequence_root.addChild(&close_gripper);

    sequence_root.executeTick();
    return 0;
}

/* Expected output:

    Robot says: "Hello!!!"
    GripperInterface::open
    ApproachObject: approach_object
    GripperInterface::close
*/

动态创建的树

将以下XML存储在my_tree.xml文件中

请注意,以下语法也有效:

 <root main_tree_to_execute = "MainTree" >
     <BehaviorTree ID="MainTree">
        <Sequence name="root_sequence">
            <SayHello       name="action_hello"/>
            <OpenGripper    name="open_gripper"/>
            <ApproachObject name="approach_object"/>
            <CloseGripper   name="close_gripper"/>
        </Sequence>
     </BehaviorTree>
 </root>

我们必须首先将自定义TreeNode注册到其中BehaviorTreeFactory ,然后从文件或文本加载XML。

XML中使用的标识符必须与用于注册TreeNode的标识符一致。

属性“name”表示实例的名称,它是可选的。

#include "behaviortree_cpp/xml_parsing.h"
#include "Blackboard/blackboard_local.h"
#include "dummy_nodes.h"

int main()
{
    using namespace BT;
    using namespace DummyNodes;

    GripperInterface gi;    
    BehaviorTreeFactory factory;

    factory.registerSimpleAction("SayHello", std::bind(SayHello) );
    factory.registerSimpleAction("OpenGripper", 
                                 std::bind( &GripperInterface::open, &gi));
    factory.registerSimpleAction("CloseGripper", 
                                  std::bind( &GripperInterface::close, &gi));

    factory.registerNodeType<ApproachObject>("ApproachObject");

    // IMPORTANT: when the object "tree" goes out of scope,
    // all the TreeNodes instances are destroyed
    auto tree = buildTreeFromFile(factory, "./my_tree.xml");

    tree.root_node->executeTick();
    return 0;
}

/* Expected output:

    Robot says: "Hello!!!"
    GripperInterface::open
    ApproachObject: approach_object
    GripperInterface::close
*/

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值