Introduction: The Navigation Problem
Imagine a warehouse floor at 3 AM. No human operators. Just autonomous mobile robots (AMRs) weaving between aisles, avoiding obstacles in real time, coordinating with a dozen siblings, and delivering parts to assembly stations with centimeter-level precision. This is not science fiction—it’s the daily reality for Fortune 500 manufacturers using ROS 2 Nav2.
Nav2 is the production-grade successor to the ROS Navigation Stack, now trusted by over 100 companies worldwide. Unlike its ROS 1 predecessor, Nav2 is built on the Behavior Tree (BT) scheduling paradigm, a plugin-based architecture, and ROS 2’s modern middleware (DDS). This post deconstructs the entire Nav2 stack as deployed in real warehouse environments: the sensor fusion loop, the costmap computation pipeline, global and local path planning trade-offs, control strategies, fleet orchestration via Open-RMF, and the friction of migrating from ROS 1 to ROS 2.
By the end, you’ll understand not just how Nav2 works, but why each component exists, what breaks in production, and how to reason about trade-offs when tuning your AMR fleet.
Part 1: The Sensor-to-Motion Pipeline
Understanding the Perception-to-Control Loop
Every autonomous navigation decision flows through a tightly coupled chain:
Sensor Data → Perception → Localization → Planning → Control → Motor Command
Think of this as a biological nervous system. Sensors are the eyes and proprioceptors. Perception is the sensory cortex. Localization is your inner ear—telling you where you are. Planning is prefrontal reasoning. Control is the motor cortex. Motors are muscles.
This loop must close at 10–50 Hz (typical: 20 Hz) to maintain stability and responsiveness. Latency above 500 ms becomes dangerous; the robot can’t react fast enough to new obstacles.

The diagram above shows how sensor data flows through five functional layers:
- Sensor Input: LiDAR (2D range scans), depth cameras, wheel encoders, GPS/RTK
- Perception: SLAM (Simultaneous Localization and Mapping) and obstacle detection
- Localization: AMCL (Adaptive Monte Carlo Localization) refines pose estimates
- Costmap: Occupancy grid representing traversable vs. unsafe space
- Planning & Control: Path planning and trajectory tracking generate motor commands
In practice, this loop is asynchronous and distributed. A LiDAR fires at 10 Hz. Odometry updates at 100 Hz. The planner runs at 5 Hz (heavy computation). The controller runs at 50 Hz (lightweight). Nav2 ‘s behavior tree scheduler manages these timing mismatches.
Why Layered Perception?
You might ask: why not just use one sensor? Because each sensor has blind spots:
- LiDAR: Excellent range and accuracy outdoors, but fails in rain, fog, or reflective surfaces. Slow (10 Hz typical).
- Cameras: High temporal resolution (30+ fps), good texture, but fragile in darkness and computationally expensive.
- Wheel Encoders: Precise short-term motion, but drift accumulates over hours (dead reckoning).
- GPS/RTK: Global reference, 10 mm accuracy with RTK corrections, but denied indoors and requires clear sky view.
Real deployments use sensor fusion: LiDAR for obstacle detection, encoders for odometry, SLAM for loop closure, and GPS as a global correction mechanism outdoors. The costmap aggregates all these signals into a single risk metric per grid cell.
Part 2: Building the Map—SLAM and Localization
What is SLAM?
SLAM stands for Simultaneous Localization and Mapping. It solves a chicken-and-egg problem: to map your environment, you need to know where you are. But to know where you are, you need a map. SLAM breaks the loop by incrementally building the map while correcting pose estimates.
Analogy: Imagine entering a dark maze. You leave breadcrumb trails and note landmarks (room shapes, door positions). Every time you discover a familiar landmark again (loop closure), you realize your path estimate was wrong, and you retroactively correct your mental map and your position within it.
SLAM Toolbox vs. Cartographer
ROS 2 offers two main SLAM engines:
SLAM Toolbox: The actively maintained standard for ROS 2. It ports the classical Karto scan-matching algorithm but rebuilds everything else:
– Pose graph optimization using g2o for loop closure
– Lifelong mapping: continually refine maps over weeks/months
– Localization mode: acts as a pure localization system once a map is saved
– Serialization: save/load pose graphs and maps in human-readable formats
– Trade-off: Slightly less accurate than Cartographer, but far more reliable and easier to deploy
Cartographer: Google’s full-featured SLAM system with 3D support. Advantages:
– Superior loop closure using adaptive voxel filters
– Multi-sensor fusion (LiDAR + IMU + odometry)
– Fast optimization
Production reality: Cartographer is overshadowed in ROS 2 because the port is not actively maintained. SLAM Toolbox dominates warehouse deployments.
The SLAM Pipeline: Scan Matching to Pose Graph

