Design & Selection · Module 14
Selecting controller update rates
A sampled controller adds about one and a half periods of delay. The faster the loop you want, the faster the controller must run.
Assumptions: Numbers in the examples are illustrative and the code is executed by the site’s tests. Facts taken from a cited source are marked; other statements are general engineering knowledge and must be confirmed on the datasheet of the part you use.
1. Engineering problem
Running a control loop too slowly adds delay that eats the phase margin and causes oscillation. Running it faster costs compute and requires sensors that update that fast. The choice follows from the bandwidth you want.
2. When is this needed?
- Choosing rates for motor, velocity and navigation loops.
- When a loop oscillates and a faster rate helps.
- Budgeting CPU and bus bandwidth.
3. Selection and design decisions
A common approximation models the sample-and-hold plus computation delay as about 1.5 sampling periods; the phase lost at the crossover frequency fc is then 360°·fc·1.5/fs. A widely used rule of thumb is a sampling rate of 10 to 20 times the loop bandwidth or more (engineering practice, not from one cited standard). Other rates in the stack are set elsewhere: the Nav2 default parameters run the controller server at 20 Hz (read 2026-11-06), and the diff_drive_controller publishes odometry at 50 Hz by default. The Nav2 velocity smoother can run faster than the controller to interpolate commands (for example 100 Hz for a 20 Hz controller, per its README).
| Loop | Typical rate (practice) | Reason |
|---|---|---|
| Motor current loop (driver firmware) | Several kHz to tens of kHz | Fastest, in the driver |
| Wheel velocity loop | 100 Hz to 1 kHz | Bandwidth of a few to tens of Hz |
| Odometry publishing | 50 Hz (diff_drive default) | Must exceed the control rates that use it |
| Navigation local controller | 10 to 50 Hz (Nav2 default 20 Hz) | Follows the costmap update |
| Planning | 1 Hz or lower | Replans on events |
4. Advantages and disadvantages
- Faster loops reduce delay and cost compute, bus bandwidth and sometimes noise.
- Rate ladders: each loop should be several times slower than the one it commands.
- Jitter in a slow loop is worse than a bit more latency in a fast one.
5. Requirements and constraints
- Sensor rate at least the controller rate (no repeated stale samples).
- Controller thread meets its deadline (see the real-time guide).
- Each outer loop is slower than its inner loop by a factor of several.
6. Architecture
planner (1 Hz) ─▶ local controller (20 Hz) ─▶ velocity smoother (higher rate) ─▶ wheel loop (100 Hz to 1 kHz) ─▶ driver current loop7. Implementation
- State the bandwidth each loop needs.
- Compute the phase lost at that bandwidth for candidate rates (below).
- Check sensor and bus capacity for the rate.
- Check CPU and deadline for the rate.
- Test for oscillation margin on the real robot.
import math
def phase_lost(rate_hz, fc_hz, delay_periods=1.5):
t_delay = delay_periods / rate_hz # sample-and-hold plus computation delay, in periods (a common approximation)
return math.degrees(2 * math.pi * fc_hz * t_delay)
fc = 5.0
for rate in (20, 50, 100, 500):
lost = phase_lost(rate, fc)
print(f"{rate:3d} Hz loop, {fc:.0f} Hz crossover: delay costs about {lost:5.1f} deg of phase margin ({rate / fc:.0f}x the crossover frequency)")Printed (checked by the site’s tests):
20 Hz loop, 5 Hz crossover: delay costs about 135.0 deg of phase margin (4x the crossover frequency)
50 Hz loop, 5 Hz crossover: delay costs about 54.0 deg of phase margin (10x the crossover frequency)
100 Hz loop, 5 Hz crossover: delay costs about 27.0 deg of phase margin (20x the crossover frequency)
500 Hz loop, 5 Hz crossover: delay costs about 5.4 deg of phase margin (100x the crossover frequency)Reading it: for a 5 Hz crossover, a 20 Hz loop (4×) costs about 135° of phase, which leaves nothing for stability; 50 Hz (10×) costs 54°; 100 Hz (20×) costs 27°; 500 Hz (100×) costs 5.4°. The approximation of 1.5 periods of delay is a rule of thumb, and real delays include sensor and communication latency.
8. Real examples
- AMR: 1 kHz wheel loops on the microcontroller, 50 Hz odometry, 20 Hz Nav2 controller.
9. Failure scenarios
- A velocity loop at 20 Hz asked to have a 5 Hz bandwidth.
- Sensor at 30 Hz feeding a 1 kHz loop that sees steps.
- A loop rate the CPU cannot sustain, giving jitter.
10. Troubleshooting
- Measure the actual loop period and its jitter.
- Estimate the total delay including sensors.
- Increase the rate or reduce the bandwidth.
11. Validation
- The calculation prints the lines shown (executed by the site tests).
- Measured loop jitter is small against the period.
12. Engineering checklist
13. Further references
- Nav2 default parameters (jazzy): nav2_params.yaml, read 2026-11-06.
- Nav2 velocity smoother README (jazzy): nav2_velocity_smoother, read 2026-11-06.
- diff_drive_controller parameters (ros2_controllers, jazzy branch): diff_drive_controller_parameter.yaml, read 2026-11-06.