Python Behavior Trees for Robotics — Core Concepts
What Is a Behavior Tree?
A behavior tree (BT) is a directed acyclic graph that models decision-making as a hierarchy of tasks. Each node returns one of three statuses: SUCCESS, FAILURE, or RUNNING (still working on it). The tree is “ticked” repeatedly — typically 10–30 times per second — and each tick traverses the tree to determine what the robot should be doing right now.
Behavior trees originated in the video game industry (Halo 2, circa 2004) and were adopted by robotics because they solve the same problem: managing complex, reactive behavior in an organized way.
Node Types
Leaf Nodes
Action nodes do things: move the arm, drive forward, speak a phrase. They return SUCCESS when done, FAILURE if they cannot complete, or RUNNING while in progress.
Condition nodes check things: is the battery above 20%? Is there an obstacle ahead? Is the gripper holding an object? They return SUCCESS (true) or FAILURE (false) immediately — never RUNNING.
Composite Nodes
Sequence (→) executes children left to right. If a child succeeds, it moves to the next one. If any child fails, the sequence fails immediately. Think of it as an AND gate — all children must succeed for the sequence to succeed.
Example sequence: Check door is reachable → Navigate to door → Open door. If navigation fails, the whole sequence fails without trying to open the door.
Selector (?) tries children left to right until one succeeds. If a child fails, it tries the next one. If any child succeeds, the selector succeeds. Think of it as an OR gate — at least one child must succeed.
Example selector: Try to open door with handle → Try to push door → Ask human for help. The robot tries the easiest approach first and falls back.
Parallel runs multiple children simultaneously. It succeeds or fails based on a policy — for example, succeed when all children succeed, or succeed when at least one succeeds.
Decorator Nodes
Decorators wrap a single child and modify its behavior:
- Inverter: Flips SUCCESS to FAILURE and vice versa
- Repeat: Runs the child N times or until failure
- Timeout: Forces FAILURE if the child takes too long
- Retry: Re-ticks a failed child up to N times
How Ticking Works
Every tick starts at the root and flows downward. A sequence node ticks its first child. If that child returns SUCCESS, it ticks the second child. If the second returns RUNNING, the sequence also returns RUNNING. On the next tick, the sequence remembers where it left off and starts by re-ticking the child that was RUNNING.
This “memory” behavior is crucial. A robot navigating to a location returns RUNNING for hundreds of ticks until it arrives. The parent sequence waits patiently, and the rest of the tree above it can continue checking higher-priority interrupts.
Priority and Reactivity
Behavior trees naturally support priority through the order of children in selectors and the tree’s top-down traversal:
Selector
├── Sequence: Emergency Response
│ ├── Condition: Battery critically low?
│ └── Action: Return to charger
├── Sequence: Main Task
│ ├── Condition: Have task assignment?
│ └── Action: Execute task
└── Action: Idle patrol
If battery drops critically low, the emergency sequence activates on the next tick, preempting whatever the robot was doing. This happens naturally because the emergency branch is checked first.
Behavior Trees vs. State Machines
Finite State Machines (FSMs) are the traditional alternative. Key differences:
| Feature | Behavior Trees | State Machines |
|---|---|---|
| Adding behavior | Add a branch (no rewiring) | Add state + transitions (may rewire many) |
| Readability | Tree structure, top-down | Graph, can become spaghetti |
| Reactivity | Built-in (priority through tree order) | Must add explicit interrupt transitions |
| Reusability | Subtrees can be copy-pasted | States are tightly coupled |
| Scalability | Handles 100+ behaviors well | Becomes unmanageable past 20-30 states |
State machines excel for simple systems with few states. Behavior trees win when complexity grows, which is why robotics has largely migrated to them.
Python Libraries
py_trees is the most popular Python behavior tree library. It provides all standard node types, visualization tools, and ROS 2 integration. It was developed for real robot systems at the Australian Centre for Robotic Vision.
behaviortree.cpp (BehaviorTree.CPP) is the C++ standard, used by the ROS 2 Navigation stack (Nav2). It has Python bindings for configuration but runs in C++ for performance.
Common Misconception
“Behavior trees are just fancy if-else chains.” The key difference is modularity and the RUNNING status. If-else logic executes once and makes a decision. A behavior tree ticks continuously, allowing long-running actions (navigate for 30 seconds), reactive interrupts (stop immediately if obstacle detected), and composable sub-behaviors that can be developed and tested independently. The continuous ticking model is fundamentally different from one-shot conditional logic.
One thing to remember: Behavior trees organize robot decisions into composable sequences (do these things in order) and selectors (try these options until one works), with the tree structure naturally encoding priority and enabling reactive switching between behaviors.
See Also
- Python Bluetooth Ble How Python connects to fitness trackers, smart locks, and wireless sensors using the invisible radio signals all around you.
- Python Circuitpython Hardware Why CircuitPython makes wiring up LEDs, sensors, and motors as easy as plugging in a USB drive.
- Python Computer Vision Autonomous How self-driving cars use cameras and Python to see the road, spot pedestrians, read signs, and understand traffic — like giving a car human eyes and a brain.
- Python Home Assistant Automation How Python turns your home into a smart home that reacts to you automatically, like a helpful invisible butler.
- Python Lidar Point Cloud Processing How self-driving cars use millions of laser dots to build a 3D picture of the world around them, and how Python helps make sense of it all.