Breaking down the diagram:
- Raw Sensor Data: LiDAR scan arrives (e.g., 720 points, 10 Hz)
- Scan Matcher (core algorithm): Uses Iterative Closest Point (ICP) or grid-based matching to align the new scan against the existing map or the last scan
- Pose Update: If the scan matches well, the robot’s pose estimate advances
- Pose Graph: Each matched scan creates a pose node (6D state: x, y, theta + covariance). An edge connects the previous pose to the current one, weighted by the matching confidence
- Loop Closure Detection: When the robot revisits a previously-seen location (detected via scan similarity), a loop-closure edge is added. This causes the pose graph to be inconsistent (the loop has error accumulated along the path)
- Graph Optimization: A solver (g2o) redistributes error back through the graph, creating a globally consistent map
Adaptive Monte Carlo Localization (AMCL)
Once the map is built, AMCL maintains the robot’s pose estimate in that known map. How it works:
- Particle Filter: Maintain 2,000–50,000 particles, each representing a possible robot pose (x, y, theta)
- Prediction Step: Move particles forward according to odometry (wheel encoder data)
- Likelihood Computation: Score each particle by comparing the expected laser scan (computed from the map) to the actual scan
- Resampling: Discard low-likelihood particles; duplicate high-likelihood ones
- Result: Particles cluster around the true pose; the cluster mean is your pose estimate
Why not just trust odometry? Wheel slip, uneven floors, and bearing drift cause odometry to accumulate error. After 1 hour, a robot trusting only odometry might be 10 meters off its true position. AMCL corrects this in real time.
Trade-off: AMCL requires a pre-built map. In unknown environments, you need SLAM. Once exploration is done and the map is frozen, AMCL is lighter and faster.
GPS-Integrated SLAM for Outdoor Deployments
Warehouses aren’t always indoors. Outdoor yards, port facilities, and logistics hubs need GPS.
The problem: GPS alone is unreliable. Multipath (signal bouncing off buildings), shadowing (trees), and ionospheric delay introduce errors of 5–10 meters, sometimes more.
Solution: Fuse GPS with LiDAR SLAM. The pose graph uses two constraint types:
- Odometric constraints (LiDAR scan matching + IMU): High precision, but drift
- GPS constraints: Lower precision (±0.5 m with RTK-GPS), but globally accurate
The optimizer weights both types and produces a trajectory that fits both sensor streams. In practice:
- GPS-denied indoors: SLAM dominates; GPS constraints are ignored
- GPS-rich outdoors: GPS anchors the long-term trajectory; SLAM refines local accuracy
- Mixed indoor-outdoor: Seamless handoff as GPS signal availability changes
This hybrid approach enables AMRs to navigate from a warehouse into a yard, update their global reference, and return indoors with a globally consistent map.
Part 3: The Costmap—Representing Obstacle Risk
Costmap Architecture: Layers, Not Monoliths
A costmap is a 2D grid overlay on the map. Each cell encodes the cost of occupying that location: 0 (free space), 1–254 (graded obstacle risk), or 255 (lethal/occupied).
Nav2’s costmap is not a single computation. It’s a stack of layer plugins, each contributing data:

Static Layer
This is the pre-built SLAM map (occupancy grid). It’s rarely updated. It captures walls, desks, and permanent infrastructure.
Cost:
0 = free
100 = likely occupied (from SLAM)
254+ = wall
Trade-off: The static map can be stale. A box moved from one aisle to another yesterday won’t show up. This is why obstacle detection layers exist.
Obstacle Layer (2D Raycast)
Real-time sensor data. The layer subscribes to LaserScan messages (2D LiDAR) and raycasts into a 2D grid:
- For each ray in the scan, mark the endpoint as occupied
- Mark traversed cells as free (the sensor can “see through” empty space)
- Range: Typically 30 meters for warehouse LiDARs (trade-off: longer range = more computation)
This layer updates at sensor frequency (10 Hz for LiDAR), capturing dynamic obstacles: other robots, people, moving boxes.
Decay strategy: Old obstacles fade over time (configurable: 0.5–10 seconds). This prevents a momentary person-detection from blocking routes permanently.
Voxel Layer (3D Raycast)
For robots with 3D depth sensors (RealSense cameras, Velodyne 3D LiDARs), the voxel layer builds a 3D occupancy grid and projects it down to 2D.
Advantage: Marks overhead obstacles (e.g., a loading dock overhang at 1.5 m height). A 2D layer would miss this, and the robot would crash.
Disadvantage: Higher computation; only necessary if your robot is tall or operates in multi-level environments.
The voxel layer maintains a 3D voxel grid (e.g., 30 m × 30 m × 2 m, 5 cm resolution = 3.6M voxels). This is memory-intensive, so most warehouse deployments use 2D-only (obstacle layer).
Inflation Layer (Exponential Cost Decay)
Once obstacles are marked, the inflation layer creates a “safety buffer” around them. Think of it as pushing obstacles outward, even though they’re not physically larger.
Why? If the robot treats an obstacle as a point at exactly cell (10, 10), its center can approach within 5 cm. Dangerous if the robot has wheels or a bumper. Instead, mark all cells within inscribed radius as lethal, and decay cost exponentially outward.
Mathematics:
cost(cell) = 254 * exp(-distance_to_obstacle / inflation_radius)
If the robot has a 0.5 m radius, cells within 0.5 m of any obstacle get cost 254 (lethal). Cells from 0.5–1.0 m get graded costs (e.g., 200, 150, 100). Beyond 1.0 m, cost approaches 0.
Trade-off: Larger inflation radius = safer but more restrictive paths (can’t navigate tight aisles). Smaller radius = more agile but crash risk.
This is a major tuning parameter for warehouse AMRs. Too conservative, and the fleet can’t navigate 1.2 m wide aisles. Too aggressive, and robots collide with low-hanging pipes.
Combining Layers: Master Costmap
The planner and controller each maintain their own costmap instance. The master costmap algorithm:
for each cell (x, y):
cost = 0
for each layer in [static, obstacle, voxel, inflation]:
cost = max(cost, layer_cost[x, y])
master_costmap[x, y] = cost
The max operator is important: a single lethal obstacle anywhere in the stack makes the cell lethal. This is safe (no false negatives) but can be overly conservative (false positives when layers conflict).
Part 4: Path Planning—Global Trade-Offs
What Global Path Planning Does
The planner computes a collision-free path from the robot’s current pose to the goal, subject to:
- Constraint 1: No cell with cost > threshold (usually 252)
- Constraint 2 (optional): Path must be kinematically feasible (honor max turning radius, reversing rules)
- Objective: Minimize some combination of distance, turns, and smoothness
The planner runs at 5 Hz (low frequency is okay because the environment is mostly static). The output is a sequence of waypoints (e.g., 100 points spaced 0.5 m apart).
The Planner Trio: NavFn, Smac, Theta*
Nav2 ships with three global planners. Each makes different trade-offs:

