BehaviorTree.CPP行为树学习:Reactive Trees

The next example shows the difference between a SequenceNode and a ReactiveSequence.

接下来的例子将会展示SequenceNode和ReactiveSequence的区别

原英文链接:Tutorial 4: Reactive Trees - BehaviorTree.CPP

An Asynchronous Action has it's own thread. This allows the user to use blocking functions but to return the flow of execution to the tree. 

异步的动作有自己的线程。这允许用户使用阻塞函数将执行流程返回到行为树

Learn more about Asynchronous Actions

了解有关异步操作的详细信息‎

Users should fully understand how Concurrency is achieved in BT.CPP and learn best practices about how to develop their own Asynchronous Actions. You will find an extensive article here.

‎(用户应充分了解如何在 BT.CPP 中实现并发并了解如何开发自己的异步操作,您将‎‎在这里‎‎找到一篇广泛的文章。‎)

// Custom type
struct Pose2D
{
    double x, y, theta;
};

class MoveBaseAction : public AsyncActionNode
{
  public:
    MoveBaseAction(const std::string& name, const NodeConfiguration& config)
      : AsyncActionNode(name, config)
    { }

    static PortsList providedPorts()
    {
        return{ InputPort<Pose2D>("goal") };
    }

    NodeStatus tick() override;

    // This overloaded method is used to stop the execution of this node.
    void halt() override
    {
        _halt_requested.store(true);
    }

  private:
    std::atomic_bool _halt_requested;
};

//-------------------------

NodeStatus MoveBaseAction::tick()
{
    Pose2D goal;
    if ( !getInput<Pose2D>("goal", goal))
    {
        throw RuntimeError("missing required input [goal]");
    }

    printf("[ MoveBase: STARTED ]. goal: x=%.f y=%.1f theta=%.2f\n", 
           goal.x, goal.y, goal.theta);

    _halt_requested.store(false);
    int count = 0;

    // Pretend that "computing" takes 250 milliseconds.
    // It is up to you to check periodically _halt_requested and interrupt
    // this tick() if it is true.
    while (!_halt_requested && count++ < 25)
    {
        std::this_thread::sleep_for( std::chrono::milliseconds(10) );
    }

    std::cout << "[ MoveBase: FINISHED ]" << std::endl;
    return _halt_requested ? NodeStatus::FAILURE : NodeStatus::SUCCESS;
}

 The method MoveBaseAction::tick() is executed in a thread different from the main thread that invoked MoveBaseAction::executeTick().

(MoveBaseAction::tick()在一个不同于main主线程里面,它调用了 MoveBaseAction::executeTick().)

You are responsible for the implementation of a valid halt() functionality.

你有负责实现终止 函数的功能

The user must also implement convertFromString<Pose2D>(StringView), as shown in the previous tutorial.

用户还必须实现convertFromString<Pose2D>(StringView),如前一教程所示。

Sequence VS ReactiveSequence

这是一个Sequence例子

 <root>
     <BehaviorTree>
        <Sequence>
            <BatteryOK/>
            <SaySomething   message="mission started..." />
            <MoveBase       goal="1;2;3"/>
            <SaySomething   message="mission completed!" />
        </Sequence>
     </BehaviorTree>
 </root>
int main()
{
    using namespace DummyNodes;
    using std::chrono::milliseconds;

    BehaviorTreeFactory factory;
    factory.registerSimpleCondition("BatteryOK", std::bind(CheckBattery));
    factory.registerNodeType<MoveBaseAction>("MoveBase");
    factory.registerNodeType<SaySomething>("SaySomething");

    auto tree = factory.createTreeFromText(xml_text);

    NodeStatus status;

    std::cout << "\n--- 1st executeTick() ---" << std::endl;
    status = tree.tickRoot();

    tree.sleep( milliseconds(150) );
    std::cout << "\n--- 2nd executeTick() ---" << std::endl;
    status = tree.tickRoot();

    tree.sleep( milliseconds(150) );
    std::cout << "\n--- 3rd executeTick() ---" << std::endl;
    status = tree.tickRoot();

    std::cout << std::endl;

    return 0;
}

 

期望的输出:

    --- 1st executeTick() ---
    [ Battery: OK ]
    Robot says: "mission started..."
    [ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00

    --- 2nd executeTick() ---
    [ MoveBase: FINISHED ]

    --- 3rd executeTick() ---
    Robot says: "mission completed!"

You may have noticed that when executeTick() was called, MoveBase returned RUNNING the 1st and 2nd time, and eventually SUCCESS the 3rd time.

你会发现当executeTick()被调用时,MoveBase返回运行中在第一和第二次,在第三次返回成功) 

BatteryOK is executed only once.

BatteryOK只执行一次

If we use a ReactiveSequence instead, when the child MoveBase returns RUNNING, the sequence is restarted and the condition BatteryOK is executed again.

如果我们使用的是ReactiveSequence,当子节点MoveBase返回运行中,序列节点会重启并且BatteryOK会再次被执行

If, at any point, BatteryOK returned FAILURE, the MoveBase action would be interrupted (halted, to be specific).

如果在一些点,BatteryOK 返回失败,MoveBase将会被中断,具体来说会停止

 

 <root>
     <BehaviorTree>
        <ReactiveSequence>
            <BatteryOK/>
            <Sequence>
                <SaySomething   message="mission started..." />
                <MoveBase       goal="1;2;3"/>
                <SaySomething   message="mission completed!" />
            </Sequence>
        </ReactiveSequence>
     </BehaviorTree>
 </root>

 

期望输出:

    --- 1st executeTick() ---
    [ Battery: OK ]
    Robot says: "mission started..."
    [ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00

    --- 2nd executeTick() ---
    [ Battery: OK ]
    [ MoveBase: FINISHED ]

    --- 3rd executeTick() ---
    [ Battery: OK ]
    Robot says: "mission completed!"

 Event Driven trees?

(事件驱动树?)

important

We used the command tree.sleep() instead of std::this_thread::sleep_for() for a reason.

请注意,我们使用tree.sleep()而不是std::this_thread::sleep_for()是有原因的

 The method Tree::sleep() should be preferred, because it can be interrupted by a Node in the tree when "something changed". Tree::sleep() will be interrupted when an AsyncActionNode::tick() is completed or, more generally, when the method TreeNode::emitStateChanged() is invoked.

应该首选方法Tree::sleep(),因为当“有什么变化”时,树中的节点可以中断它。当AsyncActionNode::tick()完成时,或者更一般地说,当调用TreeNode::emitStateChanged()方法时,Tree::sleep()将被中断。

【说明】

BehaviorTree.CPP行为树学习系列是翻译自源英文网站,由于个人知识能力水平有限,如有错误的地方,请在评论区留言,会不断修改和完善的

本想全部都翻译一遍的,发现已经有大佬翻译过了,本着不重复造轮子的原则,大佬的翻译部分链接为

https://blog.csdn.net/qq_37766828/category_11885955.html

这里是目前为止后面未翻译的部分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值