Robotics From Zero
Module: Move Carefully

Tuning & Debugging

Practical techniques for tuning PID controllers, diagnosing motion problems, and making your robot move smoothly.

8 min read

Tuning & Debugging

You built a PID controller, picked some gains, and hit run. Your robot lurches forward, overshoots the target, wobbles, and eventually settles -- kind of. Or maybe it just vibrates in place. Now what?

This lesson is about the practical side: how to systematically tune PID gains, how to read the signs when something is wrong, and how to use logging and testing to prove your controller actually works.

Manual Tuning: The Step-by-Step Method

If you have no idea where to start, follow this sequence. It works for nearly every system.

Step 1. Set Kp = 0, Ki = 0, Kd = 0. The robot should not move.

Step 2. Increase Kp slowly. Command a step change (e.g., target speed jumps from 0 to 1.0 m/s). Watch the response:

  • Too low: the robot barely moves.
  • Good: the robot reaches the target quickly but overshoots a little.
  • Too high: the robot oscillates and never settles.
Progressive PID tuning — step-by-step process showing the effect of increasing Kp, then adding Ki, then Kd
Manual tuning follows a clear sequence: start with P only (increase until oscillation), then add I to eliminate steady-state error, then add D to damp overshoot. Each step builds on the last.

Stop when you see sustained oscillation (constant back-and-forth). Note this critical gain as Ku, then set Kp = 0.5 * Ku.

Step 3. If the robot settles close to the target but not exactly on it (steady-state error), increase Ki in small increments until the error disappears. Use the minimum Ki that works.

Step 4. If overshoot is a problem, increase Kd to add damping. Go slowly -- too much Kd amplifies sensor noise and causes jitter.

Tip

Most wheeled robots work well with just PI control (Kd = 0). Only add the D term if you see persistent overshoot that the P and I terms cannot solve alone.

Ziegler-Nichols: A Classic Starting Point

The Ziegler-Nichols method gives you a formula-based starting point. It is not magic -- you will still need to refine the results -- but it gets you in the right ballpark.

  1. Set Ki = 0 and Kd = 0.
  2. Increase Kp until the system oscillates continuously at a constant amplitude. This is the ultimate gain Ku.
  3. Measure the oscillation period Tu (seconds for one full cycle).
Ziegler-Nichols method — showing the critical oscillation with ultimate gain Ku and period Tu marked
The Ziegler-Nichols method finds the boundary of stability: increase Kp until the system oscillates at constant amplitude. The gain at this point (Ku) and the oscillation period (Tu) feed into formulas that estimate good PID gains.
  1. Apply the formulas:
ControllerKpKiKd
P only0.5 * Ku00
PI0.45 * Ku1.2 * Kp / Tu0
PID0.6 * Ku2 * Kp / TuKp * Tu / 8

For example, if Ku = 4.0 and Tu = 0.4 s:

  • Kp = 0.6 * 4.0 = 2.4
  • Ki = 2 * 2.4 / 0.4 = 12.0
  • Kd = 2.4 * 0.4 / 8 = 0.12
Warning

Ziegler-Nichols was designed for slow industrial processes and often produces aggressive gains for fast mechanical systems. Treat the output as a starting point, then reduce Ki and Kd if the response is too aggressive.

Diagnosing Common Problems

Common PID problems — visual gallery showing oscillation, overshoot, steady-state error, integral windup, and noise amplification
Six common PID failure modes at a glance. Each has a distinct signature in the step response plot — learning to recognize these patterns lets you diagnose problems instantly.

When your robot misbehaves, the symptom tells you which gain to adjust.