NavFn (Navigation Function)
Algorithm: Wavefront propagation (Dijkstra or A*) on a 2D grid.
How it works:
1. Initialize cost field: goal cell = 0, all others = infinity
2. Propagate: each cell’s cost is the minimum of its neighbors’ costs plus transition cost
3. At any pose, follow the negative gradient downslope to the goal
Behavior: Produces broad, sweeping curves because the gradient field is diffused.
Pros:
– Fastest (100+ ms for typical 100m × 100m warehouse)
– Proven, battle-tested
– Works on any cost map
Cons:
– Not kinematically feasible (ignores robot turning radius)
– Gradienty artifacts; path is often suboptimal
– No smoothing
When to use: Small warehouses, fast prototyping, low-compute robots.
Smac Planner 2D
Algorithm: A* search on a grid using 4 or 8 connected neighborhoods, with optional post-smoothing.
How it works:
1. Search grid from start to goal, using heuristic (Euclidean distance) to prioritize promising cells
2. Open list (priority queue) of candidate cells, ordered by estimated cost
3. Expand lowest-cost cell, add neighbors to open list
4. When goal is reached, backtrack to construct path
5. Optional: Smooth the path using line-of-sight checks
Behavior: Produces paths with fewer turns and better global awareness than NavFn.
Pros:
– 2–3x faster than Smac 3D (see below) with similar quality
– Classical A*, well-understood
– No weird artifacts like NavFn
– Typical planning time: 50–100 ms
Cons:
– Still not kinematically feasible
– 8-connected search can produce diagonal zigzags; 4-connected is more realistic but suboptimal
When to use: Most warehouse deployments. It’s the sweet spot between quality and speed. Smac 2D is the default in Nav2.
Theta* (Theta Star)
Algorithm: A variant that allows any-angle paths* (not restricted to grid directions). Uses line-of-sight checks to skip grid cells.
How it works:
1. A* search like Smac, but with an additional optimization
2. When evaluating a cell, check if there’s a line-of-sight path from the predecessor’s parent directly to this cell (skipping the intermediate cell)
3. If yes, take the direct path (straight line)
4. Result: paths composed of straight-line segments at arbitrary angles
Behavior: Strongly prefers straight lines, creating the most direct paths.
Pros:
– Highest quality paths (straight lines, fewest turns)
– Any-angle freedom
Cons:
– Slower than Smac (more line-of-sight checks)
– Not kinematically feasible (ignores turning radius)
– Still requires post-processing for robot control
When to use: High-speed robots or large open warehouses where turn smoothness is critical.
Beyond 2D: Kinematically Feasible Planning
All three planners above ignore the robot’s kinematics (turning radius, reversing capabilities). For car-like or ackermann robots, this is unacceptable. The solution: Smac 3D Hybrid-A (also called Hybrid A) and State Lattice.
These planners explicitly model:
– Robot’s maximum steering angle
– Required turning radius
– Whether the robot can reverse
Trade-off: 10–30x slower than 2D planners. Not suitable for high-frequency replanning. Use them only when kinematic feasibility is critical.
Part 5: Local Control—Trajectory Tracking Under Uncertainty
The Planner-Controller Contract
The global planner gives the controller a static path. But the world is dynamic:
- A forklift moves into the planned path
- Odometry drifts, pushing the robot off the path
- A colleague walks by, blocking the route
The controller must react in real time:
Input: Global path + current costmap + current robot pose + goal pose
Output: Velocity command (linear: m/s, angular: rad/s) at 20–50 Hz
The controller considers the next 1–2 seconds of motion (lookahead window) and selects the best trajectory to track the path while avoiding obstacles.
Three Control Philosophies

