The XML schema
In the first tutorial this simple tree was presented.
<root BTCPP_format="4">
<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>
You may notice that:
The first tag of the tree is
<root>
. It should contain 1 or more tags<BehaviorTree>
.The tag
<BehaviorTree>
should have the attribute[ID]
.The tag
<root>
should contain the attribute[BTCPP_format]
.Each TreeNode is represented by a single tag. In particular:
- The name of the tag is the ID used to register the TreeNode in the factory.
- The attribute
[name]
refers to the name of the instance and is optional. - Ports are configured using attributes. In the previous example, the action
SaySomething
requires the input portmessage
.
In terms of number of children:
ControlNodes
contain 1 to N children.DecoratorNodes
and Subtrees contain only 1 child.ActionNodes
andConditionNodes
have no child.
Ports Remapping and pointers to Blackboards entries
As explained in the second tutorial input/output ports can be remapped using the name of an entry in the Blackboard, in other words, the key of a key/value pair of the BB.
A BB key is represented using this syntax: {key_name}
.
In the following example:
- the first child of the Sequence prints "Hello",
- the second child reads and writes the value contained in the entry of the blackboard called "my_message";
<root BTCPP_format="4" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<SaySomething message="Hello"/>
<SaySomething message="{my_message}"/>
</Sequence>
</BehaviorTree>
</root>
Compact vs Explicit representation
The following two syntaxes are both valid:
<SaySomething name="action_hello" message="Hello World"/>
<Action ID="SaySomething" name="action_hello" message="Hello World"/>
We will call the former syntax "compact" and the latter "explicit". The first example represented with the explicit syntax would become:
<root BTCPP_format="4" >
<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>
Even if the compact syntax is more convenient and easier to write, it provides
too little information about the model of the TreeNode. Tools like Groot require either
the explicit syntax or additional information.
This information can be added using the tag <TreeNodeModel>
.
To make the compact version of our tree compatible with Groot, the XML must be modified as follows:
<root BTCPP_format="4" >
<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
As we saw in this tutorial, it is possible to include a Subtree inside another tree to avoid "copy and pasting" the same tree in multiple location and to reduce complexity.
Let's say that we want to encapsulate a few actions into the behaviorTree "GraspObject" (being optional, attributes [name] are omitted for simplicity).
<root BTCPP_format="4" >
<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>
We may notice that the entire tree "GraspObject" is executed after "SaySomething".
Include external files
Since version 2.4.
You can include external files in a way that is similar to '#include \<file>' in C++. We can do this easily using the tag:
<include path="relative_or_absolute_path_to_file">
using the previous example, we may split the two behavior trees into two files:
<!-- file maintree.xml -->
<root BTCPP_format="4" >
<include path="grasp.xml"/>
<BehaviorTree ID="MainTree">
<Sequence>
<Action ID="SaySomething" message="Hello World"/>
<SubTree ID="GraspObject"/>
</Sequence>
</BehaviorTree>
</root>
<!-- file grasp.xml -->
<root BTCPP_format="4" >
<BehaviorTree ID="GraspObject">
<Sequence>
<Action ID="OpenGripper"/>
<Action ID="ApproachObject"/>
<Action ID="CloseGripper"/>
</Sequence>
</BehaviorTree>
</root>
Note "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"/>