The XML format
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>
您可能會注意到:
- 樹的第一個標簽是
<root>。它應包含1個或多個標簽<BehaviorTree>。 - 標簽
<BehaviorTree>應具有屬性[ID]。 - 標簽
<root>應包含屬性[main_tree_to_execute]。 [main_tree_to_execute]如果文件包含多個<BehaviorTree>,則該屬性為必填,否則為可選。- 每個
TreeNode由單個標簽表示。特別是:- 標簽的名稱是用於在工廠中注冊
TreeNode的ID。 - 該屬性
[name]引用實例的名稱,並且是可選的。 - 使用屬性配置端口。在前面的示例中,該操作
SaySomething需要輸入端口message。
- 標簽的名稱是用於在工廠中注冊
- 在子節點的數量方面:
ControlNodes容納1到N個子節點。DecoratorNodes和子樹僅包含1個子項。ActionNodes和ConditionNodes有沒有子項。
端口重新映射和指向Blackboards條目的指針
如第二篇教程中所述,可以使用Blackboard中條目的名稱(即BB的鍵/值對的鍵)來重新映射輸入/輸出端口。
BB密鑰使用以下語法表示:{key_name}。
在以下示例中:
- 序列的第一個子節點打印
"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>
您可以在此處下載XML模式。
子樹
正如我們在本教程中所看到的,可以在另一棵樹中包括一個子樹,以避免在多個位置“復制和粘貼”同一棵樹並降低復雜性。
假設我們想將很少的動作封裝到behaviorTree"GraspObject"中(為方便起見,省略了屬性[name])。
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence>
<Action ID="SaySomething" message="Hello World"/>
<Subtree ID="GraspObject"/> <!-- "GraspObject" -->
</Sequence>
</BehaviorTree>
<BehaviorTree ID="GraspObject">
<Sequence>
<Action ID="OpenGripper"/>
<Action ID="ApproachObject"/>
<Action ID="CloseGripper"/>
</Sequence>
</BehaviorTree>
</root>
我們可能會注意到,整個樹"GraspObject"在"SaySomething"之后執行。
包括外部文件
從2.4版本開始。
您可以采用類似於#include的方式包含外部文件在C++中。我們可以使用標簽輕松地做到這一點:
<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>
^ x ^
ROS用戶注意事項
如果要在ROS包中查找文件,可以使用以下語法:
<include ros_pkg="name_package" path="path_relative_to_pkg/grasp.xml"/>
