Skip to the lesson
FixTheRobot Explore Robotics / Navigation / M7 Safety, Uncertainty and Recovery / M7-T5

Navigation · Theory · M7

M7-T5 — Behavior Trees for Navigation

A behaviour tree is a way to write “try this, else that, and ask for help last” so that a person can read it and a robot can run it every tick.

  • Lesson 5 of 7
  • Module 7: Safety, Uncertainty and Recovery
  • Theory
  • About 8 minutes to read

Navigation is not a straight line from “go” to “arrived”. The path may be blocked, the controller may stall, a door may be shut. Someone has to decide, in code, what the robot does next. A behaviour tree is a small, readable structure for those decisions: leaves do things and ask questions, inner nodes say in which order and under which conditions. This lesson reads and writes a small tree.

Learning objectives

After this lesson, you should be able to:

  • Define tick, status (success, failure, running), sequence, fallback, condition, action and retry.
  • Trace a tick through a small tree and write down the leaves that were visited.
  • Build a tree that plans, drives, recovers in a sensible order and asks for help last.
  • Compare a tree with a finite state machine and say how Nav2 uses trees to wrap planning and recovery.

The intuition

Think of a nurse’s checklist for delivering a sample. “Pick up the sample. Walk to the lab. Hand it over.” If any step fails, the checklist stops: that is a sequence. Now think of a rule for getting through a door: “push it; if that fails, pull it; if that fails, call security.” The first option that works ends the search: that is a fallback. Trees are made by nesting those two. “Deliver the sample, or else try the recovery routine, or else ask for help” puts sequences inside a fallback.

The key difference from a flowchart is that the whole tree is ticked over and over, usually ten times a second or more. Each tick starts at the root and decides again what to do. A node returns success, failure or running (“I am still working, call me again”). Because every tick re-checks the conditions at the top, a robot that is driving along a path notices that the path has just become blocked and reacts on the next tick, without any special transition.

That is also why trees scale. In a state machine every new behaviour needs transitions to and from the others. In a tree you insert a subtree where it belongs, and the rest keeps working.

A small navigation behaviour treeA tree with a fallback at the root and three children. The first child is a sequence of a condition path clear and an action follow path. The second is a sequence of the recovery clear costmap and follow path. The third is the action ask for help. ? fallback → sequence→ sequenceask_help path_clearfollow_pathclear_costmapfollow_path conditionactionaction (recovery)action Ticks run top to bottom and left to right; each node returns success, failure or running.
A small navigation tree: try to follow the path; if that fails clear the costmap and follow again; if that fails ask for help.

The mathematics

Node types

Basic behaviour tree nodes
NodeTicks its childrenReturnsReads as
Sequence (→)In order, until one is not successThe status of the first child that is not success; success if all succeed“Do all of these, in order.”
Fallback (?)In order, until one is not failureThe status of the first child that is not failure; failure if all fail“Get one of these to work.”
ConditionNone (leaf)success or failure, from the world“Is the path clear?”
ActionNone (leaf)success, failure or running“Follow the path.”
Retry (n)The child, up to n timessuccess at the first success, running if the child runs, failure after n failures“Try again, at most n times.”
Tick rules
tick⁡(sequence)=first child status≠success, else success\operatorname{tick}(\text{sequence})=\text{first child status}\ne \text{success},\,\text{else success}
tick⁡(fallback)=first child status≠failure, else failure\operatorname{tick}(\text{fallback})=\text{first child status}\ne \text{failure},\,\text{else failure}
tick⁡(retry n)=success at the first success; running if the child is running; failure after n failures\operatorname{tick}(\text{retry}\,n)=\text{success at the first success};\,\text{running if the child is running};\,\text{failure after}\,n\,\text{failures}

The status running propagates upward: a sequence or a fallback whose current child is running is itself running, and the later children are not ticked. This is what stops a recovery from starting while the robot is still driving.

Reactive and memory nodes

A reactive sequence or fallback restarts from its first child on every tick, so a condition at the front is re-checked while a later action runs. A node with memory resumes at the child that was running. Reactive nodes keep the robot responsive; memory nodes avoid repeating finished work. Libraries offer both, and which one you meant is a common source of bugs.

Decorators and the blackboard

Decorators wrap one child and change when or how it runs: retry, timeout, rate limit, inverter. A blackboard is the shared key–value store through which nodes pass data (a goal, a path), kept outside the tree structure.

Trees and state machines

Comparison of a state machine and a behaviour tree
Finite state machineBehaviour tree
StructureStates and transitions between themHierarchy of nodes, no explicit transitions
Adding a behaviourNew transitions to and from many statesInsert a subtree
Reaction to changeOnly through transitions out of the current stateConditions are re-checked from the root every tick
Good forFew modes with clear switches (docked, charging, driving)Prioritised behaviours with recovery

A worked example

Ticking the tree of the figure. The leaves return the following statuses over three ticks: the path becomes clear after the costmap is cleared, and follow_path runs for two ticks before it succeeds.

tick 1: path_clear = failure  → first sequence fails
        clear_costmap = success, follow_path = running
        → fallback returns running      visited [path_clear, clear_costmap, follow_path]
tick 2: path_clear = success, follow_path = running
        → fallback returns running      visited [path_clear, follow_path]
tick 3: path_clear = success, follow_path = success
        → fallback returns success      visited [path_clear, follow_path]

On tick 2 the reactive root starts from the first child again, finds the condition now true, and no longer needs the recovery branch. If follow_path had failed on tick 3, the first sequence would fail and the root would run the recovery branch again, then ask for help.

