AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem
AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem
FOSDEM 2026 Robotics and Simulation
Robin Müller
Research Associate | PhD Candidate
Technical University Darmstadt

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Why Behavior Trees?

Intelligent robotics require decision making capabilities and reactive mechanisms for

  • Navigation in dynamic environments
  • Interactive manipulation tasks
  • Resilient operations in general
Behavior trees promise composability, modularity, and reactivity

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Framework Comparison

ROS 2 Integration Core Library Language Versatility Functional Extensibility Developer Experience Scalability
py_trees_ros py_trees Python 🟢 🟢 🟢 🟡
ros2_ros_bt_py (Monorepo) Python 🟡 🟢 🟢 🟡
BehaviorTree.ROS2 BehaviorTree.CPP C++ 🟢 🟡 🟡 🟡
nav2_behavior_tree BehaviorTree.CPP C++ 🔴 🟡 🔴 🟡
AutoAPMS BehaviorTree.CPP C++ 🟢 🟢 🟢 🟢

🟢 High/Good | 🟡 Medium/Problematic | 🔴 Low/Bad

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

AutoAPMS Design Goals

  1. Domain-agnostic C++ development framework for behavior-based control and automated planning

  2. Reduced configuration overhead and lower entry barrier

  3. Focus on modularity and reusability for distributed workspaces and large projects

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

So how does it work?

Technical walkthrough

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Robot Architecture

Behavior Trees represent policies/plans


They utilize the robot's capabilities through clients/nodes

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Behavior: Wave Hand

Sensor
for reading hand position

float64 position

Actuator
for moving hand translationally

float64 velocity

receive





send

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

The Build Request

Encoded using BT.CPP XML schema

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

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

The Node Manifest

Two underlying implementations are made reusable through YAML configurations

center

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

center

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

center

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

center

HandIsCentered:
  class_name: fosdem26_autoapms_behavior::PositionInRange
  topic: /robot/position
  port_default:
    # Centered around 0.0
    low: -0.1
    high: 0.1
AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

The Node Manifest

  1. Register reusable C++ implementations

    auto_apms_behavior_tree_register_nodes(
      behavior_tree_nodes  # Target library
      "fosdem26_autoapms_behavior::VelocityPub"
      "fosdem26_autoapms_behavior::PositionInRange"
    )
    
  2. 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"
    )
    

Easy configuration using CMake macros in an ament_cmake package

Key benefits:

  • Workspace-wide reusable node registrations

  • Compile-time validation avoids runtime errors

  • Automatic node model generation

    → XML file for visual editors
    → C++ header for builder API

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Deploying the Behavior Tree

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

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Deploying the Behavior Tree

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
AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Customizable Behavior Generation

More than just plain behavior trees

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Customizable Behavior Generation

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

The Build Handler

Concept Idea

User-defined behavior tree generation logic

What if we want the hand to move like this?
Left → Left → Right → Right → Left → Right

→ New build request message format

  • l means left — r means right
  • E.g. l;l;r;r;l;r

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

C++ Behavior Tree Builder API

  1. Load predefined subtrees
    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");
    
  2. Create the custom tree by parsing the build request
    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;
    
AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Deploying Custom Behavior Definitions

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

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Deploying Custom Behavior Definitions

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
AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Runtime-Configurable Executor

ROS 2 Action

string build_request
string build_handler
string entry_point
string node_manifest
uint8 tree_result  

Goal  

  Result

Many behavior definitions — One powerful ROS 2 Node

ros2 run auto_apms_behavior_tree tree_executor

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Now on ROS Index 🎉

Core tools

sudo apt install ros-$ROS_DISTRO-auto-apms-behavior-tree

ROS 2 CLI integration

sudo apt install ros-$ROS_DISTRO-auto-apms-ros2behavior

Give it a try and streamline your ROS 2 project with AutoAPMS!

center

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem

Coming Soon

AutoAPMS: Lightweight and versatile integration of behavior trees into the ROS 2 ecosystem
Thank You
FOSDEM 2026 Robotics and Simulation

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

This work has been funded by the LOEWE initiative (Hesse, Germany) within the emergenCITY center [LOEWE/1/12/519/03/05.001(0016)/72]

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