Skip to the lesson
FixTheRobot Explore Robotics / Navigation / M9 Navigation in the Real World / M9-T1

Navigation · Theory · M9

M9-T1 — Nav2 Architecture

A navigation stack is a set of cooperating servers. Knowing who calls whom is half of debugging it.

  • Lesson 1 of 6
  • Module 9: Navigation in the Real World
  • Theory
  • About 10 minutes to read

When Scout is asked to deliver a tray to room 214, nothing in the robot “does navigation”. A request arrives at one server, which runs a small program that calls other servers, each of which owns one job and one piece of state. When something goes wrong, the skill is to know which server owns the failure. This lesson is the map of that system.

Learning objectives

After this lesson, you should be able to:

  • Name the Nav2 servers and the job each owns: planner, controller, smoother, behaviour server, navigator, waypoint follower, velocity smoother and collision monitor.
  • Trace a goal from the request to the velocity command, naming the action or topic at each hop.
  • Read a behaviour tree built from RecoveryNode, PipelineSequence and RoundRobin, and say what it does when a step fails.
  • Explain how plugins, lifecycle management, frames and parameter files tie the servers together.

The intuition

Picture a hospital porter’s office. A request comes in on a slip. A dispatcher (the navigator) does not carry anything herself: she checks that the route is known, asks the route planner for a path, asks the escort to follow it, and when the escort comes back with “blocked”, tries the standard fixes in order: clear the cart, back up, wait, and finally call for help. Each person has one job, a defined way to be asked, and a way to report success or failure.

Nav2 is organised the same way. The behaviour-tree navigator is the dispatcher. The planner server computes a path on the global costmap. The controller server turns that path into velocity commands using the local costmap. The behaviour server holds the recoveries. The servers talk through ROS 2 actions, which have a goal, feedback and a result, so “still working” and “failed” are first-class messages.

Nav2 servers and the path of a goalA goal enters bt_navigator, which runs a behaviour tree. The tree calls planner_server for a path and controller_server to follow it, and behavior_server for recoveries. The controller output passes through the velocity smoother and the collision monitor to the base.bt_navigatorbehaviour tree · NavigateToPose planner_serverglobal costmap · ComputePathToPose controller_serverlocal costmap · FollowPath behavior_serverSpin · BackUp · Wait action calls smoother_serveroptional path smoothing velocity_smoothercmd_vel_nav → cmd_vel_smoothed collision_monitorlast stop before the base → cmd_vel → robot base Frames: map → odom (AMCL or SLAM), odom → base_link (odometry). A lifecycle manager starts every server.
The Nav2 servers. Arrows are action calls from the navigator; the controller’s output passes through a velocity smoother and a collision monitor before it reaches the base.

The mathematics

The parts

Nav2 servers
Server / nodeOwnsInterfaceTypical plugins
bt_navigatorThe behaviour tree that sequences a navigation taskActions NavigateToPose and NavigateThroughPosesBehaviour-tree nodes (action, condition, control, decorator)
planner_serverThe global costmap and the global pathAction ComputePathToPoseNavfnPlanner, SmacPlanner2D, SmacPlannerHybrid, SmacPlannerLattice, ThetaStarPlanner
controller_serverThe local costmap, path following, progress and goal checksAction FollowPath; publishes velocity commandsDWB, RegulatedPurePursuit, MPPI
smoother_serverSmoothing a computed pathAction SmoothPathSimple smoother and others
behavior_serverThe recovery behavioursActions Spin, BackUp, DriveOnHeading, WaitOne plugin per behaviour
waypoint_followerVisiting a list of posesAction FollowWaypointsTask-at-waypoint plugins
velocity_smootherLimiting acceleration of the commandsTopic in, topic outNone
collision_monitorA last safety check on the commanded velocityTopic in, topic outPolygons and sensor sources
lifecycle managerConfigure and activate the servers in orderLifecycle servicesNone

The set of servers and their names grow with releases (docking, route and others exist in newer ones), so treat this table as the stable core, not a complete list.

The path of a goal

  1. Request. A client (RViz, a script using the Simple Commander API, an application) sends a NavigateToPose goal to bt_navigator: a pose in a frame, normally map.
  2. Plan. The tree’s ComputePathToPose node calls planner_server. The planner plugin searches the global costmap and returns a path, written to the behaviour tree’s blackboard.
  3. Follow. The tree’s FollowPath node calls controller_server with that path. At the controller frequency, the controller plugin reads the local costmap and the robot pose and publishes a velocity command.
  4. Condition the command. The velocity smoother limits acceleration; the collision monitor may slow or stop the command. The result reaches the base as cmd_vel.
  5. Monitor. The controller’s progress checker and goal checker decide whether the robot is moving and has arrived. The tree replans at a fixed rate and, on failure, runs recoveries.