Dynamic Window Approach (DWB)
Algorithm: Score a set of candidate trajectories and pick the best.
How it works:
1. Generate candidate trajectories by sampling velocity pairs (v_linear, v_angular) within the robot’s acceleration limits
2. Roll out each trajectory 1–2 seconds into the future
3. Score each trajectory on multiple critics:
– Path alignment: How close does the trajectory get to the global path?
– Goal proximity: How close does it end to the goal?
– Obstacle distance: How far from obstacles? (penalties increase as distance decreases)
– Action cost: Penalize jerky or energy-intensive motions
4. Pick the trajectory with the highest score
Pros:
– Lightweight; runs at 100+ Hz on modest hardware
– Highly tunable (11+ critic weights)
– Works for holonomic, differential-drive, and omni-directional robots
– The critic architecture is extendable (add custom scoring functions)
Cons:
– Non-predictive; only looks 1–2 seconds ahead
– Reactive; can oscillate or overshoot in cluttered spaces
– Tuning is problem-specific (different warehouses, different weights)
Typical parameters:
sampling_period: 0.1 s (10 Hz replanning)
sim_time: 2.0 s (lookahead window)
velocity_samples: 20
theta_samples: 20
This means: 400 candidate trajectories evaluated every 100 ms. On a multi-core CPU, this is feasible.
Model Predictive Path Integral (MPPI) Controller
Algorithm: Sampling-based optimal control using path integrals.
Intuition: Instead of scoring discrete trajectories (DWB’s approach), MPPI samples many trajectory perturbations (e.g., 100–1000), weights them by their cost, and averages to find the optimal control input.
How it works (simplified):
1. Initialize a baseline control trajectory (e.g., constant velocity along the path)
2. Generate 1000 perturbed trajectories by adding random noise to the control inputs
3. Roll out each trajectory; compute cost (obstacle distance, path deviation, smoothness)
4. Weight trajectories by cost: trajectories with lower cost contribute more to the next control decision
5. Average weighted trajectories to get the optimal control
6. Repeat
Pros:
– Predictive; can anticipate obstacles and plan smoother paths
– Probabilistic; naturally handles uncertainty
– High-quality trajectories; outperforms DWB in cluttered scenarios
– Runs at 100+ Hz on an Intel i5 (4th gen)
– Excellent for differential-drive and holonomic robots
Cons:
– More complex to tune (sampling distribution, cost function weights)
– Higher compute overhead than DWB (but still fast)
– Fewer public implementations; less battle-tested than DWB
Typical parameters:
model_predict_hz: 50 (prediction frequency)
lookahead_horizon: 2.0 s (planning horizon)
samples: 100 (trajectory perturbations per decision)
Regulated Pure Pursuit (RPP)
Algorithm: Geometric control; track the path using a lookahead point.
How it works:
1. Find a point on the global path, 0.5–2.0 m ahead of the robot (lookahead distance)
2. Compute the curvature needed to reach that lookahead point
3. Regulate velocity: reduce speed if obstacles are near (avoid overshooting)
4. Command velocity
Pros:
– Extremely lightweight; runs at 1000+ Hz
– Predictable; geometric control is easier to reason about
– Few parameters to tune
Cons:
– Not reactive to obstacles; if an obstacle appears between the robot and the lookahead point, RPP doesn’t avoid it
– Worse performance in cluttered spaces
– Poor at handling uncertainty
When to use: Wide-open spaces (parking lots, factory floors) or very slow robots (collision risk is low anyway).
Real-World Performance: The Clutter Test
In a warehouse obstacle challenge:
- DWB: Handles dense clutter well; weaves around obstacles. Compute: 20 ms per command cycle.
- MPPI: Smoother paths; better long-term planning. Compute: 50 ms per command cycle. Achieves 100+ Hz on modern CPUs.
- RPP: Simplest; fails when obstacles block the direct path.
For production AMR fleets, MPPI is increasingly preferred because its predictive nature reduces oscillations and recoveries.
Part 6: The Behavior Tree—Orchestrating Autonomy
Why Not a Finite State Machine?
ROS 1 used Finite State Machines (FSMs) for navigation logic. An FSM has states (IDLE, COMPUTING_PATH, TRACKING, GOAL_REACHED) and transitions (based on events).
Problem: FSMs are fragile. They don’t compose well. Adding a recovery behavior requires new states and transitions. The logic becomes a tangled graph.
Solution: ROS 2 Nav2 uses Behavior Trees.
A behavior tree is a directed acyclic graph of composable tasks. Each node represents an action or decision. Execution flows top-down, left-to-right.

