Remapping ports between Trees and SubTrees
重新映射树和子树之间的端口
在CrossDoor
示例中,我们看到一个SubTree
从其父节点(示例中的MainTree
)的角度看起来像一个单独的叶子节点。
此外,为了避免在非常大的树中发生名称冲突,任何树和子树都使用不同的黑板实例。
因此,我们需要明确地将树的端口连接到其子树的端口。
再一次, 由于这种重新映射完全在 XML 定义中完成, 您 不需要 修改您的 C++ 实现。
示例
让我们考虑这个行为树
<root main_tree_to_execute = "MainTree"><BehaviorTree ID="MainTree"><Sequence name="main_sequence"><SetBlackboard output_key="move_goal" value="1;2;3" /><SubTree ID="MoveRobot" target="move_goal" output="move_result" /><SaySomething message="{move_result}"/></Sequence></BehaviorTree><BehaviorTree ID="MoveRobot"><Fallback name="move_robot_main"><SequenceStar><MoveBase goal="{target}"/><SetBlackboard output_key="output" value="mission accomplished" /></SequenceStar><ForceFailure><SetBlackboard output_key="output" value="mission failed" /></ForceFailure></Fallback></BehaviorTree>
</root>
你可能注意到:
- 我们有一个名为
MainTree
的主树,其中包含一个名为MoveRobot
的子树 - 我们要在
MoveRobot
子树内部的端口与MainTree
中的其他端口“连接”(即“重新映射”) - 这是使用 XML 标记 完成的,其中单词 internal/external 分别指向子树和其父级
以下图片显示了这两棵不同树之间的重新映射。
请注意,该图表示的是__数据流__以及黑板中的条目,而不是行为树方面的关系。
就C++而言,我们不需要做太多。为了调试目的,我们可以使用debugMessage()
方法来显示关于黑板当前状态的一些信息。
int main()
{BT::BehaviorTreeFactory factory;factory.registerNodeType<SaySomething>("SaySomething");factory.registerNodeType<MoveBaseAction>("MoveBase");auto tree = factory.createTreeFromText(xml_text);NodeStatus status = NodeStatus::RUNNING;// Keep on ticking until you get either a SUCCESS or FAILURE statewhile( status == NodeStatus::RUNNING){status = tree.tickRoot();// IMPORTANT: add sleep to avoid busy loops.// You should use Tree::sleep(). Don't be afraid to run this at 1 KHz.tree.sleep( std::chrono::milliseconds(1) );}// let's visualize some information about the current state of the blackboards.std::cout << "--------------" << std::endl;tree.blackboard_stack[0]->debugMessage();std::cout << "--------------" << std::endl;tree.blackboard_stack[1]->debugMessage();std::cout << "--------------" << std::endl;return 0;
}/* Expected output:[ MoveBase: STARTED ]. goal: x=1 y=2.0 theta=3.00[ MoveBase: FINISHED ]Robot says: mission accomplished--------------move_result (std::string) -> fullmove_goal (Pose2D) -> full--------------output (std::string) -> remapped to parent [move_result]target (Pose2D) -> remapped to parent [move_goal]--------------
*/