← BlogAMR Navigation Basics· 5/12

Global vs Local Costmap — Dividing the Work Between Long-Range Planning and Instant Avoidance

Nav2 splits costmaps into a global one for whole-map path planning and a local rolling-window one for real-time obstacle avoidance. This post covers their roles, dynamic sizing, and why multi-robot deployments must populate both.

~5 min
Nav2costmapglobal-plannerlocal-plannerAMR

Global vs Local Costmap

Robot navigation runs two fundamentally different questions at the same time.

  • "Which route should I take to the destination?" — the big picture view of the entire map
  • "How do I get around the person right in front of me?" — a sub-second, in-the-moment reaction

Trying to handle both with one costmap does neither well. Nav2 therefore splits the costmap into global and local, each with its own job.

A Full Map and a Moving Window

Rendering diagram…
  • Global costmap — a fixed-size map covering the entire environment. The planner draws one long start-to-goal path on it. Primarily static-map-based (walls).
  • Local costmap — a small rolling window (e.g., 5 m × 5 m) that follows the robot. The controller uses fresh LiDAR obstacles inside this window to dodge them and produce cmd_vel.

Think of global as "the full route from a navigation app" and local as "the steering wheel adjustments you make second to second while driving." They work together — the global plan provides the route; the local planner follows it while handling immediate obstacles autonomously.

▶ Simulation footage — a Clearpath Husky driving a warehouse aisle along its Nav2 path (cyan dashes). The green square on the floor is the local costmap riding along with the robot; the cyan dashed path running past that window to the end of the aisle was planned on a far larger global costmap. The wide ribbon trailing behind the robot is not a path but the track it has already covered, coloured by speed (blue = stopped, cyan/green = moving). Actual values from this run — local 5 m × 5 m (every cell free), global 314 × 302 cells at 0.25 m (about 78 m × 76 m, 22,340 lethal cells). The racking lives only in the global map; the local window stayed empty for the whole drive.

Size Is Dynamic, Not Fixed

Setting the local costmap too large makes it computationally expensive; too small and fast-approaching obstacles are seen too late. It is better to dynamically size the range based on the environment — for example, capping the obstacle sensing range at min(arena_diagonal / 2, 25 m): proportional to the environment but bounded.

💡 The fixed-value trap — hard-coding a single costmap size works poorly across environments: oversized in a small warehouse, undersized in a large outdoor arena. "Proportional to environment + upper bound" makes one configuration hold up across diverse venues.

The Multi-Robot Trap — You Must Populate Both

In the previous post we established that "other robots only exist in the obstacle layer." There is one more dimension to this. Other robots' positions must be injected into both the local and global costmaps.

Rendering diagram…

Adding other robots only to the local costmap means instant avoidance works, but the global path is drawn right through the other robot, causing repeated head-on encounters. Conversely, raw LiDAR scan noise in the global costmap causes path oscillation. The correct distribution: noise → local only; robot positions → both — that selective assignment is the key.

⚠️ "Local avoidance will handle it" is wrong in multi-robot scenarios. If the global path is planned to collide in the first place, reactive avoidance alone leads to repeated deadlocks.

In a nutshell

📌 Global costmap = long-range path on the full map (planner). Local costmap = instant avoidance in a rolling window around the robot (controller). Size both proportionally to the environment, and in multi-robot setups distribute data selectively: robot positions go into both costmaps; raw LiDAR noise goes into local only.

See standard test results with videos and verdict evidence on the imSim Portal.

View public results →