Pid Document 2

Embed Size (px)

Citation preview

  • 8/18/2019 Pid Document 2

    1/28

    The Beginner’s PID

    Here’s the PID equation as everyone first learns it:

    This leads pretty much everyone to write the following PID controller:

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double errSum, lastErr;double kp, ki, kd;void Compute()

      /*!ow long sin"e we last "al"ulated*/

      unsigned long now # millis();

      double timeC$ange # (double)(now % lastTime);

     

    /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  errSum (error * timeC$ange);

      double dErr # (error % lastErr) / timeC$ange;

     

    /*Compute 'I Output*/

      Output # kp * error & ki * errSum & kd * dErr;

     /*emember some variables or ne+t time*/

      lastErr # error;

      lastTime # now;

     

    void SetTunings(double -p, double -i, double -d)

      kp # -p;

      ki # -i;

      kd # -d;

    Compute( is called either regularly or irregularly! and it wor"s pretty well# This series isn’t

    a$out %wor"s pretty well& though# If we’re going to turn this code into something on parwith industrial PID controllers! we’ll have to address a few things:

  • 8/18/2019 Pid Document 2

    2/28

    '# Sample Time - The PID algorithm functions $est if it is evaluated at a regular

    interval# If the algorithm is aware of this interval! we can also simplify some of theinternal math#

    # Derivative Kick - )ot the $iggest deal! $ut easy to get rid of! so we’re going to do

     *ust that#

    +# On-The-Fly Tuning Changes - , good PID algorithm is one where tuning

     parameters can $e changed without *olting the internal wor"ings#

    -# Reset in!up "itigati#n -.e’ll go into what /eset .indup is! and implement a

    solution with side $enefits

    0# On$O%% &'ut#$"anual( - In most applications! there is a desire to sometimes turn

    off the PID controller and ad*ust the output $y hand! without the controllerinterfering

    1# Initiali)ati#n - .hen the controller first turns on! we want a %$umpless transfer#&

    That is! we don’t want the output to suddenly *er" to some new value

    2# C#ntr#ller Directi#n - This last one isn’t a change in the name of ro$ustness per se#

    it’s designed to ensure that the user enters tuning parameters with the correct sign#

    3nce we’ve addressed all these issues! we’ll have a solid PID algorithm# .e’ll also! not

    coincidentally! have the code that’s $eing used in the lastest version of the ,rduino PID

    4i$rary# 5o whether you’re trying to write your own algorithm! or trying to understandwhat’s going on inside the PID li$rary! I hope this helps you out# 4et’s get started#

     )e6t 77

    8PD,T9: In all the code e6amples I’m using dou$les# 3n the ,rduino! a dou$le is the

    same as a float (single precision# True dou$le precision is ., over"ill for PID# If thelanguage you’re using does true dou$le precision! I’d recommend changing all dou$les to

    floats#

    http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-sample-timehttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-sample-timehttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-derivative-kickhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-tuning-changeshttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-reset-winduphttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-onoffhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-initializationhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginners-pid-directionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-sample-timehttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-derivative-kickhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-tuning-changeshttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-reset-winduphttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-onoffhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-initializationhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginners-pid-directionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-sample-timehttp://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/improving-the-beginner%E2%80%99s-pid-sample-time

  • 8/18/2019 Pid Document 2

    3/28

    Impr#ving the Beginner’s PID * Sample Time

    (This is ;odification

  • 8/18/2019 Pid Document 2

    4/28

     

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

     

      double ratio # (double)1ewSampleTime  / (double)SampleTime;

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

    3n lines '@A''! the algorithm now decides for itself if it’s time to calculate# ,lso! $ecause

    we now B)3. that it’s going to $e the same time $etween samples! we don’t need to

    constantly multiply $y time change# .e can merely ad*ust the Bi and Bd appropriately

    (lines +' A + and result is mathematically equivalent! $ut more efficient#

    one little wrin"le with doing it this way though though# if the user decides to change the

    sample time during operation! the Bi and Bd will need to $e re>twea"ed to reflect this new

    change# that’s what lines +>- are all a$out#

    ,lso )ote that I convert the sample time to 5econds on line # 5trictly spea"ing this isn’tnecessary! $ut allows the user to enter Bi and Bd in units of 'sec and s! rather than 'm5

    and m5#

    The Results

    the changes a$ove do + things for us

    '# /egardless of how frequently Compute( is called! the PID algorithm will $e

    evaluated at a regular interval E4ine ''F

    # =ecause of the time su$traction E4ine '@F there will $e no issues when millis(wraps $ac" to @# That only happens every 00 days! $ut we’re going for $ulletproof

    remem$erG

    +# .e don’t need to multiply and divide $y the timechange anymore# 5ince it’s a

    constant we’re a$le to move it from the compute code Elines '0'1F and lump it in

  • 8/18/2019 Pid Document 2

    5/28

    with the tuning constants Elines +'+F# ;athematically it wor"s out the same! $ut it

    saves a multiplication and a division every time the PID is evaluated

    Si!e n#te a+#ut interrupts

    If this PID is going into a microcontroller! a very good argument can $e made for using aninterrupt# 5et5ampleTime sets the interrupt frequency! then Compute gets called when it’stime# There would $e no need! in that case! for lines >'! +! and -# If you plan on doing

    this with your PID implentation! go for it? Beep reading this series though# ou’ll hopefully

    still get some $enefit from the modifications that follow#

    There are three reasons I didn’t use interrupts

    '# ,s far as this series is concerned! not everyone will $e a$le to use interrupts#

    # Things would get tric"y if you wanted it implement many PID controllers at the

    same time#

    +# If I’m honest! it didn’t occur to me# immie /odgers suggested it while proof>

    reading the series for me# I may decide to use interrupts in future versions of thePID li$rary#

    http://jimmieprodgers.com/http://jimmieprodgers.com/http://jimmieprodgers.com/

  • 8/18/2019 Pid Document 2

    6/28

    Improving the Beginner’s PID – Derivative Kick

    (This is ;odification

  • 8/18/2019 Pid Document 2

    7/28

    It turns out that the derivative of the 9rror is equal to negative derivative of Input! 9KC9PT

    when the 5etpoint is changing# This winds up $eing a perfect solution# Instead of adding

    (Bd L derivative of 9rror! we su$tract (Bd L derivative of Input# This is "nown as using

    %Derivative on ;easurement&

     The Code

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double errSum, lastInput;double kp, ki, kd;int SampleTime # .; //. se"void Compute()

      unsigned long now # millis();

      int timeC$ange # (now % lastTime);

      i(timeC$ange0#SampleTime)

     

      /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  errSum error;

      double dInput # (Input % lastInput);

     /*Compute 'I Output*/

      Output # kp * error & ki * errSum % kd * dInput;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now;

     

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

     

  • 8/18/2019 Pid Document 2

    8/28

      double ratio # (double)1ewSampleTime  / (double)SampleTime;

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

    The modifications here are pretty easy# .e’re replacing d9rror with >dInput# Instead of

    remem$ering the last9rror! we now remem$er the lastInput

     The Result

    Here’s what those modifications get us# )otice that the input still loo"s a$out the same# 5o

    we get the same performance! $ut we don’t send out a huge 3utput spi"e every time the5etpoint changes#

    This may or may not $e a $ig deal# It all depends on how sensitive your application is to

    output spi"es# The way I see it though! it doesn’t ta"e any more wor" to do it without

    "ic"ing so why not do things rightG

  • 8/18/2019 Pid Document 2

    9/28

  • 8/18/2019 Pid Document 2

    10/28

    Improving the Beginner’s PID Tuning Changes

    (This is ;odification

  • 8/18/2019 Pid Document 2

    11/28

    This interpretation wor"s fine until the Bi is changed# Then! all of a sudden! you multiply

    this new Bi times the entire error sum that you have accumulated# That’s not what we

    wanted? .e only wanted to affect things moving forward?

     The Solution

    There are a couple ways I "now of to deal with this pro$lem# The method I used in the last

    li$rary was to rescale err5um# Bi dou$ledG Cut err5um in Half# That "eeps the I Term from

     $umping! and it wor"s# It’s "ind of clun"y though! and I’ve come up with something more

    elegant# (There’s no way I’m the first to have thought of this! $ut I did thin" of it on my

    own# That counts damnit?

    The solution requires a little $asic alge$ra (or is it calculusG

    Instead of having the Bi live outside the integral! we $ring it inside# It loo"s li"e we haven’t

    done anything! $ut we’ll see that in practice this ma"es a $ig difference#

     )ow! we ta"e the error and multiply it $y whatever the Bi is at that time# .e then store the

    sum of TH,T# .hen the Bi changes! there’s no $ump $ecause all the old Bi’s are already

    %in the $an"& so to spea"# .e get a smooth transfer with no additional math operations# It

    may ma"e me a gee" $ut I thin" that’s pretty se6y#

     The Code

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double ITerm, lastInput;double kp, ki, kd;int SampleTime # .; //. se"void Compute()

      unsigned long now # millis();

      int timeC$ange # (now % lastTime);

      i(timeC$ange0#SampleTime)

     

      /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  ITerm (ki * error);

      double dInput # (Input % lastInput);

  • 8/18/2019 Pid Document 2

    12/28

     /*Compute 'I Output*/

      Output # kp * error & ITerm % kd * dInput;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now; 

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

     

      double ratio # (double)1ewSampleTime  / (double)SampleTime;

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

    5o we replaced the err5um varia$le with a composite ITerm varia$le E4ine -F# It sums

    BiLerror! rather than *ust error E4ine '0F# ,lso! $ecause Bi is now $uried in ITerm! it’s

    removed from the main PID calculation E4ine 'F#

     The Result

  • 8/18/2019 Pid Document 2

    13/28

    5o how does this fi6 things# =efore when "i was changed! it rescaled the entire sum of theerrorN every error value we had seen# .ith this code! the previous error remains untouched!

    and the new "i only affects things moving forward! which is e6actly what we want#

  • 8/18/2019 Pid Document 2

    14/28

    Improving the Beginner’s PID Reset !indup

    (This is ;odification

  • 8/18/2019 Pid Document 2

    15/28

    There are several ways that windup can $e mitigated! $ut the one that I chose was as

    follows: tell the PID what the output limits are# In the code $elow you’ll see there’s now a

    5et3uput4imits function# 3nce either limit is reached! the pid stops summing (integrating#

    It "nows there’s nothing to $e doneN 5ince the output doesn’t wind>up! we get an immediate

    response when the setpoint drops into a range where we can do something#

     The Solution – Step #

     )otice in the graph a$ove though! that while we got rid that windup lag! we’re not all the

    way there# There’s still a difference $etween what the pid thin"s it’s sending! and what’s

     $eing sent# .hyG the Proportional Term and (to a lesser e6tent the Derivative Term#

    9ven though the Integral Term has $een safely clamped! P and D are still adding their two

    cents! yielding a result higher than the output limit# To my mind this is unaccepta$le# If the

    user calls a function called %5et3utput4imits& they’ve got to assume that that means %the

    output will stay within these values#& 5o for 5tep ! we ma"e that a valid assumption# In

    addition to clamping the I>Term! we clamp the 3utput value so that it stays where we’d

    e6pect it#

    ()ote: ou might as" why we need to clamp $oth# If we’re going to do the output anyway!

    why clamp the Integral separatelyG If all we did was clamp the output! the Integral term

    would go $ac" to growing and growing# Though the output would loo" nice during the step

    up! we’d see that telltale lag on the step down#

  • 8/18/2019 Pid Document 2

    16/28

     The Code

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double ITerm, lastInput;double kp, ki, kd;int SampleTime # .; //. se"double out2in, out2a+;void Compute()

      unsigned long now # millis();

      int timeC$ange # (now % lastTime);

      i(timeC$ange0#SampleTime)

     

      /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  ITerm (ki * error);

      i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;

      double dInput # (Input % lastInput); 

    /*Compute 'I Output*/

      Output # kp * error & ITerm% kd * dInput;

      i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now;

     

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

     

      double ratio # (double)1ewSampleTime

      / (double)SampleTime;  ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

     void SetOutput4imits(double 2in, double 2a+)

      i(2in 0 2a+) return;

  • 8/18/2019 Pid Document 2

    17/28

      out2in # 2in;

      out2a+ # 2a+;

     

    i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     

    i(ITerm0 out2a+) ITerm# out2a+;  else i(ITerm3 out2in) ITerm# out2in;

    , new function was added to allow the user to specify the output limits Elines 0>1+F# ,nd

    these limits are used to clamp $oth the I>Term E'2>'F and the 3utput E+>-F

     The Result

    ,s we can see! windup is eliminated# in addition! the output stays where we want it to# this

    means there’s no need for e6ternal clamping of the output# if you want it to range from +

    to '12! you can set those as the 3utput 4imits#

  • 8/18/2019 Pid Document 2

    18/28

    Improving the Beginner’s PID $n%$& 

    (This is ;odification

  • 8/18/2019 Pid Document 2

    19/28

    The solution to this pro$lem is to have a means to turn the PID off and on# The common

    terms for these states are %;anual& (I will ad*ust the value $y hand and %,utomatic& (the

    PID will automatically ad*ust the output# 4et’s see how this is done in code:

     The Code

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double ITerm, lastInput;double kp, ki, kd;int SampleTime # .; //. se"double out2in, out2a+;bool in5uto # alse;

     6deine 251754

    6deine 57TO25TIC .

     

    void Compute()

      i(8in5uto) return;

      unsigned long now # millis();

      int timeC$ange # (now % lastTime);

      i(timeC$ange0#SampleTime)

     

      /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  ITerm (ki * error);

      i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;

      double dInput # (Input % lastInput);

      /*Compute 'I Output*/  Output # kp * error & ITerm% kd * dInput;

      i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now;

     

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

  • 8/18/2019 Pid Document 2

    20/28

     

      double ratio # (double)1ewSampleTime  / (double)SampleTime;

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

     void SetOutput4imits(double 2in, double 2a+)

      i(2in 0 2a+) return;

      out2in # 2in;

      out2a+ # 2a+;

     

    i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;

     void Set2ode(int 2ode)

      in5uto # (2ode ## 57TO25TIC);

    , fairly simple solution# If you’re not in automatic mode! immediately leave the Compute

    function without ad*usting the 3utput or any internal varia$les#

     The Result

  • 8/18/2019 Pid Document 2

    21/28

    It’s true that you could achieve a similar effect $y *ust not calling Compute from the calling

    routine! $ut this solution "eeps the wor"ings of the PID contained! which is "ind of what

    we need# =y "eeping things internal we can "eep trac" of which mode were in! and more

    importantly it let’s us "now when we change modes# That leads us to the ne6t issueS

  • 8/18/2019 Pid Document 2

    22/28

    Improving the Beginner’s PID Initiali'ation

    (This is ;odification

  • 8/18/2019 Pid Document 2

    23/28

    double ITerm, lastInput;double kp, ki, kd;int SampleTime # .; //. se"double out2in, out2a+;bool in5uto # alse;

     6deine 251754

    6deine 57TO25TIC .

     void Compute()

      i(8in5uto) return;

      unsigned long now # millis();

      int timeC$ange # (now % lastTime);

      i(timeC$ange0#SampleTime)

     

      /*Compute all t$e working error variables*/

      double error # Setpoint % Input;  ITerm (ki * error);

      i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;  double dInput # (Input % lastInput);

     /*Compute 'I Output*/

      Output # kp * error & ITerm% kd * dInput;

      i(Output0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now;

     

     void SetTunings(double -p, double -i, double -d)

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     void SetSampleTime(int 1ewSampleTime)

      i (1ewSampleTime 0 )

     

      double ratio # (double)1ewSampleTime  / (double)SampleTime;

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

     void SetOutput4imits(double 2in, double 2a+)

  • 8/18/2019 Pid Document 2

    24/28

      i(2in 0 2a+) return;

      out2in # 2in;

      out2a+ # 2a+;

     

    i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;

     void Set2ode(int 2ode)

      bool new5uto # (2ode ## 57TO25TIC);

      i(new5uto 99 8in5uto)

      /*we :ust went rom manual to auto*/

      Initialie();

     

      in5uto # new5uto;

     void Initialie()

      lastInput # Input;

      ITerm # Output;

      i(ITerm0 out2a+) ITerm# out2a+;

      else i(ITerm3 out2in) ITerm# out2in;

    .e modified 5et;ode(S to detect the transition from manual to automatic! and we added

    our initialiMation function# It sets ITermJ3utput to ta"e care of the integral term! and

    lastInput J Input to "eep the derivative from spi"ing# The proportional term doesn’t rely on

    any information from the past! so it doesn’t need any initialiMation#

     The Result

  • 8/18/2019 Pid Document 2

    25/28

    .e see from the a$ove graph that proper initialiMation results in a $umpless transfer from

    manual to automatic: e6actly what we were after#

    (pdate !h) not ITerm*+,

    I have $een getting a lot of questions recently as"ing why I don’t set ITermJ@ upon

    intialiMation# ,s an answer! I’d as" you to consider the following scenario: The pid is in

    manual! and the user has set the output to 0@# ,fter a time! the process steadies out to an

    input of 20## The user ma"es the 5etpoint 20# and turns on the pid# .hat should happenG

    I contend that after switching to automatic the output value should stay at 0@# since the P

    and D terms will $e Mero! the only way this will happen is if ITerm is initialiMed to the value

    of 3utput#

    If you are in a situation where you need the output to initialiMe to Mero! there is no need alter 

    the code a$ove# ust set 3utputJ@ in your calling routine $efore turning the PID from

    ;anual to ,utomatic#

  • 8/18/2019 Pid Document 2

    26/28

    Improving the Beginner’s PID Direction

    (This is the last modification in a larger series on writing a solid PID algorithm

     The Problem

    The processes the PID will $e connected to fall into two groups: direct acting and reverseacting# ,ll the e6amples I’ve shown so far have $een direct acting# That is! an increase in

    the output causes an increase in the input# Oor reverse acting processes the opposite is true#

    In a refrigerator for e6ample! an increase in cooling causes the temperature to go down# To

    ma"e the $eginner PID wor" with a reverse process! the signs of "p! "i! and "d all must $e

    negative#

    This isn’t a pro$lem per se! $ut the user must choose the correct sign! and ma"e sure that all

    the parameters have the same sign#

     The Solution

    To ma"e the process a little simpler! I require that "p! "i! and "d all $e 7J@# If the user is

    connected to a reverse process! they specify that separately using the

    5etControllerDirection function# this ensures that the parameters all have the same sign! and

    hopefully ma"es things more intuitive#

     The Code

    /*working variables*/

    unsigned long lastTime;

    double Input, Output, Setpoint;double ITerm, lastInput;double kp, ki, kd;int SampleTime # .; //. se"double out2in, out2a+;bool in5uto # alse;

     6deine 251754

    6deine 57TO25TIC .

     6deine IECT

    6deine E

  • 8/18/2019 Pid Document 2

    27/28

      ITerm (ki * error);

      i(ITerm 0 out2a+) ITerm# out2a+;

      else i(ITerm 3 out2in) ITerm# out2in;

      double dInput # (Input % lastInput);

     /*Compute 'I Output*/

      Output # kp * error & ITerm% kd * dInput;

      i(Output 0 out2a+) Output # out2a+;

      else i(Output 3 out2in) Output # out2in;

     /*emember some variables or ne+t time*/

      lastInput # Input;

      lastTime # now;

     

     void SetTunings(double -p, double -i, double -d)

      i (-p3 == -i3== -d3) return;

      double SampleTimeInSe" # ((double)SampleTime)/.;  kp # -p;

      ki # -i * SampleTimeInSe";

      kd # -d / SampleTimeInSe";

     i("ontrollerire"tion ##E

  • 8/18/2019 Pid Document 2

    28/28

      else i(ITerm 3 out2in) ITerm# out2in;

     void Set2ode(int 2ode)

      bool new5uto # (2ode ## 57TO25TIC);

      i(new5uto ## 8in5uto)

      /*we :ust went rom manual to auto*/

      Initialie();

     

      in5uto # new5uto;

     void Initialie()

      lastInput # Input;

      ITerm # Output;

      i(ITerm 0 out2a+) ITerm# out2a+;

      else i(ITerm 3 out2in) ITerm# out2in;

     void SetControllerire"tion(int ire"tion)

      "ontrollerire"tion # ire"tion;