A behaviour tree in one picture

Nav2’s default navigation tree has this shape (node names as in the Nav2 behaviour-tree documentation; check the version for your distribution):

Default navigation tree, simplified
RecoveryNode(number{of}retries=6)  PipelineSequence\mathrm{RecoveryNode}(\mathrm{number}_{\{\text{of}\}\text{retries}}=6)\;\mathrm{PipelineSequence}
RateController(hz=1.0)\mathrm{RateController}(\mathrm{hz}=1.0)
RecoveryNode(1)  ComputePathToPose\mathrm{RecoveryNode}(1)\;\mathrm{ComputePathToPose}
ClearEntireCostmap(global)\mathrm{ClearEntireCostmap}(\text{global})
RecoveryNode(1)  FollowPath\mathrm{RecoveryNode}(1)\;\mathrm{FollowPath}
ClearEntireCostmap(local)  ReactiveFallback  GoalUpdated  RoundRobin  Spin  Wait  BackUp\mathrm{ClearEntireCostmap}(\text{local})\;\mathrm{ReactiveFallback}\;\mathrm{GoalUpdated}\;\mathrm{RoundRobin}\;\mathrm{Spin}\;\mathrm{Wait}\;\mathrm{BackUp}
ClearEntireCostmap (local), ClearEntireCostmap (global)
PipelineSequence
A sequence that keeps ticking its earlier children while the later ones run: it plans again while following.
RecoveryNode
Runs its first child; if that fails, runs the second child (the recovery) and tries the first again, up to number_of_retries times. It has exactly two children.
RoundRobin
Each time it is run, it tries the next child: clear the costmaps, then spin, then wait, then back up.
RateController
A decorator that lets its child run at most hz times per second.

What ties it together

  • Plugins. Planners, controllers, costmap layers, goal checkers and recoveries are plugins chosen by name in the parameter file. Changing the algorithm is a configuration change.
  • Lifecycle. Servers are managed nodes: unconfigured → inactive → active. A lifecycle manager brings them up in order; a server that failed to configure stays down, and goals sent to the navigator fail.
  • Frames. The map frame is fixed to the world, odom is continuous but drifts, and base_link moves with the robot (lesson M1-T4). Localization publishes map → odom; odometry publishes odom → base_link.
  • Parameters. One YAML file configures every server under its name and a ros__parameters key. Parameter names change between releases, so read the documentation of your distribution before copying values.

A worked example

One goal, with numbers. Scout is asked to drive a 14.2 m path to the pharmacy. Assume a desired speed of 0.5 m/s, the controller at 20 Hz, the planner’s RateController at 1 Hz and a progress checker that expects 0.5 m of movement in 10 s (values you should read from your own file; these are common defaults at the time of writing).

Goal timeline
time to drive=14.2 m0.5 m/s=28.4 s\text{time to drive}=\frac{14.2\,\mathrm{m}}{0.5\,\mathrm{m}/\mathrm{s}}=28.4\,\mathrm{s}
controller cycles=28.4 s×20 Hz=568 velocity commands\text{controller cycles}=28.4\,\mathrm{s}\times 20\,\mathrm{Hz}=568\,\text{velocity commands}
planner calls=⌊(28.4 s1 s)+1=29 paths computed\text{planner calls}=\lfloor (\frac{28.4\,\mathrm{s}}{1\,\mathrm{s}})+1=29\,\text{paths computed}
progress requirement=0.5 m10 s=0.05 m/s≪0.5 m/s: met with a margin of 10×\text{progress requirement}=\frac{0.5\,\mathrm{m}}{10\,\mathrm{s}}=0.05\,\mathrm{m}/\mathrm{s}\ll 0.5\,\mathrm{m}/\mathrm{s}:\,\text{met with}\,a\,\text{margin of}\,10\times

So one successful goal is one action goal to the navigator, 29 action goals to the planner, one long-running action to the controller and 568 commands. When a bug appears “in navigation”, you now know where to look: if the path is wrong, the planner and the global costmap; if the path is right and the motion is wrong, the controller, the local costmap and the velocity chain.

When it gets stuck. Suppose a trolley blocks the corridor. The controller sees no progress for 10 s and fails. The inner RecoveryNode clears the local costmap and retries once: another 10 s. If it fails again, the outer node runs the recoveries, one per attempt: clear both costmaps, spin, wait, back up. With six retries, the tree can fail up to 7 times before it gives up. Roughly: 7 attempts × 2 tries × 10 s = 140 s of standing still, plus the time of the recoveries themselves, before the goal is aborted. That is a number worth checking against what the hospital considers acceptable for a blocked corridor, and it is set by three parameters you can read in the file.

