<BTEng format_version="1.0" main_tree_to_execute="main_tree">
...
</BTEng>
| Attribute | Required | Description |
|---|---|---|
format_version |
no | Schema version (currently 1.0) |
main_tree_to_execute |
no | ID of tree to run (default: first <Tree>) |
<Tree ID="my_tree">
<!-- exactly one root node -->
<Sequence name="root">
...
</Sequence>
</Tree>
Each <Tree> has exactly one root child. Multiple <Tree> elements allowed (subtrees).
<Sequence name="optional_label">
...children...
</Sequence>
<Fallback name="..."> <!-- also: Selector -->
...
</Fallback>
<Parallel success_threshold="2" failure_threshold="1">
...
</Parallel>
<ReactiveSequence>
...
</ReactiveSequence>
<ReactiveFallback>
...
</ReactiveFallback>
Parallel attributes:
success_threshold: integer, -1 means all children (default)failure_threshold: integer, default 1<Inverter>
<Action ID="..."/>
</Inverter>
<Retry max_attempts="5">
<Action ID="..."/>
</Retry>
<Timeout duration="2.5"> <!-- seconds -->
<Action ID="..."/>
</Timeout>
<RateController hz="10.0">
<Action ID="..."/>
</RateController>
<ForceSuccess>
<Action ID="..."/>
</ForceSuccess>
<ForceFailure>
<Condition ID="..."/>
</ForceFailure>
<!-- Look up by ID in NodeFactory registry -->
<Action ID="MyAction" param1="value" port1="{bb_key}"/>
<Condition ID="MyCondition"/>
The tags Action / Condition are semantic — both look up by ID in the
NodeFactory. Unrecognised tags are also looked up by name directly in the factory.
<Action ID="Move" target="{goal_position}" speed="1.5"/>
| Syntax | Meaning |
|---|---|
attr="{key}" |
Blackboard read/write using key key |
attr="value" |
Static string parameter |
Port direction (input vs output) is determined from TreeNodesModel declarations, or
defaults to input if absent.
InputPort(name, default=...) declared in provided_ports() is honoured at runtime.
When an attribute is absent from the XML element, the declared default is used.
When the attribute is present, the XML value overrides the default.
@register_node()
class MoveJ(StatefulActionNode):
@classmethod
def provided_ports(cls):
return [InputPort("speed", default="1.05")]
<!-- speed = "1.05" (default applied) -->
<Action ID="MoveJ"/>
<!-- speed = "0.5" (XML overrides default) -->
<Action ID="MoveJ" speed="0.5"/>
<!-- speed read from blackboard key "joint_speed" -->
<Action ID="MoveJ" speed="{joint_speed}"/>
<SubTree ID="pick" target="{current_goal}" drop_zone="{bin}"/>
<Tree ID="pick"> defined in the same filetarget="{current_goal}" creates a child Blackboard where local key target
maps to parent key current_goalkey="fixed") are set directly in the child Blackboard<Node type="MyCustomNode" param="value" input="{bb_key}"/>
Use when you want to avoid tag-name collisions or prefer explicit typing. type must
be registered in NodeFactory. No parser changes needed for new types.
Declares port metadata — used to determine whether a {key} attribute is an input or
output port. Optional; parser defaults to input if absent.
<TreeNodesModel>
<Action ID="Move">
<input_port name="target" default="home"/>
<output_port name="arrival_status"/>
</Action>
<Condition ID="IsReady"/>
</TreeNodesModel>
The default attribute on <input_port> is informational in the model XML; runtime
defaults come from InputPort(default=...) declared in provided_ports().
<?xml version="1.0" encoding="UTF-8"?>
<BTEng format_version="1.0" main_tree_to_execute="main">
<Tree ID="main">
<ReactiveFallback name="root">
<ReactiveSequence name="navigate">
<Condition ID="IsPathClear"/>
<Timeout duration="10.0">
<Action ID="Navigate" target="{goal}"/>
</Timeout>
</ReactiveSequence>
<SubTree ID="recovery" goal="{goal}"/>
</ReactiveFallback>
</Tree>
<Tree ID="recovery">
<Sequence name="recover_seq">
<Action ID="BackUp"/>
<Action ID="Replan" target="{goal}"/>
</Sequence>
</Tree>
<TreeNodesModel>
<Condition ID="IsPathClear"/>
<Action ID="Navigate">
<input_port name="target"/>
</Action>
<Action ID="BackUp"/>
<Action ID="Replan">
<input_port name="target"/>
</Action>
</TreeNodesModel>
</BTEng>
New node types require no parser changes:
@register_node()
class MySpecialNode(ActionNode):
@classmethod
def provided_ports(cls):
return [InputPort("param", default="default_val")]
<Action ID="MySpecialNode" param="{key}"/>
<!-- or explicit generic form -->
<Node type="MySpecialNode" param="static_value"/>
The parser resolves ID / type at tree-build time via NodeFactory and seeds port
defaults from the node manifest before processing XML attributes.
::: bteng.xml_parser.parser.XMLTreeParser options: show_root_heading: true heading_level: 3 filters: [”!^_”]