Jump to content
  • Advertisement
Sign in to follow this  
Alessandro

proportional-integral-derivative controller (PID controller) help

This topic is 4399 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement
Oh those are fun!
I use them a lot in my games...
spaceship thruster controls and whatnot


heres mine:
class pidcontroller{
float integral;
float lasterror;
float P,I,D;
public:
pidcontroller(float p,float i, float d){
P=p;I=i;D=d;
integral=0;
lasterror=0;
}
float checkpid(float input,float setpoint){
float error=setpoint-input;
integral+=error;
float derivative=error-lasterror;
lasterror=error;
//printf("e%f i%f d%f\n",error,integral,derivative);
return ((P*error)+(I*integral)+(D*derivative));
}
};


so with mine, i have it contained as a class.
and the P,I and D parameters are inputted in the constructor
then the Setpoint is stored externally by your program (it changes a lot so i dont bother having it be inside the PID itself)
so every gameloop i call checkpid, sending it the Input and the Setpoint, and it returns a float for me to use in the game

actually calculating good P,I, and D values is something you need to do yourself of course... I just tweak them by hand

Share this post


Link to post
Share on other sites
Thank you very much for your help ! I bet finding the most accurate P,I and D values must be quite time-consuming, right ?
What i need is to use a PID controller to command aircraft elevators so that altitude is mantained say at 10,000 feet.
What P,I,D values could i use just to start experimenting ?
Thanks again.

Share this post


Link to post
Share on other sites
Quote:
Original post by Alessandro
Thank you very much for your help ! I bet finding the most accurate P,I and D values must be quite time-consuming, right ?
What i need is to use a PID controller to command aircraft elevators so that altitude is mantained say at 10,000 feet.
What P,I,D values could i use just to start experimenting ?
Thanks again.


be careful here: a PID, while not limited to, is designed mostly for second order systems, and i quite doubt a transferfunction from rudders to height is anything like second order.

Share this post


Link to post
Share on other sites
Just for comparison, here is my PID controller class:


class PIDController
{
public:

/// Constructor
PIDController( float kp, float ki, float kd );

/// Updates the controller.
void Update( float sv, float pv, float dt );

/// Returns the current control value.
float GetControlValue() const { return m_ControlValue; }

private:

float m_ControlValue;
float m_P;
float m_I;
float m_D;
float m_E0, m_E1, m_E2;
};

/// @param kp P parameter.
/// @param ki I parameter.
/// @param kd D parameter.
PIDController::PIDController( float kp, float ki, float kd )
: m_P( kp ), m_I( ki ), m_D( kd )
{
m_E0 = 0.f;
m_E1 = 0.f;
m_E2 = 0.f;
m_ControlValue = 0.f;
}


/// @param sv Set value. This is the target value.
/// @param pv Process value. This is the measured (or current) value.
/// @param dt The time elapsed since the last update.
void PIDController::Update( float sv, float pv, float dt )
{
// If the elapsed time is zero (or less) ignore this update.

if ( dt <= 0.f )
{
return;
}

// Only the last 3 error values are needed.

m_E2 = m_E1;
m_E1 = m_E0;
m_E0 = sv - pv;

float const e01 = m_E0 - m_E1;
float const e12 = m_E1 - m_E2;
float const p = m_P * e01;
float const i = m_I * m_E0 * dt;
float const d = m_D * ( e01 - e12 ) / dt;

m_ControlValue += p + i + d;
}

It is based on the information in this page: sci.engr.* FAQ on PID Controller Tuning

Share this post


Link to post
Share on other sites
*looks at JohnBolton's PID*
*remembers important point*

Alessandro:
My PID is designed under the assumption that it be updated every gameloop, and that the gameloop has a Constant update frequency.
If you are dependant on screen framerate for your game update (that's bad practice BTW) it will mess mine up.

if thats the case, notice how JohnBolton's takes time as an additional argument, so it can compensate for variable timings

Share this post


Link to post
Share on other sites
I have to confess that I had never heard of PID controllers. However, it is fairly clear that this is just a particular subclass of linear filters, where the coefficients of datapoints in the past have all constant weight, except for the current one and the previous (well, I guess you could estimate the derivative using more than two points, but let's ignore that).

Wouldn't it be better for most situations to have some kind of downweighting of things that happened too long ago? In haphazardlynamed's code, that would mean replacing the line
integral+=error;
by
integral = integral*.99 + error;
or something of that style.

Share this post


Link to post
Share on other sites
Yes, some PIDs do that,
another common approach is to just cap the min and max values for Integral to avoid having it oversaturate with time.

I typically have the 'I' parameter as 0 anyway though, since I'm usually using it as a filter for user input vs thruster controls and stuff, where things change a lot and having an Integral parameter that tries to zero it at some constant point is bad...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!