行为树(BT)笔记(十):封装遗留代码

在本教程中,我们将了解如何处理不适合与BehaviorTree.CPP一起使用的遗留代码。

让我们开始假设这是我的类。

// This is my custom type.
struct Point3D { double x,y,z; };

class MyLegacyMoveTo
{
public:
    bool go(Point3D goal)
    {
        printf("Going to: %f %f %f\n", goal.x, goal.y, goal.z);
        return true; // true means success in my legacy code
    }
};

我们想要创建一个名为“MoveTo”的ActionNode,它调用方法MyLegacyMoveTo :: go()

最终目标是能够在这样的树中使用此ActionNode:

 <root main_tree_to_execute = "MainTree" >
     <BehaviorTree ID="MainTree">
        <SequenceStar name="root">
            <MoveTo  goal="-1;3;0.5" />
            <MoveTo  goal="${myGoal}" />
        </SequenceStar>
     </BehaviorTree>
 </root>

我们需要做的第一件事是允许我们的库将NodeParameter(只不过是一对表示键/值的字符串)转换为Point3D。

正如我们在之前的教程中所做的那样,我们应该为convertFromString实现模板特化

Point3D的特定字符串表示由三个以分号分隔的数字组成,表示__x,y和z_。

 <root main_tree_to_execute = "MainTree" >
     <BehaviorTree ID="MainTree">
        <SequenceStar name="root">
            <MoveTo  goal="-1;3;0.5" />
            <MoveTo  goal="${myGoal}" />
        </SequenceStar>
     </BehaviorTree>
 </root>

最后,我们可以使用C ++ 11 lambda(或者,std :: bind)将方法包装到具有正确签名的函数中。

 <root main_tree_to_execute = "MainTree" >
     <BehaviorTree ID="MainTree">
        <SequenceStar name="root">
            <MoveTo  goal="-1;3;0.5" />
            <MoveTo  goal="${myGoal}" />
        </SequenceStar>
     </BehaviorTree>
 </root>
int main()
{
    using namespace BT;

    MyLegacyMoveTo move_to;

    // Here we use a lambda that captures the reference of move_to
    auto MoveToWrapperWithLambda = [&move_to](TreeNode& parent_node) -> NodeStatus
    {
        Point3D goal;
        // thanks to paren_node, you can access easily the NodeParameters and the blackboard
        parent_node.getParam("goal", goal);

        bool res = move_to.go( goal );
        // convert bool to NodeStatus
        return res ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
    };

    BehaviorTreeFactory factory;
    factory.registerSimpleAction("MoveTo", MoveToWrapperWithLambda);

    auto blackboard = Blackboard::create<BlackboardLocal>();
    auto tree = buildTreeFromText(factory, xml_text, blackboard);

    // We set the entry "myGoal" in the blackboard.
    Point3D my_goal = {3,4,5};
    blackboard->set("myGoal", my_goal);

    NodeStatus status = NodeStatus::RUNNING;
    while (status == NodeStatus::RUNNING)
    {
        status = tree.root_node->executeTick();
    }
    return 0;
}

/* Expected output:

Going to: -1.000000 3.000000 0.500000
Going to: 3.000000 4.000000 5.000000

The first MoveTo read the parameter from the string "-1;3;0.5"
whilst the second from the blackboard, that contains a copy of the Point3D my_goal.

*/

我们传递给SimpleActionNode的仿函数需要以下形式:

 BT :: NodeStatus  myFunction (BT :: TreeNode &amp ;  parent )

因此,我们可以通过访问NodeParameter

 parent.getParam()

甚至使用设置/获取Blackboard的条目

 parent.blackboard()

 

猜你喜欢

转载自blog.csdn.net/Travis_X/article/details/87776988