** Balancing robot for dummies **
Part four: PID control
Forewords: Control strategy is a whole univers, let's keep it simple
8 - Possible control strategies
error = Actual value - Set point
-
ON/OFF control
This strategy in used for electric heaters with mechanical thermostat
pseudo code
if actTemp < SetPoint Power = ON
else Power = OFF
Code for a basic (static) balancing robot
Set point = 0
error = actAngle
pseudo code
If actAngle = 0 Motors stop
else if actAngle <0 Motor full forward (PWM 256)
else if actAngle >0 Motor full backward (PWM 256)
Don't try it, it just doesn't work; let's be more sophisticated.
-
PID control (Proportional Integral Derivative)
This control is the sum of 3 actions
Proportional action:
The proportional term makes a change to the output that is proportional to the current error value.
pTerm = Kp * error
A high value will cause a hard counter reaction to a change in attitude.
Above a certain value the system will start to oscillate, the ideal spot is just below this point.
You cannot ballance a robot with a proportional value of 0.
Proportional control only is much better than pure ON/OFF, but the Bot will keep oscillating and finally fall on the floor
Derivative action:
This action is proportional to the error variation
With a fixed time loop, time may be omited:
dTerm = Kd * (error - last_error);
last_error = error;
The Derivative portion calculates how fast a change in angle occurs.
With ballancing bot, these values are usually used as a damping factor, meaning negative signs in the formula.
Without the derivative action, there is no damping to dissipate the energy of the system.
With only proportional control, any input to the system will cause an undamped oscillation that will continue for ever.
If you are an electrical engineer, think of how an RLC circuit differs from an LC circuit
The derivative term works the fastest, because it detects change in rate before even a significant error appears.
Integral action:
integrated_error += error;
iTerm = Ki * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
GUARD_GAIN sets up a limit for iTerm.
The integral term allows a precise landing at setpoint, it is known as "steady state error".
It is the only term that keeps changing no matter how small the error remains.
You're basically telling the controller, "if you aren't quite getting to angle, keep increasing PWM over a period of time until you get there".
PID control is the sum of those 3 actions
int updatePid(int targetPosition, int currentPosition) {
int error = targetPosition - currentPosition;
pTerm = Kp * error;
integrated_error += error;
iTerm = Ki * constrain(integrated_error, -GUARD_GAIN, GUARD_GAIN);
dTerm = Kd * (error - last_error);
last_error = error;
return -constrain(K*(pTerm + iTerm + dTerm), -255, 255);
}
The best PID analogy I found is the spring car suspension:
kp is the strength of the spring.
kd is the amount of damping needed to stop oscillations due to kp.
Proportional reacts to a measure of the present error.
Derivative reacts as a prediction of the future error,
Integral adjustment is based on past errors
PID tuning:
For manual tuning, set all three constants to zero, then turn up Kp until oscillation occurs.
Then turn up Kd until oscillation disappears. Adjust Kd until the system is critically damped, i.e. there's no overshoot.
Then increase Ki until the steady-state error goes to zero in a reasonable time.
Further readings:
http://www.jashaw.com/pid/tutorial/
Next part: DC motor control and final complete code (Version 1)