Proportional control
One gain, the whole trade-off, and the steady state error it cannot remove.
Do this lesson in the simulatorcommand = Kp * error
One line, one number to choose, and most of what a controller does.
What the gain means
Kp has units. Here the error is in centimetres and the command is in percent, so Kp is percent per centimetre. At Kp = 2, being 10 cm out asks for 20 percent. That is a physical statement, not a magic number, and it is why the same gain on a different robot means something different.
Turning it up
from bugbot import *
connect()
TARGET = 30.0
for KP in (0.5, 2.0, 6.0):
for tick in range(60):
error = distance() - TARGET
plot("kp %s" % KP, error)
drive(max(-70, min(70, KP * error)), 0, 0)
wait(0.1)
stop()
print("kp", KP, "ended at", round(distance(), 1))
backward(60, distance=25)
wait(0.5)
Three shapes on one chart:
- 0.5: creeps in, still going when the time runs out. Gentle, slow, and never quite arrives.
- 2.0: arrives in a few seconds and stays. This is the one you want.
- 6.0: arrives fast, overshoots, comes back, overshoots again. It settles eventually, and it looks awful doing it.
The steady state error
The low gain case does not just look slow. It stops short, and stays short.
The reason is in the actuator. Below about 15 percent this drive does not move at all. At Kp = 0.5, an error of 2 cm asks for 1 percent, the motors do nothing, and the error stays at 2 cm for ever. The controller is asking for a push too small for the machine to deliver.
That is steady state error, and it is not a fault in the arithmetic. Proportional control needs an error to produce an output. When the output it produces is too small to move anything, the error stops shrinking.
Three ways out, in increasing order of respectability:
- Raise the gain, and accept the overshoot that comes with it.
- Add a dead band and declare that close enough is close enough.
- Add an integral term, which accumulates a small error until it becomes a large enough push. That is U5.4, and it is the real answer.
Choosing Kp by hand
- Start low, say 1.
- Double it until the robot overshoots or wobbles.
- Halve that.
Crude, effective, and it is roughly what most people actually do. U5.5 is the version with a method behind it.
Task: find a gain that works
Settle 30 cm from the wall, within 5 cm, and stay there from ten seconds onwards. Print the kp: you chose.
from bugbot import *
connect()
KP = 1.0
TARGET = 30.0
Challenges
- Find the gain at which it first overshoots, to the nearest 0.5.
- Find the gain below which it never arrives at all. Explain it with the dead band.
- Run the same gain from 100 cm away and from 5 cm away. Does the same number suit both?