行为树中使用xml来加载树
【原英文链接】The XML format - BehaviorTree.CPP
我们来看一个例子
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<SaySomething name="action_hello" message="Hello"/>
<OpenGripper name="open_gripper"/>
<ApproachObject name="approach_object"/>
<CloseGripper name="close_gripper"/>
</Sequence>
</BehaviorTree>
</root>
- 第一个标签(tag)是 ,它包含 一个或多个
- 应该有 [ID] 属性
- 应该包含属性 [main_tree_to_execute]
- 如果文件包含多个,则属性[main_tree_to_execute]是必需的,否则是可选的。
- 每个TreeNode都由一个标记表示。特别地:
标签的名字是在用工厂(factory)注册的ID。
属性[name]是指实例的名称,是可选的。
端口(ports)是使用属性配置的。上面例子中,SaySomething 需要输入端口 message
就子节点而言
- 控制节点包含 1到N个子节点
- 描述节点 和 子树(Subtrees) 只有一个子节点
- 动作节点(ActionNodes) 和 条件节点 (ConditionNodes)没有子节点
端口重新映射和指向黑板条目的指针(Ports Remapping and pointers to Blackboards entries)
在下面例子中
第一个序列节点的子节点将打印 “Hello”
第二个子节点 读和写 黑板条目中包含“my_message”;的值
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<SaySomething message="Hello"/>
<SaySomething message="{my_message}"/>
</Sequence>
</BehaviorTree>
</root>
紧凑与显式表示(Compact vs Explicit representation)
以下两种语法都有效:
<SaySomething name="action_hello" message="Hello World"/>
<Action ID="SaySomething" name="action_hello" message="Hello World"/>
我们将前者称为“compact”,后者称为“explicit”。用显式语法表示的第一个示例将是:
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<Action ID="SaySomething" name="action_hello" message="Hello"/>
<Action ID="OpenGripper" name="open_gripper"/>
<Action ID="ApproachObject" name="approach_object"/>
<Action ID="CloseGripper" name="close_gripper"/>
</Sequence>
</BehaviorTree>
</root>
即使紧凑语法更方便、更易于编写,但它提供的有关TreeNode模型的信息太少。像Groot这样的工具需要明确的语法或附加信息。可以使用标记添加此信息。
为了使树的"compact"版本与Groot兼容,必须按如下方式修改XML:
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<SaySomething name="action_hello" message="Hello"/>
<OpenGripper name="open_gripper"/>
<ApproachObject name="approach_object"/>
<CloseGripper name="close_gripper"/>
</Sequence>
</BehaviorTree>
<!-- the BT executor don't require this, but Groot does -->
<TreeNodeModel>
<Action ID="SaySomething">
<input_port name="message" type="std::string" />
</Action>
<Action ID="OpenGripper"/>
<Action ID="ApproachObject"/>
<Action ID="CloseGripper"/>
</TreeNodeModel>
</root>
Subtrees(子树)
正如我们在本教程中看到的,可以在另一棵树中包含一个子树,以避免在多个位置“复制和粘贴”同一棵树,并降低复杂性。
假设我们想将一些操作封装到行为树“GraspObject”中(可选,为了简单起见,省略了属性[name])。
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence>
<Action ID="SaySomething" message="Hello World"/>
<SubTree ID="GraspObject"/>
</Sequence>
</BehaviorTree>
<BehaviorTree ID="GraspObject">
<Sequence>
<Action ID="OpenGripper"/>
<Action ID="ApproachObject"/>
<Action ID="CloseGripper"/>
</Sequence>
</BehaviorTree>
</root>
我们可能会注意到,整个树“GraspObject”是在“SaySomething”之后执行的。
Include external files(包括外部文件)
从 2.4 版本起
您可以采用类似于C++中#include的方式包含外部文件。我们可以使用 tag轻松完成此操作:
<include path="relative_or_absolute_path_to_file">
使用前面的示例,我们可以将两个行为树拆分为两个文件:
<!-- file maintree.xml -->
<root main_tree_to_execute = "MainTree" >
<include path="grasp.xml"/>
<BehaviorTree ID="MainTree">
<Sequence>
<Action ID="SaySomething" message="Hello World"/>
<SubTree ID="GraspObject"/>
</Sequence>
</BehaviorTree>
</root>
<!-- file grasp.xml -->
<root main_tree_to_execute = "GraspObject" >
<BehaviorTree ID="GraspObject">
<Sequence>
<Action ID="OpenGripper"/>
<Action ID="ApproachObject"/>
<Action ID="CloseGripper"/>
</Sequence>
</BehaviorTree>
</root>
【说明】
BehaviorTree.CPP行为树学习系列是翻译自源英文网站,由于个人知识能力水平有限,如有错误的地方,请在评论区留言,会不断修改和完善的