bteng

BTEng XML Specification

Root Element

<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 Definition

<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).


Built-in Node Tags

Control Nodes

<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:

Decorators

<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>

Leaf Nodes

<!-- 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.


Port Remapping

<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.

Input port defaults

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

<SubTree ID="pick" target="{current_goal}" drop_zone="{bin}"/>

Generic Node Syntax

<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.


TreeNodesModel (optional)

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().


Full Example

<?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>

Extensibility

New node types require no parser changes:

  1. Define a class and register it:
    @register_node()
    class MySpecialNode(ActionNode):
        @classmethod
        def provided_ports(cls):
            return [InputPort("param", default="default_val")]
    
  2. Use in XML:
    <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.


API Reference

::: bteng.xml_parser.parser.XMLTreeParser options: show_root_heading: true heading_level: 3 filters: [”!^_”]