Where the commands go. The controller’s output is typically published on a topic such as cmd_vel_nav, processed by the velocity smoother and the collision monitor, and arrives at the base as cmd_vel. Topic names are configured, and a wrong remap is the classic reason for “the plan is fine and the robot does not move” (project M9-L4).

Engineering implications and limitations

Debug by following the goal

Ask in order: is every server active? Is a transform from map to base_link available? Did the planner return a path? Is the controller publishing? Does the command reach the base? Each is one command (ros2 lifecycle get, tf2_echo, ros2 topic echo, ros2 topic info -v). A failure is almost always found at the first hop that says no.

Configuration is code

The parameter file and the behaviour-tree XML decide behaviour as much as any source file. They need review, version control and automatic checks, which is what the linters of this module do (labs M9-L2 and M9-L3).

Plugins and releases

Plugin class names, parameter names, default values and even the format of the behaviour-tree files change between Nav2 releases. When you copy a tutorial or a colleague’s file, check it against the documentation of your distribution. Pin the release you test, and re-run your tests when you upgrade.

Where the safety lives

The planner and controller optimise; the collision monitor and the base’s own limits protect. Do not rely on the planner’s costmap alone for safety: keep a final check that works from the latest sensor data and the commanded velocity (module 7).

Common misconceptions

“Nav2 is the planner.”

The planner is one server of several. Many failures people call “planning” are in the controller, the costmaps, the frames or the configuration.

“If the goal is accepted, navigation works.”

Acceptance only means the navigator is active. A path may still fail, the controller may produce no motion, or the command may never reach the base.

“The behaviour tree is just a config detail.”

It decides what happens on every failure: how many retries, which recovery, when to abort. It deserves the same attention as the algorithms.

“The same parameters work on every release.”

Names, plugin identifiers and defaults change. Always read the documentation for the release you run.

Engineering takeaways

  1. Nav2 is a set of lifecycle servers: navigator, planner, controller, smoother, behaviours, waypoint follower, velocity smoother and collision monitor.
  2. A goal travels from the client to bt_navigator, which calls the planner and the controller through actions; the velocity chain ends at the base.
  3. The behaviour tree decides retries and recoveries: RecoveryNode, PipelineSequence and RoundRobin are the building blocks.
  4. Plugins, lifecycle, frames and one parameter file tie the servers together, and all four are common sources of failure.
  5. Debug by following the goal hop by hop, and check the documentation of your release before copying parameters.

References and further reading

The Nav2 documentation and the papers that describe the system.

  • S. Macenski, F. Martín, R. White and J. Ginés Clavero, “The Marathon 2: A Navigation System”, IEEE/RSJ IROS, 2020.
  • S. Macenski, T. Foote, B. Gerkey, C. Lalancette and W. Woodall, “Robot Operating System 2: Design, architecture, and uses in the wild”, Science Robotics 7(66), 2022.
  • Nav2 documentation, “Concepts”, “Configuration Guide” and “Behavior Tree Nodes”, docs.nav2.org (choose your distribution).
  • M. Colledanchise and P. Ögren, “Behavior Trees in Robotics and AI: An Introduction”, CRC Press, 2018.

Knowledge check

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

Question 1

Scout’s goal is accepted by the navigator, a path appears in RViz, but the robot does not move. Name two servers or topics you would inspect first, and why.

Explanation

The controller server and the velocity chain. The path shows that the navigator and planner worked, so the question is whether the controller publishes commands and whether they reach the base: check the controller’s lifecycle state and log, then which velocity topics have publishers and subscribers.

Question 2

A RecoveryNode in a tree has three children. What is wrong, and what does the node normally do with two?

Explanation

RecoveryNode expects exactly two children: the action and its recovery. With two, it runs the first; if it fails, it runs the second and then tries the first again, up to the number of retries.

Question 3

The controller runs at 20 Hz and the robot drives 21 m at 0.7 m/s. How many velocity commands does the controller produce?

Explanation

30 s × 20 Hz = 600 commands (21 / 0.7 = 30 s).

What’s next

Next: how to change the numbers in that parameter file without breaking the robot.

Practice this lesson

Lint a Nav2 Parameter File

Paste a parameter file and find the settings that contradict each other or the robot.

Next lesson

M9-T2 — Tuning a Navigation Stack

Tune inflation, lookahead, tolerances and costmap resolution with a method that changes one thing at a time.

Nothing below is required to finish this lesson.