Date post: | 07-Jul-2018 |
Category: |
Documents |
Upload: | mauro-antonio |
View: | 218 times |
Download: | 1 times |
of 28
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;