下面例子将展示SequenceNode和ReactiveSequence的不同

一个异步行为有它自己的线程;允许用户使用阻塞函数,但是要将执行流返回给到树;

//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 periodicall _halt_requested and interrupt
// this tick() if it is true.
while (!_halt_requested && count++ < 25)
{
SleepMS(10);
}

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

方法​​MoveBaseAction::tick()​​​在不主线程不同的线程中执行,主线程唤醒的​​MoveBaseAction::executeTick()​​.

自己需要实现一个有效的halt()函数;

也需要实现一个函数​​convertFromString<Pose2D>(StringView)​​;

Sequence与ReactiveSequence比较

下面是一个简单的SequenceNode

"mission started..." />
<MoveBase goal="1;2;3"/>
<SaySomething message="mission completed!"
int main()
{
using namespace DummyNodes;

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();

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

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

std::cout << std::endl;

return 0;
}
Expected output:

--- 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!"

 

注意到当executeTick()被执行的时候,MoveBase返回RUNNING,在第一次和第二次,第三次最后成功;

BatteryOK只执行了一次;

如果使用ReactiveSequence,MoveBase返回RUNNING,序列sequence重新开始从BatteryOK开始执行,这样比较合理

"mission started..." />
<MoveBase goal="1;2;3"/>
<SaySomething message="mission completed!"
Expected output:
--- 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!"