The XML 格式
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>
</root>
树的第一个tag是<root>,它应当包含一个或者多个tag<BehaviorTree>.
tag<BehaviorTree>应当有属性[ID].
tag<root>应当包含属性[main_tree_to_execute]
属性[main_tree_to_execute]是强制的,如果文件包含多个<BehaviorTree>的话,其他情况就是可选的;
每一个TreeNode由一个tag来表示:
tag的名字是一个ID,用于将TreeNode在factory中进行注册;
属性[name]参考实例的名字,是可选的;
Ports用属性来配置,在先前的例子中,the action SaySomething要求输入接口 message。
就子节点的数量:
controlNodes包含一个到N个子节点;
DecoratorNodes和子树包含一个子节点;
ActionNodes和ConditionNodes没有子节点;
端口重映射和指向黑板的入口
正如第二篇教程解释的那样,输入和输出接口可以被用于重映射使用黑板上的一个入口的名字,换句话说,是黑板上键值对的键值;
一个黑板键值由如下句法表示:{key_name}
例如:
Sequence的第一个子节点输出"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>
紧凑型和具体型表示
以下两种句法都有效:
<SaySomething name="action_hello" message="Hello World"/>
<Action ID="SaySomething" name="action_hello" message="Hello World"/>
前者称之为紧凑型,后者称之为具体型
由具体型句法表示的例子如下:
<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工具要求要么是具体型句法或者附加的信息,元素<TreeNodeModel>需要被增加;
为了让紧凑型的版本适应于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>
子树
在教程this tutorial中,可以在一个树中包含另一棵树,避免了复制和粘贴同样的树在多个位置上,从而减少了复杂性。
想要去压缩更少的行为在行为树GraspObject中,如下
<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 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>
Note for ROS users
If you want to find a file inside a ROS package, you can use this syntax:
<include ros_pkg="name_package" path="path_relative_to_pkg/grasp.xml"/>