<BehaviorTree ID="DoWave">
<Sequence>
<SubTree ID="MoveToEndPosition"/>
<SkipUnlessUpdated entry="@repeat">
<SubTree ID="RepeatWave"
repeat="{@repeat}"/>
</SkipUnlessUpdated>
<SubTree ID="MoveToCenterPosition"/>
</Sequence>
</BehaviorTree>

Two underlying implementations are made reusable through YAML configurations

MoveToTheSide:
class_name: fosdem26_autoapms_behavior::VelocityPub
topic: /robot/velocity_cmd
port_default:
# Negative for moving left - positive for right
velocity: -1.0

StopMovement:
class_name: fosdem26_autoapms_behavior::VelocityPub
topic: /robot/velocity_cmd
port_default:
# Zero velocity to stop the hand
velocity: 0.0

HandReachedEndPosition:
class_name: fosdem26_autoapms_behavior::PositionInRange
topic: /robot/position
port_default:
# Negative for end on the left - positive for right
low: -1.0
high: -0.95

HandIsCentered:
class_name: fosdem26_autoapms_behavior::PositionInRange
topic: /robot/position
port_default:
# Centered around 0.0
low: -0.1
high: 0.1
Register reusable C++ implementations
auto_apms_behavior_tree_register_nodes(
behavior_tree_nodes # Target library
"fosdem26_autoapms_behavior::VelocityPub"
"fosdem26_autoapms_behavior::PositionInRange"
)
Register specific manifests for your use-case
set(SIDE left) # and/or right
auto_apms_behavior_tree_register_nodes(
wave_${SIDE} # Alias for node manifest
NODE_MANIFEST
"config/common_nodes.yaml"
"config/wave_${SIDE}_nodes.yaml"
)
CMake macros in an ament_cmake packageWorkspace-wide reusable node registrations
Compile-time validation avoids runtime errors
Automatic node model generation
→ XML file for visual editors
→ C++ header for builder API
Registration: Two behaviors — One definition
auto_apms_behavior_tree_register_trees(
"behavior/tree/generic_wave.xml"
ALIAS_NAMESPACE wave_${SIDE}
NODE_MANIFEST "fosdem26_autoapms_behavior::wave_${SIDE}"
)
Deployment: ros2 behavior CLI tool
ros2 behavior run <package>::<namespace>::<tree> --blackboard <key>:=<value> ...
<package> Name of registering package
<namespace> Namespace defined during registration
<tree> Behavior Tree ID from XML definition

Deployment:
Wave left
ros2 behavior run \
fosdem26_autoapms_behavior::wave_left::DoWave \
--blackboard repeat:=2
Wave right
ros2 behavior run \
fosdem26_autoapms_behavior::wave_right::DoWave \
--blackboard repeat:=2
User-defined behavior tree generation logic
What if we want the hand to move like this?
Left → Left → Right → Right → Left → Right
l means left — r means rightl;l;r;r;l;r
TreeDocument doc, doc_left, doc_right;
doc_left.newTreeFromResource("fosdem26_autoapms_behavior::wave_left::MoveToEndPosition")
.setName("MoveLeft");
doc_right.newTreeFromResource("fosdem26_autoapms_behavior::wave_right::MoveToEndPosition")
.setName("MoveRight");
TreeDocument::TreeElement tree = doc.newTree("CustomBehavior").makeRoot();
model::Sequence sequence = tree.insertNode<model::Sequence>();
for (const std::string dir : auto_apms_util::splitString(build_request, ';')) {
if (dir == "l")
sequence.insertSubTreeNode(doc_left.getTree("MoveLeft"));
else if (dir == "r")
sequence.insertSubTreeNode(doc_right.getTree("MoveRight"));
}
return tree;
Registration: Register build handler and assign to behavior
auto_apms_behavior_tree_register_build_handlers(
custom_build_handler # Target library
"fosdem26_autoapms_behavior::CustomBuilder"
)
auto_apms_behavior_tree_register_behavior(
"l;l;r;r;l;r" # May also be defined at runtime
ALIAS "custom_wave"
BUILD_HANDLER "fosdem26_autoapms_behavior::CustomBuilder"
CATEGORY "custom"
)
Deployment: ros2 behavior CLI tool
ros2 behavior run <package>::<alias>
<package> Name of registering package <alias> Behavior alias defined during registration

Deployment:
Static resource
ros2 behavior run \
fosdem26_autoapms_behavior::custom_wave
Dynamic request
ros2 behavior run \
--build-request "l;l;r;r;l;r" \
--build-handler fosdem26_autoapms_behavior::CustomBuilder
string build_request
string build_handler
string entry_point
string node_manifest
uint8 tree_result
ros2 run auto_apms_behavior_tree tree_executor
sudo apt install ros-$ROS_DISTRO-auto-apms-behavior-tree
sudo apt install ros-$ROS_DISTRO-auto-apms-ros2behavior
Full example code on GitHub
fosdem26-devtalk-autoapms
User Guide & API Docs
autoapms.github.io/auto-apms-guide
AI Generated Docs & Interactive Guide
deepwiki.com/AutoAPMS/auto-apms
SPEAKER NOTES: - Set the context: robotics needs hierarchical decision making - Not everything can be FSMs - BTs provide modularity, composability and a neat way to model reactivity
SPEAKER NOTES: - AutoAPMS targets the gap between raw BT.CPP and application development - Makes C++ BT development as accessible as Python approaches Problems with existing solutions: - **Python implementations** → Limited performance, harder ROS 2 integration - **Manual C++ setup** → High configuration overhead, steep learning curve - **Domain-specific frameworks** → Not generalizable (e.g., nav2_behavior_tree)
SPEAKER NOTES: - BehaviorTree.ROS2 exists but provides only basic integration - Still requires manual registration, configuration, and deployment - Behavior Trees in C++ still lack quality of life features compared to Python counterparts
Overview of robot that "moves a hand" (visualized in the terminal)
The robot has a write-only velocity and a read-only position interface for its arm
In the following we implement a demo that creates a "wave behavior" by using the velocity interface (write) and the position interface (read)
Which nodes do we need to put inside the subtrees?
Highly flexible behavior definition. Multiple ways to customize the build pipeline
User has freedom of designing the pipeline according to his needs but is also responsible for maintaining consistency
"Node Manifest" and "Build Handler" are core concepts that we should have a closer look at
Not only static behavior resources but dynamically interpreted
Ready for you to tailor to your specific needs