6.行為樹(Behavior Tree)XML格式
阿新 • • 發佈:2020-12-19
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"/>