59 lines
1.9 KiB
C++
59 lines
1.9 KiB
C++
#include "pid.h"
|
|
|
|
PIDController::PIDController(float P, float I, float D, float ramp, float limit)
|
|
: P(P)
|
|
, I(I)
|
|
, D(D)
|
|
, output_ramp(ramp) // output derivative limit [volts/second]
|
|
, limit(limit) // output supply limit [volts]
|
|
, error_prev(0.0f)
|
|
, output_prev(0.0f)
|
|
, integral_prev(0.0f)
|
|
{
|
|
timestamp_prev = _micros();
|
|
}
|
|
|
|
// PID controller function
|
|
float PIDController::operator() (float error){
|
|
// calculate the time from the last call
|
|
unsigned long timestamp_now = _micros();
|
|
float Ts = (timestamp_now - timestamp_prev) * 1e-6f;
|
|
// quick fix for strange cases (micros overflow)
|
|
if(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;
|
|
|
|
// u(s) = (P + I/s + Ds)e(s)
|
|
// Discrete implementations
|
|
// proportional part
|
|
// u_p = P *e(k)
|
|
float proportional = P * error;
|
|
// Tustin transform of the integral part
|
|
// u_ik = u_ik_1 + I*Ts/2*(ek + ek_1)
|
|
float integral = integral_prev + I*Ts*0.5f*(error + error_prev);
|
|
// antiwindup - limit the output
|
|
integral = _constrain(integral, -limit, limit);
|
|
// Discrete derivation
|
|
// u_dk = D(ek - ek_1)/Ts
|
|
float derivative = D*(error - error_prev)/Ts;
|
|
|
|
// sum all the components
|
|
float output = proportional + integral + derivative;
|
|
// antiwindup - limit the output variable
|
|
output = _constrain(output, -limit, limit);
|
|
|
|
// if output ramp defined
|
|
if(output_ramp > 0){
|
|
// limit the acceleration by ramping the output
|
|
float output_rate = (output - output_prev)/Ts;
|
|
if (output_rate > output_ramp)
|
|
output = output_prev + output_ramp*Ts;
|
|
else if (output_rate < -output_ramp)
|
|
output = output_prev - output_ramp*Ts;
|
|
}
|
|
// saving for the next pass
|
|
integral_prev = integral;
|
|
output_prev = output;
|
|
error_prev = error;
|
|
timestamp_prev = timestamp_now;
|
|
return output;
|
|
}
|