If you run the program with different gain settings you will
see several things going on. First with just the proportional
gain nonzero, the steady state is an oscillation around the ratio
between the set point and the (fractional) gain,
( `set_point @ kp @ 128 */` ) .
Also the oscillations damp out
at a rate that is inversely proportional to the gain. Consequently
the ability to quickly damp out the oscillations competes against
the ability to reach the desired output setting.
The DC level of the output can be
tweaked by adjusting the initial output value, but simply using the
integral term takes care of that automatically. Setting the P and I
terms to nonzero makes the output actually settle out at the desired
setting. If you now add the derivative term (by setting its gain to
nonzero), the controller will respond more quickly to changes in the
set point. The problem with the derivative term is that it is
very sensitive to noise in the data, it looks pretty helpful if
the noise is zero, but it amplifies the noise if its not zero.

Play around with different settings and see how the controller responds. For extra credit, replace my sensor/controller simulator with the real thing, try replacing the sensor with the frequency counter from last time (measuring the RPM of a motor by counting revolutions) and the controller with the PWM motor controller from FD XVIII Number 2, giving you a speed controlled motor that will automatically adjust for varying loads.