Key BT Concepts
Task Nodes (Leaf Nodes):
– SetInitialPose: Set the robot’s starting pose
– ComputePath: Call the planner
– FollowPath: Call the controller
– IsGoalReached: Check distance to goal
Composite Nodes (Decorators):
– Sequence: Execute children left-to-right; stop on first failure
– Fallback: Try children left-to-right; stop on first success
– Parallel: Execute all children concurrently
Example Tree Logic:
Root
├── Sequence: "Navigate to Goal"
│ ├── SetInitialPose
│ ├── Sequence: "Planning + Tracking Loop"
│ │ ├── ComputePath
│ │ ├── FollowPath
│ │ ├── IsGoalReached? (checks if goal reached)
│ │ └── [if goal reached: return SUCCESS]
│ └── GoalReached: return SUCCESS
└── Fallback: "Recovery on Navigation Failure"
├── ClearCostmap (retry planning without obstacles)
├── BackupAndSpin (reverse, spin 360°)
├── RequestAssistance (escalate to human)
Execution:
1. Start at root
2. Execute SetInitialPose; if success, proceed to next sequence
3. Compute path; if failure, backtrack and try recovery (Fallback)
4. If recovery succeeds, retry planning
5. If all recoveries fail, propagate failure upward
6. If tracking succeeds and goal is reached, return SUCCESS
Advantages Over FSMs
- Composability: Reuse subtrees across behaviors
- Explainability: The tree structure is the spec and the code
- Fault tolerance: Fallback nodes encode recovery strategies
- Dynamic behavior: At runtime, swap out planner/controller plugins
Part 7: Recovery Behaviors—When Things Break
Production failures are inevitable. A forklift blocks the path. GPS dies. Sensors get dirty. Recovery behaviors are the robot’s reflex responses.
Standard Recoveries
Costmap Clearing:
Action: Forget all detected obstacles; keep static map
Rationale: The obstacle layer may have stale detections (e.g., a person left 3 seconds ago but still marked occupied)
Risk: If the obstacle is actually present, the robot collides
Frequency: First recovery attempt
Backup and Spin:
Action: Drive backward 0.5 m, then rotate 360°
Rationale: Might free the robot from a local deadlock (e.g., slightly wedged against a wall)
Risk: Backs into an obstacle not detected by forward-facing sensors
Frequency: Second recovery
Replanning:
Action: Recompute the global path from current pose
Rationale: Environment changed; old path is invalid
Risk: If obstacles keep appearing, replanning loops forever
Frequency: Always used before costmap clear
Request Assistance:
Action: Stop, flash lights, emit sound; wait for human intervention
Rationale: Robot is truly stuck and can't recover autonomously
Risk: Robot blocks traffic; human must arrive and diagnose
Frequency: Last resort
Configuring Recoveries
In Nav2, recovery behaviors are plugins. A typical configuration:
recovery_behaviors:
- id: "clear_costmap"
action: "nav2_clear_costmap_recovery::ClearCostmapRecovery"
- id: "backup_spin"
action: "nav2_simple_recovery_behavior::BackUp"
params:
backup_dist: 0.5
spin_dist: 360.0
- id: "wait"
action: "nav2_wait_recovery::WaitRecovery"
params:
wait_duration: 5.0
Failure Modes: When Recovery Fails
Scenario 1: Persistent Obstacle
Planning fails → Clear costmap → Plan succeeds → Robot drives → Collision!
The costmap clearing removed the real obstacle. This happens when your inflation radius is too aggressive or your cost threshold is too permissive.
Fix: Tighten cost thresholds, increase inflation radius, or add a timeout between recovery attempts (don’t keep clearing the same obstacle).
Scenario 2: Replanning Loop
Path computed → Tracking fails (obstacle appears) → Replan → Path computed → Tracking fails (obstacle reappears at different location) → Replan → ...
The robot oscillates, never making progress. Common in crowded environments with moving obstacles.
Fix: Add a bounded-replanning window. Only replan if 2+ seconds have elapsed since the last plan. Or use MPPI controller, which anticipates obstacles.
Scenario 3: Sensor Failure
LiDAR driver crashes → Costmap stops updating → Robot drives into obstacles it can't detect
Nav2 doesn’t auto-detect sensor failures. It just waits for the next sensor message (which never comes).
Fix: Implement a watchdog timer. If no sensor update arrives within N seconds, trigger a safety stop. Most production deployments use a hardware safety relay (independent of software).
Part 8: Multi-Robot Coordination with Open-RMF
The Fleet Problem
As the warehouse grows from 3 robots to 50, new problems emerge:
- Traffic Conflicts: Robot A and Robot B plan paths that cross at the same time, same location.
- Resource Contention: Two robots need the same charging dock.
- Task Allocation: Which robot should pick up this part? The nearest? The least-busy?
Nav2 solves single-robot navigation. It doesn’t coordinate multi-robot systems. That’s where Open-RMF (Robot Middleware Framework) enters.
Open-RMF Architecture

