[ODE] Servo to reach a target position
Royce3
royce3 at ev1.net
Thu Apr 10 11:58:02 2003
>I'm be interested! Not so much for ODE, but because I tried to write one
>for an unrelated project and got nowhere. Ended up coming up with
>something that does work well, and fits what I thought PID meant, but
>actually looks nothing like what a later learned PID was. :-)
Here's the code, tho I haven't had a chance to test it very extensively.
Be wary the I calculation may be wrong, but it works for me :)
Also remember, 95% of applications only need P, and 99% only need P and D.
// pid.h
#ifndef PID_H
#define PID_H
#include <math.h>
class PID
{
// Kp = Proportional gain
// Ki = Integral gain
// Kd = Derivative gain
// Isum = accumulated error for I-term
// E = saved Error from previous calculation
// MaxE = maximum error signal seen
// dT1 = saved dT from previous calculation
// OV = Output Variable
float Kp, Ki, Kd, Isum, E, MaxE, dT1, OV;
public:
PID ( float Kp_=0, float Ki_=0, float Kd_=0 )
{
Reset();
SetGain ( Kp_, Ki_, Kd_ );
}
void Reset()
{
Isum = 0;
E = 0;
dT1 = 0;
MaxE = 0;
OV = 0;
}
void SetGain ( float Kp_, float Ki_=0, float Kd_=0 )
{
Kp = Kp_;
Ki = Ki_;
Kd = Kd_;
}
// SP = destination/target
// PV = feedback
// dT = time elapsed since last update
// return value = command output
float StepPosition ( float SP, float PV, float dT )
{
float E1 = E; // previous error
E = SP - PV; // new error
float Op=0, Oi=0, Od=0; // P, I, and D terms of calculation
// P-Loop
Op = CalcP ( E );
// I-Loop
Oi = CalcI ( E );
// D-Loop
Od = CalcD ( E, E1 );
// Final Summation
OV = Op + Oi + Od;
dT1 = dT; // save this dT to be previous dT for next time
return OV;
}
// SP = destination/target
// PV = feedback
// dT = time elapsed since last update
// return value = command output
float StepSpeed ( float SP, float PV, float dT )
{
float E1 = E; // previous error
E = SP - PV; // new error
float Op=0, Oi=0, Od=0; // P, I, and D terms of calculation
// P-Loop
Op = CalcP ( E );
// I-Loop
Oi = CalcI ( E );
// D-Loop
Od = CalcD ( E, E1 );
// Final Summation
OV += Op + Oi + Od;
dT1 = dT; // save this dT to be previous dT for next time
return OV;
}
private:
float CalcP ( float E )
{
return E * Kp;
}
float CalcI ( float E )
{
if ( Ki > 0 )
{
Isum += E / 10;
if ( fabs(E) > MaxE )
MaxE = (float)fabs(E);
if ( Isum > MaxE )
Isum = MaxE;
else if ( Isum < -MaxE )
Isum = -MaxE;
return Ki * Isum;
}
else
return 0;
}
float CalcD ( float E, float E1 )
{
if ( Kd > 0 )
{
float dE = E - E1; // change in error
return Kd * E;
}
else
return 0;
}
};
#endif//PID_H
// pidtest.cpp
#include <stdio.h>
#include "../pid.h"
void main()
{
PID pid ( 0.1f );
float position = 0;
for ( int i = 0; i < 50; i++ )
{
position += pid.StepPosition ( 10, position, 0.1f );
printf ( "%.02f ", position );
}
printf ( "\n\nfinal position: %.02f\n", position );
}
// end of pidtest.cpp