The order of recoveries. Scout has four recoveries with a time cost and a risk level (0 harmless, 1 moves blind, 2 turns in place). Score each as cost + 10 · risk: clear_costmap 1, wait 5, back_up 8 + 10 = 18, spin 12 + 20 = 32. Each recovery fixes one cause: ghost, person, wedged, dead-end pose. Run one after another and then retry the drive:

order                                  expected cost per fault
clear, wait, back_up, spin            (1 + 6 + 24 + 56) / 4 = 21.75
wait, clear, back_up, spin            22.75
spin, back_up, wait, clear            (56 + 55 + 50 + 32) / 4 = 48.25

Cheapest first costs less than half of the worst order on average, and, more importantly, avoids the risky spin until nothing safer worked (lab M7-L3, stage 2). A tree that puts all recoveries in one sequence runs all four every time: cost 56 for every fault.

Where Nav2 does this. Nav2’s navigator is a behaviour-tree executor. The default tree for navigating to a pose plans at a limited rate, follows the path, and wraps both in recovery nodes with a bounded number of retries; on repeated failure it runs a round-robin of recoveries such as clearing the costmaps, spinning, waiting and backing up. The exact tree is an XML file you can read and change, and its shape is the one used above.

Engineering implications and limitations

Keep leaves small and honest

An action should do one thing and report its status truthfully. “Follow path” returns running while it drives, success on arrival and failure when the controller gives up. An action that returns success to “keep the tree moving” hides the problem from every node above it.

Every retry has a budget

A tree without bounds on retries and recoveries can loop for ever. Give each recovery and each retry a limit, and end with a branch that tells a person (lab M7-L3, stage 3). The tree is the right place for these limits because they are policy, readable without compiling anything.

Recoveries need preconditions

Backing up needs free space behind; spinning needs clearance all round. Put these as conditions in front of the action, or the tree will cheerfully drive into a wall (lesson M7-T6).

Log the ticks

Record which leaves ran and their statuses. A tree is easy to read after the fact only if the log says which branch fired, and that is the first thing to look at in a failed run (lesson M1-T6).

A tree is policy, not safety

A behaviour tree orders actions; it does not guarantee that any of them is safe. The safety of a stop, a back-up or a spin comes from the layers below (lesson M7-T2) and from a safety case for the machine as a whole. This track does not replace that work.

Common misconceptions

“A tree is just a nested if-statement.”

A tree is ticked repeatedly and every node has a status, including running. That gives it reactivity and the ability to be interrupted, which an if-statement does not have.

“Fallback means catch the exception.”

It means “try the next option when this one fails”. It is control flow on status, not error handling.

“Running means failing slowly.”

Running means working. A fallback that treats running like failure starts a recovery during normal driving.

“More recoveries make a more robust robot.”

Each recovery is an action with its own risk. Ordered, bounded recoveries help; a long unconditional list moves a stuck robot around in ways nobody checked.

Engineering takeaways

  1. A tree is ticked repeatedly; each node returns success, failure or running.
  2. A sequence stops at the first child that is not a success; a fallback stops at the first child that is not a failure.
  3. Running passes upwards and prevents later children, such as recoveries, from starting.
  4. Order recoveries by cost and risk, give them preconditions and budgets, and end with a request for help.
  5. The tree orders actions; safety comes from the layers beneath it and from a proper safety case.

References and further reading

The behaviour-tree book is the standard primary reference; the Nav2 pages describe the trees used in practice.

  • M. Colledanchise and P. Ögren, “Behavior Trees in Robotics and AI: An Introduction”, CRC Press, 2018.
  • M. Colledanchise and P. Ögren, “How Behavior Trees Modularize Hybrid Control Systems and Generalize Sequential Behavior Compositions, the Subsumption Architecture, and Decision Trees”, IEEE Transactions on Robotics, 33(2), 2017.
  • S. Macenski, F. Martín, R. White and J. Ginés Clavero, “The Marathon 2: A Navigation System”, IEEE/RSJ IROS, 2020.
  • Nav2 documentation, “Behavior Trees” and “Navigation Concepts”, docs.nav2.org; BehaviorTree.CPP documentation.

Knowledge check

Three conceptual questions. Write an answer, then reveal the explanation. Your answers stay in your browser.

Question 1

A fallback has children A (running) and B (success). What does it return and is B ticked?

Explanation

It returns running and B is not ticked: a fallback stops at the first child that is not a failure, and running is not a failure.

Question 2

A sequence has children A (success), B (failure) and C (success). What does it return, and which children were ticked?

Explanation

Failure. A and B were ticked; C was not, because the sequence stopped at the first child that was not a success.

Question 3

Why is the order clear_costmap, wait, back_up, spin better than the reverse for a robot that is equally likely to have any of four faults?

Explanation

The recoveries differ in cost and risk, and each fixes one fault. Trying the cheapest first minimises the average total cost (shortest-job-first), and the risky spin is only reached if nothing safer worked: 21.75 on average against 48.25 for the reverse order in the example.

What’s next

Next: how to tell that a robot is stuck, and how to choose and bound the recoveries.

Practice this lesson

Build a Recovery Behavior Tree

Scout gives up at the first obstacle: build a tree that retries, clears, backs up and then asks for help.

Next lesson

M7-T6 — Recovery Behaviors and Stuck Detection

Detect a stuck robot from progress over time, and order recoveries (wait, clear, back up, spin) by cost and risk.

Nothing below is required to finish this lesson.