TL;DR:
Tune one term at a time in this order: P first, then D to calm overshoot, then a little I to remove the steady error.
With P alone, a typical loop settles short of the target by an amount that shrinks as P grows, but it oscillates when P is too large.
Log the target, the measurement and the output every run, and change one gain at a time.
You set a wheel to run at 100 rpm and it settles at 50. You double the gain and it settles at 75, then at a higher gain it starts to shake. This is the normal path of tuning a PID loop. Guessing three numbers at once rarely works, but an order of steps does.
Know what you are tuning
A wheel speed controller measures the speed with an encoder, compares it with the target, and sets the motor's PWM command. The error is target − measured. The terms are the same ones explained in PID control with a line-following robot: proportional, integral, derivative.
Before tuning, check the basics. The encoder must count in the right direction, the speed estimate must be steady (see sensor noise), the loop must run at a fixed rate, and the output must be limited to the allowed PWM range. A sign mistake turns a control loop into a runaway.
Step 1: set up logging
Print or store a row each loop: time, target, measured speed, output command. Then plot it. A plot shows overshoot, oscillation and offsets that you cannot see by eye. Do this before changing any gain. Then run a step test: change the target from 0 to a fixed speed and watch the response.
Step 2: P alone
Set Ki = 0 and Kd = 0. Start with a small Kp and raise it between runs. Watch for three things: how fast it reaches the target (rise time), how far it overshoots, and where it ends up.
Worked example: tuning a wheel speed controller
Use a simplified model, to see the logic with numbers. Suppose the motor's steady speed is 0.5 rpm for each unit of command (a gain G = 0.5), and the target is r = 100 rpm. With P control the command is u = Kp × (r − speed). In steady state, speed = G × u, so:
speed = G·Kp·(r − speed), which gives speed = G·Kp·r / (1 + G·Kp).
The leftover error is r / (1 + G·Kp).
Kp | G·Kp | Steady speed | Steady error |
|---|---|---|---|
2 | 1 | 50 rpm | 50 rpm |
6 | 3 | 75 rpm | 25 rpm |
18 | 9 | 90 rpm | 10 rpm |
Check one row: for Kp = 6, G·Kp = 3, so speed = 3 × 100 / 4 = 75 and the error is 100 / 4 = 25.
So P alone leaves a steady-state error, and it only shrinks as Kp rises. A real motor also has delay and inertia, so past some Kp the speed overshoots and begins to oscillate. This simple model has no such dynamics, so treat it as the first half of the story.
Pick the value just below where oscillation starts. A common practice is to take a Kp somewhat below the value at which the loop first oscillates steadily.
Step 3: add D for overshoot
If the response overshoots and rings, add Kd. D responds to the rate of change of the error, so it pushes against rapid changes and calms the ringing. Increase it slowly. Too much D amplifies noise, and the motor buzzes or the output jitters. Filter the speed measurement if needed.
Step 4: add I for the steady error
Now the leftover offset from the table matters. Add a small Ki. The integral term keeps growing while there is any error, so it pushes until the error is zero. In the example, the integral keeps raising the command until the speed hits 100 rpm exactly, which needs u = 100 / 0.5 = 200 units. Raise Ki just enough that the offset disappears in a reasonable time. Too much I causes slow oscillation and overshoot.
Add anti-windup: clamp the integral sum so that it cannot grow without limit when the output is saturated, for example when the motor is blocked.
A tuning loop that works
Log a step response.
Change one gain.
Log again and compare.
Keep a note of each setting and what happened.
Stop when the response is good enough for the job. There is no perfect set of gains.
Re-tune when conditions change. A battery at a lower charge, a heavier load or a different floor changes the plant, and the same gains may give a different response.
Where it goes wrong
Changing several gains at once. You will not know which one helped.
Tuning on a stand and running on the floor. The load differs, so check on the real surface.
Ignoring saturation. If the output is at its limit the controller cannot do more, whatever the gains.
A slow or irregular loop. If the loop timing wobbles, the D and I terms are wrong. Use a fixed time step.
Chasing noise. If the plot is jagged because of the sensor, fix the sensor first.
Safety: Put the robot on a stand with wheels off the ground for the first runs, because a high gain or wrong sign can make the wheels run to full power suddenly. Keep a kill switch within reach and keep fingers, hair and cables clear of the wheels. After tuning on a stand, do the first floor runs at low speed in an open area.
Try it yourself
Pick one motor with an encoder. Log a step response at three values of Kp, plot them together and mark the steady error and the overshoot on each. Then add a small Kd and then a small Ki and compare. Keep the plots. The difference between your first and last plots is the whole job of tuning. For the wider picture of why feedback is used at all, see feedback vs open-loop control.
Frequently asked questions
Is there a formula that gives the right gains?
There are rules of thumb, and they can give a start, but real hardware has friction, delay and noise, so you still test and adjust using logged data.
Why add D after P?
P alone often overshoots and rings. D damps that by reacting to how fast the error changes, so it makes sense to fix this before adding I, which can make overshoot worse.