SymptomLikely CauseFix
Oscillates around the targetKp too highLower Kp, or increase Kd to add damping
Overshoots then slowly settlesKp slightly too high, Kd too lowLower Kp or raise Kd
Settles below the target (steady-state error)Ki too low or zeroIncrease Ki gradually
Very slow to reach the targetKp too lowIncrease Kp
Jitters and twitches near the targetKd too high, amplifying sensor noiseLower Kd, or filter sensor data
Shoots forward after being stuckIntegral windupAdd anti-windup (clamp the integral term)
anti_windup_pid.py
class PIDController:
    def __init__(self, Kp, Ki, Kd, max_integral=10.0):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.max_integral = max_integral
        self.integral = 0.0
        self.prev_error = 0.0
 
    def update(self, target, actual, dt):
        error = target - actual
 
        # Proportional
        P = self.Kp * error
 
        # Integral with anti-windup clamp
        self.integral += error * dt
        self.integral = max(-self.max_integral,
                           min(self.max_integral, self.integral))
        I = self.Ki * self.integral
 
        # Derivative (on error)
        D = self.Kd * (error - self.prev_error) / dt
        self.prev_error = error
 
        return P + I + D

Using Logs and Plots to Debug

Staring at a moving robot and guessing what is wrong is a losing strategy. Instead, log the data and plot it.

Record these values every control loop iteration:

  • Timestamp -- so you can see timing.
  • Target (setpoint) -- what you asked for.
  • Actual (measurement) -- what the sensor reported.
  • Error -- the difference.
  • P, I, D terms -- the individual contributions.
  • Total output -- what was sent to the motor.
logging_pid.py
import csv
 
log_file = open("pid_log.csv", "w", newline="")
writer = csv.writer(log_file)
writer.writerow(["time", "target", "actual", "error", "P", "I", "D", "output"])
 
t = 0.0
while t < 10.0:
    actual = sensor.read()
    error = target - actual
 
    P = pid.Kp * error
    I = pid.Ki * pid.integral
    D = pid.Kd * (error - pid.prev_error) / dt
    output = pid.update(target, actual, dt)
 
    writer.writerow([f"{t:.3f}", target, f"{actual:.4f}",
                     f"{error:.4f}", f"{P:.4f}", f"{I:.4f}",
                     f"{D:.4f}", f"{output:.4f}"])
 
    motor.set_power(output)
    t += dt
 
log_file.close()

Plot the CSV and look for these patterns:

  • Target vs. Actual diverging: your gains are too low overall.
  • Actual oscillating around Target: Kp too high or Kd too low.
  • I term growing without bound: you need anti-windup.
  • D term spiking wildly: sensor noise -- add a low-pass filter.
  • Actual never reaching Target: steady-state error, increase Ki.
Tuning effects grid — 3×3 grid showing the effect of low, medium, and high values for Kp, Ki, and Kd
A visual reference card for PID tuning. Each row shows what happens when you increase one gain: more P → faster but oscillates, more I → eliminates offset but overshoots, more D → smoother but sensitive to noise.

A single plot of target vs. actual over time will tell you more in ten seconds than ten minutes of watching the robot.

Testing Strategies

Do not declare your controller "tuned" until you have tested it properly. Here are three tests every PID controller should pass.

1. Step Response Test

Command a sudden change in setpoint (e.g., target speed jumps from 0 to 1.0 m/s). Measure:

  • Rise time: how quickly the actual value reaches 90% of the target.
  • Overshoot: how far past the target the actual value goes (ideally under 10%).
  • Settling time: how long until the actual value stays within 2% of the target.

2. Tracking Test

Command a smoothly changing setpoint (e.g., a sine wave or ramp). Check that the actual value follows the target closely without lagging behind. Large tracking error means your gains are too low or your control loop is too slow.

3. Disturbance Rejection Test

While the robot is holding a steady setpoint, apply a disturbance -- push the robot, add weight, or change the surface. The controller should recover quickly. If it takes a long time to return to the target, increase Ki. If it oscillates after the disturbance, increase Kd or lower Kp.

What's Next?

You now have the complete toolkit for precise robot motion: closed-loop feedback, PID algorithms, motor control modes, velocity commands, and practical tuning and debugging techniques.

In Module 6, we shift from motion to perception -- how robots see and understand the world using cameras, lidar, and sensor fusion. Because even a perfectly tuned controller is useless if the robot does not know where it is going.

Got questions? Join the community

Discuss this lesson, get help, and connect with other learners on r/softwarerobotics.

Join r/softwarerobotics

Further Reading

Related Lessons

Discussion

Sign in to join the discussion.