Open-RMF is a middleware layer above Nav2. Each robot runs its own Nav2 stack (perception, planning, control). Open-RMF adds:
- Fleet Manager (per robot or per fleet): Translates abstract tasks into itineraries (sequences of poses). Reports actual robot state.
- Traffic Schedule Database: A centralized database where all fleet managers register their planned routes.
- Conflict Detection: Detects when two robots will be in the same place at the same time.
- Negotiation: Fleet managers exchange alternative itineraries.
- Arbitration: A third-party judge chooses which itineraries to accept.
Example: Resolving a Conflict
Initial State:
– Robot A: taskA assigned; plans to travel from Station 1 → Station 2 (via Aisle C), ETA 10 s
– Robot B: taskB assigned; plans to travel from Station 3 → Station 2 (via Aisle C), ETA 8 s
– Both robots will reach Aisle C at t=9s. Conflict.
Negotiation:
– Traffic Schedule Database detects conflict, sends notice to fleet managers for A and B
– Fleet Manager A proposes: “Robot A waits 5 s, then moves” (revised ETA: 15 s)
– Fleet Manager B proposes: “Robot B takes longer route via Aisle D” (revised ETA: 15 s)
– Judge evaluates proposals:
– Option A: Robot A waits (minimal cost; no extra distance)
– Option B: Robot B takes longer route (extra 7 s)
– Decision: Accept Option A (Robot A waits)
– Both fleet managers implement their agreed itineraries
Result: No deadlock, no collision, minimal time loss.
Open-RMF Trade-Offs
Advantages:
– Standardized multi-fleet coordination (supports heterogeneous robots)
– Traffic safety at the system level
– Supports building infrastructure integration (lifts, doors, elevators)
Disadvantages:
– Requires all robots to report itineraries ahead of time
– Doesn’t handle dynamic obstacles (people, moving boxes) well; only vehicle-to-vehicle conflicts
– Adds operational complexity (must deploy and maintain the schedule database)
Practical Use:
– Warehouses with predictable task workflows (pick-and-place, delivery routes)
– Mixed environments with human workers (ensure robots don’t collide with each other, leaving people to navigate dynamically)
– Multi-vendor robot fleets (ensure ISO-standardized interoperability)
Part 9: Deployment Challenges and Failure Modes
Challenge 1: Costmap Tuning
The inflation radius and static map are the biggest tuning variables. Too conservative, and the fleet can’t navigate. Too aggressive, and robots collide.
Real Warehouse Example:
– Warehouse aisles: 1.2 m wide
– Robot width: 0.8 m
– Robot radius (bounding circle): 0.5 m
– Inflation radius: 0.4 m (safety buffer)
When inflation is applied:
– Obstacle cost inflates from 0–0.4 m radius
– Robot can’t navigate if both walls are within inflation range
– Effective passable width: 1.2 − 2*(0.4) = 0.4 m. Too tight!
Solution: Reduce inflation to 0.25 m. Increases crash risk but allows aisle navigation. Mitigate with sensors (bumpers, range scanners at multiple heights).
Challenge 2: SLAM Failures Outdoors
In outdoor yards, GPS multipath and foliage cause:
- GPS Drifts: Sudden 2 m jumps in pose estimates
- SLAM Loop Closures Fail: Vegetation hides landmarks
- Sensor Noise: Rain/fog degrade LiDAR
Mitigation:
– Use RTK-GPS (centimeter-level accuracy) to anchor the pose graph
– Use camera-based loop closure detection (more robust than LiDAR in foliage)
– Deploy in GPS-known zones (open areas with clear sky view)
Challenge 3: Replanning Latency
If the planner takes 200 ms and the robot is moving at 1 m/s, it travels 20 cm before getting a new plan. In a fast-moving warehouse, that’s risky.
Solutions:
– Use faster planners (Theta or even NavFn) if environment is mostly static
– Precompute multiple candidate paths and cache them
– Use a cost-aware local planner* that temporarily detours around obstacles without replanning globally
Challenge 4: ROS 1 → ROS 2 Migration
Many warehouses have ROS 1 robots. Migrating to ROS 2 is non-trivial:
API Changes:
– ROS 1: rospy.Subscriber('topic', Msg, callback)
– ROS 2: self.subscription = self.create_subscription(Msg, 'topic', callback, qos_profile=10)
Timing:
– ROS 1: Global clock (assumes synchronized wall clocks)
– ROS 2: Per-subscription QoS (must configure reliability, durability, history)
Tooling:
– Launch files: XML (ROS 1) → Python (ROS 2)
– Build system: catkin → colcon
Reality: Incremental migration is recommended. Use ros1_bridge as a temporary interop layer, but plan to retire it. ROS 1 Noetic hits end-of-life in May 2025, with no further updates.
Challenge 5: Dynamic Environments
Static obstacle layers assume the map doesn’t change. But warehouses are dynamic:
- Boxes are moved
- Shelves are rearranged
- Human operators walk around
Failure Mode:
Old map shows clear path from A to B
Shelf moved; path is now blocked
Robot receives path, follows it, crashes into shelf
Mitigations:
– Use costmap layers (obstacle + voxel) as the source of truth, not the static map
– Regularly refresh the static map (weekly or monthly scans)
– Use SLAM’s localization mode to continuously refine the map
Part 10: Tuning Guide for Production Deployments
Phase 1: Bench Testing (No Hardware)
-
Build a detailed costmap:
bash
ros2 launch nav2_bringup navigation_launch.py use_sim_time:=true
Play back a bag file of sensor data; visualize costmap in RViz. -
Test planner, without worrying about following:
bash
# Publish initial pose, then goal
ros2 topic pub /initialpose geometry_msgs/PoseWithCovarianceStamped '{header: {frame_id: "map"}, pose: {...}}'
ros2 topic pub /goal_pose geometry_msgs/PoseStamped '{header: {frame_id: "map"}, pose: {...}}'
Verify path is collision-free and reasonable. -
Test controller against pre-recorded trajectories. Visualize in RViz.
Phase 2: Hardware Integration
-
Bringup checklist:
– Robot wheels spin when given Cmd_Vel
– LiDAR produces scans
– Odometry integrates wheel encoder data
– SLAM runs, maps build incrementally -
Tune SLAM first:
– Adjust scan matcher parameters (ICP iterations, max range)
– Verify loop closure detection (should happen every 50–100 m)
– Validate pose graph optimization (map should not drift) -
Tune AMCL:
– Initialize withSetInitialPose(don’t rely on SLAM start)
– Verify particle filter converges in < 5 seconds
– Check that odometry drift is corrected
Phase 3: Costmap Tuning
-
Set inflation radius:
yaml
inflation_layer:
inflation_radius: 0.25 # Start conservative
cost_scaling_factor: 5.0 # Adjust steepness
Drive robot through narrow aisles. If it can’t pass, reduce inflation. -
Configure obstacle layer:
yaml
obstacle_layer:
max_obstacle_height: 1.5 # Overhead clearance
raytrace_max_range: 15.0 # Max LiDAR range to trust
mark_threshold: 2 # Hits before marking occupied -
Test with moving obstacles. Throw boxes, have people walk. Verify costmap updates within 500 ms.
Phase 4: Path Planning Tuning
-
Choose planner:
– Start with Smac 2D (default, good balance)
– If too slow, switch to NavFn
– If paths are poor, try Theta* -
Tune planner-specific params:
yaml
smac_planner:
smooth_path: true
cost_travel_multiplier: 2.0 # Penalize high-cost cells
downsample_costmap: false # No downsampling -
Measure planning time:
bash
ros2 run nav2_bringup generate_diagnostic_report --check-planner-timing
Should be < 100 ms for typical warehouse.
Phase 5: Controller Tuning
-
Choose controller:
– Start with DWB if compute is limited
– Use MPPI if smooth paths are critical
– Use RPP only for open environments -
Tune velocity limits:
yaml
robot_base_frame: "base_link"
max_vel_theta: 1.57 # rad/s
max_vel_x: 1.0 # m/s
max_accel_x: 0.5 # m/s^2
Start conservative; increase if tracking is sluggish. -
Tune critics (DWB):
“`yaml
critics:- class_name: “nav2_dwb_critics::PathAlignCritic”
scale: 32.0 # Weight of path following - class_name: “nav2_dwb_critics::ObstacleCritic”
scale: 0.02 # Weight of obstacle avoidance
“`
- class_name: “nav2_dwb_critics::PathAlignCritic”
Phase 6: Validation
-
Drive through worst-case scenarios:
– Narrow aisles (1.2 m wide)
– Dense clutter (boxes everywhere)
– Dynamic obstacles (people walking)
– GPS-denied zones (indoors)
– GPS-rich zones (outdoors) -
Measure KPIs:
– Success rate: % of navigation attempts that reach goal
– Average latency: Time from goal to arrival
– Collision rate: (crashes per 1000 km)
– Recovery frequency: % of routes requiring recovery -
Safety audits: Ensure recovery behaviors work, watchdog timers fire, and fail-safes prevent collisions.
Part 11: Real-World Example – Warehouse Deployment
Setup: 20-Robot Fleet in a 50,000 m² Warehouse
Infrastructure:
– LiDAR (30 m range, 10 Hz) per robot
– RTK-GPS for outdoor yard
– Wireless network (5 GHz mesh)
– Central task server (task allocation)
– Open-RMF traffic schedule database
Configuration:
– SLAM: SLAM Toolbox (map built incrementally over 1 week)
– Localization: AMCL (starts from initial pose, converges in 5 s)
– Planner: Smac 2D (100 ms planning time typical)
– Controller: MPPI (50 ms cycle, 100 Hz capable)
– Fleet Coordination: Open-RMF with traffic schedule
Week 1: Mapping Phase
- 3 robots drive around the warehouse under teleoperation
- SLAM Toolbox builds the occupancy map
- Loop closure detection integrates multiple passes
- Final map: 50k cells @ 5 cm resolution = 200 MB (uncompressed)
Week 2: Validation & Tuning
- Costmap inflation tuned: 0.25 m (balance between safety and aisle passability)
- AMCL convergence verified: < 5 s across the warehouse
- Path planner: Smac 2D set to smooth_path=true, cost_travel_multiplier=2.0
- Controller: MPPI tuned for 1 m/s max speed, 0.5 m/s² accel
Week 3+: Operations
Day 1 – Success:
Task: Pick part from Aisle A, deliver to Assembly Line B
Robot 1: SetInitialPose → ComputePath (85 ms) → FollowPath (smooth) → Goal reached (150 s)
Result: Success. No obstacles, no recoveries.
Day 2 – Recovery:
Task: Pick part from Aisle C, deliver to Dock D
Event: At t=30s, a forklift enters Aisle C (unplanned)
Robot 2: Following path, detects obstacle in costmap
Controller: Adjusts trajectory to avoid (MPPI lookahead = 2s)
Path still valid after obstacle is cleared
Result: Success. 10 s delay. No recovery behavior triggered.
Day 3 – Failure & Recovery:
Task: Pick part from Aisle E, deliver to Dock F
Event: At t=45s, aisle is blocked by a moved shelf (static change)
Robot 3: Planning fails (goal is unreachable)
Recovery 1: Clear costmap → Plan fails again (shelf is real)
Recovery 2: Backup & spin → Plan fails (goal is still unreachable)
Recovery 3: Request assistance
Human operator: Remotely moves the shelf
Robot 3: Resumes, reaches goal (20 s delay)
Result: Handled gracefully. Safety-critical; no collision.
Metrics after 1 week:
– Fleet success rate: 98% (2 failures required human intervention)
– Average navigation latency: 140 seconds (includes task-specific delays)
– Collision rate: 0 per 1000 km
– Recovery frequency: 3% of routes
Part 12: Future Directions and Emerging Patterns
ROS 2 Jazzy & Beyond
ROS 2 is evolving:
- Jazzy (2024): Improved performance, better GPU integration
- Rolling (latest): Experimental features, monthly snapshots
For Nav2:
– Adaptive costmap layers (layers adjust based on environment context)
– GPU-accelerated planners (CUDA kernels for A*, not yet mainstream)
– Learned controllers (neural networks trained on human trajectories)
Sim-to-Real Transfer
Deployments increasingly use simulation (Gazebo, CoppeliaSim) to:
– Test costmap algorithms before hardware
– Generate synthetic sensor data for SLAM training
– Benchmark planners and controllers
Challenge: Sim-to-real gap. Simulated sensor noise, friction, and dynamics differ from reality. Successful deployments spend 20% of time in simulation, 80% on real hardware validation.
Multi-Sensor Fusion
Next-gen warehouses will integrate:
– Thermal cameras: Detect hot objects (recently moved boxes)
– Event cameras: High-speed obstacle detection (avoids motion blur)
– Acoustic sensors: Detect equipment beeping (don’t get close)
– 5G cellular: Cloud-offloaded planning (send costmap to central server, get back paths)
These require new fusion algorithms and cost models in Nav2.
Integrating Classical and Learned Components
The trend is hybrid:
– Classical SLAM: Still the best for unknown environments
– Learned obstacle detection: Neural nets trained on warehouse imagery
– Classical planning: A and variants are still optimal
– Learned control*: RNNs trained to smooth trajectories, anticipate obstacles
This hybrid approach leverages the interpretability of classical methods with the flexibility of learning.
Conclusion: Building Trust in Autonomous Fleets
ROS 2 Nav2 is a production-proven stack for autonomous mobile robots. Its architecture—composed of perception, localization, planning, and control layers—mirrors biological nervous systems. Each layer is independently tunable, testable, and replaceable.
The key insight: Navigation is not a single algorithm. It’s a composition of specialized algorithms, each handling a subproblem:
- SLAM: Build a global reference
- AMCL: Estimate position within that reference
- Costmap: Represent obstacle risk
- Planning: Compute collision-free paths
- Control: Track paths in dynamic environments
- Behavior Tree: Orchestrate recovery and task execution
- Open-RMF: Coordinate multi-robot fleets
To deploy Nav2 successfully:
- Understand the pipeline: Sensor → Perception → Localization → Planning → Control → Motor. Latency and synchronization matter.
- Tune iteratively: Start with conservative parameters. Measure (success rate, latency, recovery frequency). Adjust. Repeat.
- Test failure modes: Sensor failures, environmental changes, dynamic obstacles. Build recovery behaviors incrementally.
- Validate on real hardware: Simulation is a starting point, not the destination. 80% of effort is real-world validation.
- Plan for the human: Recovery behaviors escalate to humans. Design human-robot interaction loops.
- Monitor in production: Deploy watchdogs, safety relays, and telemetry. When a robot fails, diagnose why.
The autonomous warehouse is no longer science fiction. It’s built on layers of classical robotics (SLAM, A*, particle filters) combined with modern ROS 2 middleware. The robots weaving between aisles at 3 AM are running Nav2.
References
- Nav2 Documentation
- Nav2 GitHub Repository
- SLAM Toolbox GitHub
- Costmap 2D Configuration Guide
- Smac Planner Documentation
- DWB Local Planner Configuration
- MPPI Controller Documentation
- Open-RMF Documentation
- ROS 2 Jazzy Migration Guide
- Programming Multiple Robots with ROS 2
- GPS and SLAM Fusion for Autonomous Robots – IEEE Xplore
- ROS 1 to ROS 2 Migration: Ekumen Blog
