Problem: Picking the Wrong Local Planner Costs You Weeks
You're setting up a mobile robot's navigation stack and need to choose a local planner. DWA and TEB both ship with ROS. Pick wrong and you'll spend weeks tuning a planner that was never right for your robot.
You'll learn:
- How DWA and TEB work under the hood
- Which performs better in tight spaces vs open environments
- Concrete config starting points for each
Time: 15 min | Level: Intermediate
Why This Happens
Both planners solve the same problem — navigate to a local goal while avoiding obstacles in real-time — but they use fundamentally different math. That difference matters enormously depending on your robot's kinematics, environment, and latency requirements.
Most teams default to DWA because it's simpler. That's fine until the robot starts cutting corners in narrow corridors or failing to squeeze through doorways. Then they switch to TEB without understanding why it's better in that case, and spend days re-tuning.
Common symptoms of a wrong planner choice:
- Robot oscillates near obstacles (DWA in tight spaces)
- Navigation stutters or replans constantly (TEB on slow hardware)
- Robot ignores kinematic constraints, jerks or skids
- Paths are geometrically correct but mechanically awkward
How Each Planner Works
Dynamic Window Approach (DWA)
DWA samples velocity commands (v, ω) from a window of dynamically feasible velocities — ones the robot can physically reach given its current speed and acceleration limits. It scores each candidate using a cost function balancing goal heading, clearance, and forward velocity, then executes the best one.
Admissible velocities = {(v, ω) | v ∈ [v_current - a·dt, v_current + a·dt]}
Score = α·heading + β·clearance + γ·velocity
It's a reactive, single-timestep planner. It sees the next 1–2 seconds of motion. Fast and predictable, but myopic.
DWA strengths:
- Very low CPU cost (~1–5ms per cycle on modest hardware)
- Predictable, easy to tune
- Works well in open or semi-structured environments
- Solid for differential drive robots
DWA weaknesses:
- Struggles with narrow passages (local minima)
- Can't optimize over a full trajectory horizon
- Poor handling of non-holonomic constraints in tight turns
- No time parametrization — doesn't account for dynamic obstacles well
Timed Elastic Band (TEB)
TEB represents the robot's path as a sequence of poses connected by time intervals — the "elastic band." It then runs a sparse graph optimization (using g2o under the hood) to minimize travel time while satisfying obstacle clearance, kinematic constraints, and dynamic feasibility simultaneously.
Objective: min Σ (time intervals)
Subject to:
- Obstacle clearance ≥ d_min for each pose
- |v| ≤ v_max, |ω| ≤ ω_max
- |a| ≤ a_max (kinematic model)
- Feasible for robot footprint (not just center point)
TEB optimizes over the entire trajectory horizon. It's globally aware within its local window.
TEB strengths:
- Handles narrow corridors and doorways well
- Supports car-like (Ackermann) robots natively
- Optimizes full trajectory, not just next velocity command
- Supports multiple topological paths simultaneously (homotopy classes)
TEB weaknesses:
- Higher CPU cost (~10–50ms per cycle depending on horizon length)
- More parameters to tune (~30+ vs DWA's ~12)
- Can produce oscillations if obstacle inflation is too tight
- Optimization can fail or produce infeasible plans in very cluttered scenes
Decision Framework
Use this to pick quickly:
| Factor | Use DWA | Use TEB |
|---|---|---|
| Environment | Open, structured | Narrow, complex |
| Robot type | Differential drive | Ackermann / car-like |
| CPU budget | Tight (embedded) | Available (x86/ARM) |
| Dynamic obstacles | Rare | Frequent |
| Tuning bandwidth | Low | High |
| ROS version | ROS 1 or 2 | ROS 1 or 2 (teb_local_planner) |
Short version: If your robot navigates warehouse aisles, apartments, or anywhere with doorways under 1.5m — use TEB. If it's in an open factory floor or outdoor environment — DWA is probably enough.
Solution
Step 1: Install and Configure DWA
DWA ships with nav2 (ROS 2) or navigation (ROS 1). For ROS 2:
# Already included in nav2, just set it in your nav2_params.yaml
sudo apt install ros-humble-nav2-dwb-controller
Minimal working config:
# nav2_params.yaml
controller_server:
ros__parameters:
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "dwb_core::DWBLocalPlanner"
# Velocity limits — match your robot's specs exactly
min_vel_x: 0.0
max_vel_x: 0.5 # m/s — start conservative
max_vel_theta: 1.0 # rad/s
min_speed_xy: 0.0
# Acceleration limits — prevents wheel slip
acc_lim_x: 2.5
acc_lim_theta: 3.2
decel_lim_x: -2.5
# Trajectory sampling — more = better but slower
vx_samples: 20
vtheta_samples: 40
sim_time: 1.7 # seconds ahead to simulate
# Critic weights — tune these for your environment
critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"]
PathAlign.scale: 32.0
GoalAlign.scale: 24.0
PathDist.scale: 32.0
GoalDist.scale: 24.0
BaseObstacle.scale: 0.02
Expected: Robot follows global path with smooth velocity transitions and stops before obstacles.
If it fails:
- Robot oscillates: Reduce
vtheta_samplesor increaseBaseObstacle.scale - Ignores path: Increase
PathAlign.scaleandPathDist.scale - Too slow near obstacles: Increase
max_vel_xand checkdecel_lim_x
Step 2: Install and Configure TEB
# ROS 2
sudo apt install ros-humble-teb-local-planner
# ROS 1
sudo apt install ros-noetic-teb-local-planner
Minimal working config for a differential drive robot:
# nav2_params.yaml (ROS 2) or local_planner_params.yaml (ROS 1)
TebLocalPlannerROS:
# Robot geometry — must be accurate
max_vel_x: 0.4
max_vel_x_backwards: 0.2
max_vel_theta: 0.8
acc_lim_x: 0.5
acc_lim_theta: 0.5
# Footprint model — use "circular" first, then "polygon" when tuned
footprint_model:
type: "circular"
radius: 0.25 # meters — slightly larger than real robot
# Obstacle clearance
min_obstacle_dist: 0.25 # Never go closer than this
inflation_dist: 0.6 # Start inflating at this distance
# Trajectory optimization
no_inner_iterations: 5
no_outer_iterations: 4
optimization_activate: true
# Horizon
max_samples: 500
max_global_plan_lookahead_dist: 3.0
# Kinematic model
cmd_angle_instead_rotvel: false # true for Ackermann
# Homotopy — enable for complex environments
enable_homotopy_class_planning: true
enable_multithreading: true
max_number_classes: 4
Expected: Robot takes smooth, geometrically aware paths through narrow spaces, slowing near obstacles.
If it fails:
- Optimization fails constantly: Increase
min_obstacle_distand reducemax_samples - Robot clips obstacles: Switch
footprint_model.typefrom"circular"to"polygon"and provide actual vertices - High CPU usage: Set
enable_homotopy_class_planning: falseand reduceno_outer_iterationsto 2
Step 3: Benchmark Both in Your Environment
Don't guess — measure. Use ROS's built-in logging:
# Record a navigation run
ros2 bag record /cmd_vel /odom /local_plan /cost_cloud -o nav_test
# Then compare:
# - /cmd_vel smoothness (fewer velocity reversals = better)
# - /local_plan length (shorter = more efficient)
# - CPU usage: htop while running
Run the same 5-10 goal sequence with each planner and compare:
# Quick analysis script — paste into a Jupyter notebook
import rosbag2_py
import numpy as np
# Load cmd_vel topic and compute jerk (rate of acceleration change)
# Higher mean jerk = less smooth = worse for hardware longevity
You should see: TEB produces lower jerk in narrow corridors. DWA produces lower CPU usage across all scenarios.
Verification
# Check planner is active
ros2 topic echo /local_plan --once
# Confirm no planning failures
ros2 topic echo /controller_server/transition_event
You should see: /local_plan publishing at 10–20Hz with a valid path. No FAILURE transitions in the controller server.
What You Learned
- DWA is a velocity-space sampler — fast, predictable, myopic
- TEB is a trajectory optimizer — slower, globally aware within its horizon, better for constrained spaces
- The right choice depends on environment geometry and CPU budget, not on which is "newer"
- Start with DWA and switch to TEB only when you hit specific failure modes (narrow passages, non-holonomic constraints)
Limitation: TEB's g2o optimizer can diverge in highly dynamic environments with many moving obstacles. In those cases, consider model-predictive control (MPC) planners like MPPI, which nav2 now ships as nav2_mppi_controller.
When NOT to use TEB: Embedded systems under 1GHz, environments where obstacles are purely dynamic (crowds), or when your team doesn't have bandwidth to tune 30+ parameters properly.
Tested on ROS 2 Humble, nav2 1.3.x, Ubuntu 22.04. TEB config applies to teb_local_planner 0.9+.