+ All Categories
Home > Documents > Pid Document

Pid Document

Date post: 07-Jul-2018
Category:
Upload: mauro-antonio
View: 217 times
Download: 0 times
Share this document with a friend

of 29

Transcript
  • 8/18/2019 Pid Document

    1/29

    Improving the Beginner’s PID – Introduction

    In conjunction with the release of the new Arduino PID Library I’ve decided to release this

    series of posts. The last library, while solid, didn’t really come with any code eplanation.

    This time around the plan is to eplain in !reat detail why the code is the way it is. I’mhopin! this will be of use to two !roups of people"

    • People directly interested in what’s !oin! on inside the Arduino PID library will !et

    a detailed eplanation.

    • Anyone writin! their own PID al!orithm can ta#e a loo# at how I did thin!s and

     borrow whatever they li#e.

    It’s !oin! to be a tou!h slo!, but I thin# I found a not$too$painful way to eplain my code.

    I’m !oin! to start with what I call %The &e!inner’s PID.' I’ll then improve it step$by$step

    until we’re left with an efficient, robust pid al!orithm.

    The Beginner’s PID

    (ere’s the PID e)uation as everyone first learns it"

    This leads pretty much everyone to write the followin! 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*/

    http://www.arduino.cc/playground/Code/PIDLibraryhttp://www.arduino.cc/playground/Code/PIDLibrary

  • 8/18/2019 Pid Document

    2/29

      lastErr # error;

      lastTime # now;

     

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

      kp # -p;

      ki # -i;

      kd # -d;

    *ompute+ is called either re!ularly or irre!ularly, and it wor#s pretty well. This series isn’t

    about %wor#s pretty well' thou!h. If we’re !oin! to turn this code into somethin! on par

    with industrial PID controllers, we’ll have to address a few thin!s"

    -. Sample Time - The PID al!orithm functions best if it is evaluated at a re!ular

    interval. If the al!orithm is aware of this interval, we can also simplify some of theinternal math.

    . Derivative Kick - /ot the bi!!est deal, but easy to !et rid of, so we’re !oin! to do just that.

    0. On-The-Fl Tuning !hanges - A !ood PID al!orithm is one where tunin!

     parameters can be chan!ed without joltin! the internal wor#in!s.

    1. "eset #indup $itigation -2e’ll !o into what 3eset 2indup is, and implement asolution with side benefits

    4. On%O&& '(uto%$anual) - In most applications, there is a desire to sometimes turn

    off the PID controller and adjust the output by hand, without the controller

    interferin!

    5. Initiali*ation - 2hen the controller first turns on, we want a %bumpless transfer.'That is, we don’t want the output to suddenly jer# to some new value

    6. !ontroller Direction - This last one isn’t a chan!e in the name of robustness per se.

    it’s desi!ned to ensure that the user enters tunin! parameters with the correct si!n.

    7nce we’ve addressed all these issues, we’ll have a solid PID al!orithm. 2e’ll also, notcoincidentally, have the code that’s bein! used in the lastest version of the Arduino PID

    Library. 8o whether you’re tryin! to write your own al!orithm, or tryin! to understand

    what’s !oin! on inside the PID library, I hope this helps you out. Let’s !et started.

     /et 99

    :PDAT;" In all the code eamples I’m usin! doubles. 7n the Arduino, a double is the

    same as a float +sin!le precision. True double precision is 2A< over#ill for PID. If the

    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-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-time

  • 8/18/2019 Pid Document

    3/29

    lan!ua!e you’re usin! does true double precision, I’d recommend chan!in! all doubles to

    floats.

  • 8/18/2019 Pid Document

    4/29

    Improving the Beginner’s PID – Sample Time

    +This is =odification >- in a lar!er series on writin! a solid PID al!orithm

    The Pro+lem

    The &e!inner’s PID is desi!ned to be called irre!ularly. This causes issues"

  • 8/18/2019 Pid Document

    5/29

     

     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;

     

    7n lines -@--, the al!orithm now decides for itself if it’s time to calculate. Also, because

    we now B/72 that it’s !oin! to be the same time between samples, we don’t need to

    constantly multiply by time chan!e. 2e can merely adjust the Bi and Bd appropriately

    +lines 0- 0 and result is mathematically e)uivalent, but more efficient.

    one little wrin#le with doin! it this way thou!h thou!h. if the user decides to chan!e the

    sample time durin! operation, the Bi and Bd will need to be re$twea#ed to reflect this new

    chan!e. that’s what lines 0C$1 are all about.

    Also /ote that I convert the sample time to 8econds on line C. 8trictly spea#in! this isn’tnecessary, but allows the user to enter Bi and Bd in units of -sec and s, rather than -m8

    and m8.

    The "esults

    the chan!es above do 0 thin!s for us

    -. 3e!ardless of how fre)uently *ompute+ is called, the PID al!orithm will be

    evaluated at a re!ular interval ELine --F

    . &ecause of the time subtraction ELine -@F there will be no issues when millis+wraps bac# to @. That only happens every 44 days, but we’re !oin! for bulletproof

    rememberG

    0. 2e don’t need to multiply and divide by the timechan!e anymore. 8ince it’s a

    constant we’re able to move it from the compute code Elines -4H-5F and lump it in

  • 8/18/2019 Pid Document

    6/29

    with the tunin! constants Elines 0-H0F. =athematically it wor#s out the same, but it

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

    Side note a+out interrupts

    If this PID is !oin! into a microcontroller, a very !ood ar!ument can be made for usin! aninterrupt. 8et8ampleTime sets the interrupt fre)uency, then *ompute !ets called when it’stime. There would be no need, in that case, for lines C$-, 0, and 1. If you plan on doin!

    this with your PID implentation, !o for it? Beep readin! this series thou!h.

  • 8/18/2019 Pid Document

    7/29

    Improving the Beginner’s PID – Derivative Kick

    +This is =odification > in a lar!er series on writin! a solid PID al!orithm

     The Problem

    This modification is !oin! to twea# the derivative term a bit. The !oal is to eliminate a phenomenon #nown as %Derivative Bic#'.

    The ima!e above illustrates the problem. 8ince errorJ8etpoint$Input, any chan!e in

    8etpoint causes an instantaneous chan!e in error. The derivative of this chan!e is infinity

    +in practice, since dt isn’t @ it just winds up bein! a really bi! number. This number !ets

    fed into the pid e)uation, which results in an undesirable spi#e in the output. Luc#ily there

    is an easy way to !et rid of this.

     The Solution

    http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-derivative-kick/improving-the-beginners-pid-introduction

  • 8/18/2019 Pid Document

    8/29

    It turns out that the derivative of the ;rror is e)ual to ne!ative derivative of Input, ;K*;PT

    when the 8etpoint is chan!in!. This winds up bein! a perfect solution. Instead of addin!

    +Bd derivative of ;rror, we subtract +Bd derivative of Input. This is #nown as usin!

    %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

    9/29

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

      ki *# ratio;

      kd /# ratio;

      SampleTime # (unsigned long)1ewSampleTime;

     

    The modifications here are pretty easy. 2e’re replacin! Hd;rror with $dInput. Instead of

    rememberin! the last;rror, we now remember the lastInput

     The Result

    (ere’s what those modifications !et us. /otice that the input still loo#s about the same. 8o

    we !et the same performance, but we don’t send out a hu!e 7utput spi#e every time the8etpoint chan!es.

    This may or may not be a bi! deal. It all depends on how sensitive your application is to

    output spi#es. The way I see it thou!h, it doesn’t ta#e any more wor# to do it without

    #ic#in! so why not do thin!s ri!htG

  • 8/18/2019 Pid Document

    10/29

  • 8/18/2019 Pid Document

    11/29

    Improving the Beginner’s PID Tuning Changes

    +This is =odification >0 in a lar!er series on writin! a solid PID al!orithm

     The Problem

    The ability to chan!e tunin! parameters while the system is runnin! is a must for anyrespectable PID al!orithm.

    The &e!inner’s PID acts a little craMy if you try to chan!e the tunin!s while it’s runnin!.

    Let’s see why. (ere is the state of the be!inner’s PID before and after the parameter chan!e

    above"

    8o we can immediately blame this bump on the Inte!ral Term +or %I Term'. It’s the only

    thin! that chan!es drastically when the parameters chan!e. 2hy did this happenG It has to

    do with the be!inner’s interpretation of the Inte!ral"

    http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-tuning-changes/improving-the-beginners-pid-introduction

  • 8/18/2019 Pid Document

    12/29

    This interpretation wor#s fine until the Bi is chan!ed. 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? 2e only wanted to affect thin!s movin! forward?

     The Solution

    There are a couple ways I #now of to deal with this problem. The method I used in the last

    library was to rescale err8um. Bi doubledG *ut err8um in (alf. That #eeps the I Term from

     bumpin!, and it wor#s. It’s #ind of clun#y thou!h, and I’ve come up with somethin! more

    ele!ant. +There’s no way I’m the first to have thou!ht of this, but I did thin# of it on my

    own. That counts damnit?

    The solution re)uires a little basic al!ebra +or is it calculusG

    Instead of havin! the Bi live outside the inte!ral, we brin! it inside. It loo#s li#e we haven’t

    done anythin!, but we’ll see that in practice this ma#es a bi! difference.

     /ow, we ta#e the error and multiply it by whatever the Bi is at that time. 2e then store the

    sum of T(AT. 2hen the Bi chan!es, there’s no bump because all the old Bi’s are already

    %in the ban#' so to spea#. 2e !et a smooth transfer with no additional math operations. It

    may ma#e me a !ee# but I thin# that’s pretty sey.

     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

    13/29

     /*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;

     

    8o we replaced the err8um variable with a composite ITerm variable ELine 1F. It sums

    Bierror, rather than just error ELine -4F. Also, because Bi is now buried in ITerm, it’s

    removed from the main PID calculation ELine -CF.

     The Result

  • 8/18/2019 Pid Document

    14/29

    8o how does this fi thin!s. &efore when #i was chan!ed, it rescaled the entire sum of theerrorN every error value we had seen. 2ith this code, the previous error remains untouched,

    and the new #i only affects thin!s movin! forward, which is eactly what we want.

  • 8/18/2019 Pid Document

    15/29

    Improving the Beginner’s PID Reset !indup

    +This is =odification >1 in a lar!er series on writin! a solid PID al!orithm

     The Problem

    3eset windup is a trap that probably claims more be!inners than any other. It occurs when

    the PID thin#s it can do somethin! that it can’t. Oor eample, the P2= output on an

    Arduino accepts values from @$44. &y default the PID doesn’t #now this. If it thin#s that0@@$1@@$4@@ will wor#, it’s !oin! to try those values epectin! to !et what it needs. 8ince

    in reality the value is clamped at 44 it’s just !oin! to #eep tryin! hi!her and hi!her

    numbers without !ettin! anywhere.

    The problem reveals itself in the form of weird la!s. Above we can see that the output !ets

    %wound up' 2A< above the eternal limit. 2hen the setpoint is dropped the output has to

    wind down before !ettin! below that 44$line.

     The Solution – Step "

    http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-reset-windup/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-reset-windup/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-reset-windup/improving-the-beginners-pid-introduction

  • 8/18/2019 Pid Document

    16/29

    There are several ways that windup can be miti!ated, but the one that I chose was as

    follows" tell the PID what the output limits are. In the code below you’ll see there’s now a

    8et7uputLimits function. 7nce either limit is reached, the pid stops summin! +inte!ratin!.

    It #nows there’s nothin! to be doneN 8ince the output doesn’t wind$up, we !et an immediate

    response when the setpoint drops into a ran!e where we can do somethin!.

     The Solution – Step #

     /otice in the !raph above thou!h, that while we !ot rid that windup la!, we’re not all the

    way there. There’s still a difference between what the pid thin#s it’s sendin!, and what’s

     bein! sent. 2hyG the Proportional Term and +to a lesser etent the Derivative Term.

    ;ven thou!h the Inte!ral Term has been safely clamped, P and D are still addin! their two

    cents, yieldin! a result hi!her than the output limit. To my mind this is unacceptable. If the

    user calls a function called %8et7utputLimits' they’ve !ot to assume that that means %the

    output will stay within these values.' 8o for 8tep , we ma#e that a valid assumption. In

    addition to clampin! the I$Term, we clamp the 7utput value so that it stays where we’d

    epect it.

    +/ote"

  • 8/18/2019 Pid Document

    17/29

     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

    18/29

      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;

    A new function was added to allow the user to specify the output limits Elines 4$50F. And

    these limits are used to clamp both the I$Term E-6$-F and the 7utput E0$1F

     The Result

    As we can see, windup is eliminated. in addition, the output stays where we want it to. this

    means there’s no need for eternal clampin! of the output. if you want it to ran!e from 0

    to -56, you can set those as the 7utput Limits.

  • 8/18/2019 Pid Document

    19/29

    Improving the Beginner’s PID $n%$& 

    +This is =odification >4 in a lar!er series on writin! a solid PID al!orithm

     The Problem

    As nice as it is to have a PID controller, sometimes you don’t care what it has to say.

    Let’s say at some point in your pro!ram you want to force the output to a certain value +@for eample you could certainly do this in the callin! routine"

    void loop+

    Q

    *ompute+N

    7utputJ@N

    R

    This way, no matter what the PID says, you just overwrite its value. This is a terrible idea in

     practice however. The PID will become very confused" %I #eep movin! the output, andnothin!’s happenin!? 2hat !ivesG? Let me move it some more.' As a result, when you stop

    over$writin! the output and switch bac# to the PID, you will li#ely !et a hu!e and

    immediate chan!e in the output value.

     The Solution

    http://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-onoff/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-onoff/improving-the-beginners-pid-introductionhttp://brettbeauregard.com/blog/2011/04/improving-the-beginner%E2%80%99s-pid-onoff/improving-the-beginners-pid-introduction

  • 8/18/2019 Pid Document

    20/29

    The solution to this problem is to have a means to turn the PID off and on. The common

    terms for these states are %=anual' +I will adjust the value by hand and %Automatic' +the

    PID will automatically adjust the output. Let’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

    21/29

     

      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);

    A fairly simple solution. If you’re not in automatic mode, immediately leave the *ompute

    function without adjustin! the 7utput or any internal variables.

     The Result

  • 8/18/2019 Pid Document

    22/29

    It’s true that you could achieve a similar effect by just not callin! *ompute from the callin!

    routine, but this solution #eeps the wor#in!s of the PID contained, which is #ind of what

    we need. &y #eepin! thin!s internal we can #eep trac# of which mode were in, and more

    importantly it let’s us #now when we chan!e modes. That leads us to the net issueS

  • 8/18/2019 Pid Document

    23/29

    Improving the Beginner’s PID Initiali'ation

    +This is =odification >5 in a lar!er series on writin! a solid PID al!orithm

     The Problem

    In the last section we implemented the ability to turn the PID off and on. 2e turned it off, but now let’s loo# at what happens when we turn it bac# on"

  • 8/18/2019 Pid Document

    24/29

    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

    25/29

      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;

    2e modified 8et=ode+S to detect the transition from manual to automatic, and we added

    our initialiMation function. It sets ITermJ7utput to ta#e care of the inte!ral term, and

    lastInput J Input to #eep the derivative from spi#in!. 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

    26/29

    2e see from the above !raph that proper initialiMation results in a bumpless transfer from

    manual to automatic" eactly what we were after.

    (pdate !h) not ITerm*+,

    I have been !ettin! a lot of )uestions recently as#in! why I don’t set ITermJ@ upon

    intialiMation. As an answer, I’d as# you to consider the followin! scenario" The pid is in

    manual, and the user has set the output to 4@. After a time, the process steadies out to an

    input of 64.. The user ma#es the 8etpoint 64. and turns on the pid. 2hat should happenG

    I contend that after switchin! to automatic the output value should stay at 4@. since the P

    and D terms will be Mero, the only way this will happen is if ITerm is initialiMed to the value

    of 7utput.

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

    the code above. ust set 7utputJ@ in your callin! routine before turnin! the PID from

    =anual to Automatic.

  • 8/18/2019 Pid Document

    27/29

    Improving the Beginner’s PID Direction

    +This is the last modification in a lar!er series on writin! a solid PID al!orithm

     The Problem

    The processes the PID will be connected to fall into two !roups" direct actin! and reverseactin!. All the eamples I’ve shown so far have been direct actin!. That is, an increase in

    the output causes an increase in the input. Oor reverse actin! processes the opposite is true.

    In a refri!erator for eample, an increase in coolin! causes the temperature to !o down. To

    ma#e the be!inner PID wor# with a reverse process, the si!ns of #p, #i, and #d all must be

    ne!ative.

    This isn’t a problem per se, but the user must choose the correct si!n, and ma#e sure that all

    the parameters have the same si!n.

     The Solution

    To ma#e the process a little simpler, I re)uire that #p, #i, and #d all be 9J@. If the user is

    connected to a reverse process, they specify that separately usin! the

    8et*ontrollerDirection function. this ensures that the parameters all have the same si!n, and

    hopefully ma#es thin!s 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

    28/29

      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

    29/29

      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;

    PID C$-P./T/

    And that about wraps it up. 2e’ve turned %The &e!inner’s PID' into the most robust

    controller I #now how to ma#e at this time. Oor those readers that were loo#in! for a

    detailed eplanation of the PID Library, I hope you !ot what you came for. Oor those of you

    writin! your own PID, I hope you were able to !lean a few ideas that save you some cycles

    down the road.

    Two Oinal /otes"

    "0 I1 something in this series looks 2rong please let me kno20 I ma) havemissed something3 or might 4ust need to be clearer in m) e5planation0/ither 2a) I’d like to kno20

    #0 This is 4ust a basic PID0 There are man) other issues that I intentionall)le1t out in the name o1 simplicit)0 $& the top o1 m) head 1eed 1or2ard3reset tiebacks3 integer math3 di&erent pid 1orms3 using velocit) instead

    o1 position0 I1 there’s interest in having me e5plore these topics pleaselet me kno20


Recommended