How to create a BehaviorTree

行为树类似于状态机,只是一种机制,在正确的条件下,正确的时间来唤醒回调函数。

进一步,我们使用callback和tick来相互替换;

这些回调函数里面具体执行什么取决于你;

怎样创建你自己的ActionNodes

默认的方法是采用继承的方式来实现一个TreeNode:

//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::out << "ApproachObject: " << this->name() <<std::endl;
    return BT::NodeStatus::SUCCESS;
  }
};

任何一个TreeNode的实例需要有一个名字,但不要求是唯一的;

方法tick()是实际行为发生的地方。它必须总是返回一个节点状态,如RUNNING,SUCCESS或者FAILURE。

另外,也可以用依赖注入的方式创建一个TreeNode,给定一个函数指针(如functor)

对functor唯一的要求是具有如下之一的表示:

    BT::NodeStatus myFunction()
    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
};

我们可以构建一个SimpleActionNode从下面的functors中的任何一个:

  • CheckBattery()
  • GripperInterface::open()
  • GripperInterface::close()

用一个XML来动态创建一棵树

XML文件命名为my_tree.xml:

 <root main_tree_to_execute = "MainTree" >
     <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>

You can find more details about the XML schema here.

首先比如注册我们自定义的TreeNodes到BehaviorTreeFactory中,然后从文件或者text中加载XML;

在XML中使用的标志符必须与注册TreeNodes中使用的一致;

属性name表示实例的名字,它是可选的;

#include "behaviortree_cpp_v3/bt_factory.h"

// file that contains the custom nodes definitions
#include "dummy_nodes.h"

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

    // Note: the name used to register should be the same used in the XML.
    using namespace DummyNodes;

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

    // Registering a SimpleActionNode using a function pointer.
    // you may also use C++11 lambdas instead of std::bind
    factory.registerSimpleCondition("CheckBattery", std::bind(CheckBattery));

    //You can also create SimpleActionNodes using methods of a class
    GripperInterface gripper;
    factory.registerSimpleAction("OpenGripper", 
                                 std::bind(&GripperInterface::open, &gripper));
    factory.registerSimpleAction("CloseGripper", 
                                 std::bind(&GripperInterface::close, &gripper));

    // 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.tickRoot();

    return 0;
}

/* Expected output:
*
       [ Battery: OK ]
       GripperInterface::open
       ApproachObject: approach_object
       GripperInterface::close
*/
原文地址:https://www.cnblogs.com/gary-guo/p/14694207.html