EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

PI controller algorithm

Started by cerr April 28, 2011
Hi There,

I need to resolve following problem:
I have an led panel with an opto transistor on it that measures the
light emitted/reflected from the target. I want to control the emitted
light to be equal to a certain setpoint from what the opto transistor
measures. Does that make sense? I'm using an 18F pic to control the
whole circuit and I wanted to come up with a PI if not a PID
controller algorithm that controls my LEDs. I've been reading about
PID controllers but am not 100% sure about some things. So far I've
come up with below code:

#define OFFSET 0
#define P 1
#define I 1
int control_func(int measure, int setpoint)
{
static int intgrl_err=0;
int output;
int curr_err;

//P
curr_err=measure-setpoint;
output=(curr_err*P)+OFFSET;

//I
intgrl_err+=curr_err;
output*=g*I*intgrl_err;

return output;
}

I however am not exactly sure what the g variabl in the I part is. The
documentation i read doesn't outline it... :( Some assistance would be
appreciated.

Thank you very much!
Ron
On Apr 28, 1:32=A0pm, cerr <ron.egg...@gmail.com> wrote:
> Hi There, > > I need to resolve following problem: > I have an led panel with an opto transistor on it that measures the > light emitted/reflected from the target. I want to control the emitted > light to be equal to a certain setpoint from what the opto transistor > measures. Does that make sense? I'm using an 18F pic to control the > whole circuit and I wanted to come up with a PI if not a PID > controller algorithm that controls my LEDs. I've been reading about > PID controllers but am not 100% sure about some things. So far I've > come up with below code: > > #define OFFSET 0 > #define P 1 > #define I 1 > int control_func(int measure, int setpoint) > { > static int intgrl_err=3D0; > int output; > int curr_err; > > //P > curr_err=3Dmeasure-setpoint; > output=3D(curr_err*P)+OFFSET; > > //I > intgrl_err+=3Dcurr_err; > output*=3Dg*I*intgrl_err; > > return output; > > } > > I however am not exactly sure what the g variabl in the I part is. The > documentation i read doesn't outline it... :( Some assistance would be > appreciated. > > Thank you very much! > Ron
Oh for clarification, maybe I should say that the LEDs are driven by PWM and I would like to control the duty cycle which will be a value from 0-50 (50=3D100%).
Hi Ron,

On 4/28/2011 1:32 PM, cerr wrote:
> I need to resolve following problem: > I have an led panel with an opto transistor on it that measures the > light emitted/reflected from the target. I want to control the emitted > light to be equal to a certain setpoint from what the opto transistor > measures. Does that make sense? I'm using an 18F pic to control the > whole circuit and I wanted to come up with a PI if not a PID > controller algorithm that controls my LEDs. I've been reading about > PID controllers but am not 100% sure about some things. So far I've > come up with below code:
The derivative term will most probably not be of any use to you :> In simplistic terms (PI): Error = Value - Setpoint Integrator += Error Output = (Proportional_Gain * Error) + (Integral_Gain * Error) Lather, rinse, repeat. [This is the easiest way, IMO, to view what the loop does. There are other forms for expressing it -- e.g., the "Standard Form" as well as the Laplace transform (useful for mathematical modeling tools)] You typically add an integral term when there is an offset in the "Value" that proportional control won't remove by itself (the integrator accumulates this offset and "nudges" the output accordingly) In *practice*, you often want to impose a deadband on the error signal (i.e., any error having a magnitude of "deadband" or less is treated as having an error of "0"). This can be useful when your control capabilities are too course wrt your measurement capabilities. E.g., you set your PWM to 23% duty cycle and get an error that says "too low"; so, you bump it up to 24% and then get an error that says "too high". If you have provisions for a deadband, you can just set that accordingly and end up with "23%... close enough". Also, depending on what you are controlling and how it is likely to *fail*, you might want to put some anti-windup protection on your integral term to keep "Integrator" from becoming *so* large (positive or negative) that it dominates the loop's performance for an inordinately long time. E.g., imagine using "doubles" for these variables. Now, imagine the detector is obstructed for 10,000 iterations of your control loop. In that case, you are likely to see a big "Error" *and* accumulate it repeatedly -- regardless of what your control is trying to do to compensate for it! When the detector is eventually unobstructed, the "Output" is way out of whack for a long time (until the integrator "clears"). Some implementations clamp the magnitude of the Error signal. Some loops clear the integrator automagically when the sign of the Error changes. Some loops "damp" changes to the setpoint (since a setpoint change looks like a disturbance). Bumpless transfer, etc. You probably also want to apply some limits on the range of "Output" values that you will deliver to the Field (if you haven't already done so in the hardware that is driving the LED, etc.) The task of twiddling the various gains, clamps, etc. that your particular implementation supports is called Tuning. This is where the real work is! :> In your case, I suspect this should be trivial unless you have a poorly regulated power supply, ground bounce or radical changes in target reflectivity, etc. (only you can decide how fast and/or stable the loop needs to be for your environment) Note that all of the above is gross oversimplification -- but should point you in the right direction. And, it assumes you are sampling at a fixed time interval (you can also compensate for variations in sampling). I suspect there is a metric boatload of information about PID controllers on-line. Google is your friend. HTH, --don
On 04/28/2011 01:32 PM, cerr wrote:
> Hi There, > > I need to resolve following problem: > I have an led panel with an opto transistor on it that measures the > light emitted/reflected from the target. I want to control the emitted > light to be equal to a certain setpoint from what the opto transistor > measures. Does that make sense? I'm using an 18F pic to control the > whole circuit and I wanted to come up with a PI if not a PID > controller algorithm that controls my LEDs. I've been reading about > PID controllers but am not 100% sure about some things. So far I've > come up with below code: > > #define OFFSET 0 > #define P 1 > #define I 1 > int control_func(int measure, int setpoint) > { > static int intgrl_err=0; > int output; > int curr_err; > > //P > curr_err=measure-setpoint; > output=(curr_err*P)+OFFSET; > > //I > intgrl_err+=curr_err; > output*=g*I*intgrl_err; > > return output; > } > > I however am not exactly sure what the g variabl in the I part is. The > documentation i read doesn't outline it... :( Some assistance would be > appreciated.
Response to a change in output is going to be picked up on the next sample (I assume), so you really don't need anything other than integral action -- proportional and derivative control are just invitations for Fs/2 oscillation. Normally, if you're not adjusting for sampling rate the overall integrator gain is less than one -- I suspect that's what the 'g' is. It would also be more clear to name your integrator state intgrl_state - it's not really an error. _Multiplying_ your proportional term by the integrator state is _definitely weird_. Read this: http://www.wescottdesign.com/articles/Sampling/pidwophd.html then merge what you learned with this (decorations left as an exercise to the reader). int control_func(int measure, int setpoint) { static int int_state; int output; int_state -= (measure - setpoint); // Some code to check for integrator overflow would be a Good // Idea here output = int_state >> INT_SHIFT; return output; } -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
On Apr 28, 2:35=A0pm, Tim Wescott <t...@seemywebsite.com> wrote:
> On 04/28/2011 01:32 PM, cerr wrote: > > > > > > > > > > > Hi There, > > > I need to resolve following problem: > > I have an led panel with an opto transistor on it that measures the > > light emitted/reflected from the target. I want to control the emitted > > light to be equal to a certain setpoint from what the opto transistor > > measures. Does that make sense? I'm using an 18F pic to control the > > whole circuit and I wanted to come up with a PI if not a PID > > controller algorithm that controls my LEDs. I've been reading about > > PID controllers but am not 100% sure about some things. So far I've > > come up with below code: > > > #define OFFSET 0 > > #define P 1 > > #define I 1 > > int control_func(int measure, int setpoint) > > { > > static int intgrl_err=3D0; > > int output; > > int curr_err; > > > //P > > curr_err=3Dmeasure-setpoint; > > output=3D(curr_err*P)+OFFSET; > > > //I > > intgrl_err+=3Dcurr_err; > > output*=3Dg*I*intgrl_err; > > > return output; > > } > > > I however am not exactly sure what the g variabl in the I part is. The > > documentation i read doesn't outline it... :( Some assistance would be > > appreciated. > > Response to a change in output is going to be picked up on the next > sample (I assume), so you really don't need anything other than integral > action -- proportional and derivative control are just invitations for > Fs/2 oscillation. > > Normally, if you're not adjusting for sampling rate the overall > integrator gain is less than one -- I suspect that's what the 'g' is. > It would also be more clear to name your integrator state intgrl_state - > it's not really an error. =A0_Multiplying_ your proportional term by the > integrator state is _definitely weird_. > > Read this:http://www.wescottdesign.com/articles/Sampling/pidwophd.html > > then merge what you learned with this (decorations left as an exercise > to the reader). > > int control_func(int measure, int setpoint) > { > =A0 =A0static int int_state; > =A0 =A0int output; > > =A0 =A0int_state -=3D (measure - setpoint); > > =A0 =A0// Some code to check for integrator overflow would be a Good > =A0 =A0// Idea here > > =A0 =A0output =3D int_state >> INT_SHIFT; > > =A0 =A0return output; > > } > > -- > > Tim Wescott > Wescott Design Serviceshttp://www.wescottdesign.com > > Do you need to implement control loops in software? > "Applied Control Theory for Embedded Systems" was written for you. > See details athttp://www.wescottdesign.com/actfes/actfes.html
Thank you both D & Tim for your contributions! I have been reading the whole morning and will keep doing it for the rest of today I assume... What I learned so far is, I don't need the D part and neither do I need to I part. And just as a little clarification, my pwm that activates the LEDs is having a frequency of 100kHz and will be active for 200-500uS while a "light pulse" is active, that light pulse will come in 50 or 60Hz intervals.... does this make it any more complicated? I might still need the I part as I need to sample the adc (and run through the whole controller logic) while the led is on which would directly interfer with the pwm time being reset, I can't tell right now if the pwm needs to finish it's current cycle before it starts the next one with the new duty cycle tho. I'm using a PIC16F883 - maybe someone here knows...? Thanks for everything! Your help is greatly appreciated!
On Apr 28, 2:58=A0pm, cerr <ron.egg...@gmail.com> wrote:
> On Apr 28, 2:35=A0pm, Tim Wescott <t...@seemywebsite.com> wrote: > > > > > > > > > > > On 04/28/2011 01:32 PM, cerr wrote: > > > > Hi There, > > > > I need to resolve following problem: > > > I have an led panel with an opto transistor on it that measures the > > > light emitted/reflected from the target. I want to control the emitte=
d
> > > light to be equal to a certain setpoint from what the opto transistor > > > measures. Does that make sense? I'm using an 18F pic to control the > > > whole circuit and I wanted to come up with a PI if not a PID > > > controller algorithm that controls my LEDs. I've been reading about > > > PID controllers but am not 100% sure about some things. So far I've > > > come up with below code: > > > > #define OFFSET 0 > > > #define P 1 > > > #define I 1 > > > int control_func(int measure, int setpoint) > > > { > > > static int intgrl_err=3D0; > > > int output; > > > int curr_err; > > > > //P > > > curr_err=3Dmeasure-setpoint; > > > output=3D(curr_err*P)+OFFSET; > > > > //I > > > intgrl_err+=3Dcurr_err; > > > output*=3Dg*I*intgrl_err; > > > > return output; > > > } > > > > I however am not exactly sure what the g variabl in the I part is. Th=
e
> > > documentation i read doesn't outline it... :( Some assistance would b=
e
> > > appreciated. > > > Response to a change in output is going to be picked up on the next > > sample (I assume), so you really don't need anything other than integra=
l
> > action -- proportional and derivative control are just invitations for > > Fs/2 oscillation. > > > Normally, if you're not adjusting for sampling rate the overall > > integrator gain is less than one -- I suspect that's what the 'g' is. > > It would also be more clear to name your integrator state intgrl_state =
-
> > it's not really an error. =A0_Multiplying_ your proportional term by th=
e
> > integrator state is _definitely weird_. > > > Read this:http://www.wescottdesign.com/articles/Sampling/pidwophd.html > > > then merge what you learned with this (decorations left as an exercise > > to the reader). > > > int control_func(int measure, int setpoint) > > { > > =A0 =A0static int int_state; > > =A0 =A0int output; > > > =A0 =A0int_state -=3D (measure - setpoint); > > > =A0 =A0// Some code to check for integrator overflow would be a Good > > =A0 =A0// Idea here > > > =A0 =A0output =3D int_state >> INT_SHIFT; > > > =A0 =A0return output; > > > } > > > -- > > > Tim Wescott > > Wescott Design Serviceshttp://www.wescottdesign.com > > > Do you need to implement control loops in software? > > "Applied Control Theory for Embedded Systems" was written for you. > > See details athttp://www.wescottdesign.com/actfes/actfes.html > > Thank you both D & Tim for your contributions! > I have been reading the whole morning and will keep doing it for the > rest of today I assume... What I learned so far is, I don't need the D > part and neither do I need to I part. And just as a little > clarification, my pwm that activates the LEDs is having a frequency of > 100kHz and will be active for 200-500uS while a "light pulse" is > active, that light pulse will come in 50 or 60Hz intervals.... does > this make it any more complicated? I might still need the I part as I > need to sample the adc (and run through the whole controller logic) > while the led is on which would directly interfer with the pwm time > being reset, I can't tell right now if the pwm needs to finish it's > current cycle before it starts the next one with the new duty cycle > tho. I'm using a PIC16F883 - maybe someone here knows...? > > Thanks for everything! Your help is greatly appreciated!
Otherwise, I'd see it making sense if I buffered the controller output and maybe average it during each Frequency pwm cycle(200-500uSec) and once thas's done, apply the new pwm value to be used when the next pulse comes around...
Hi Ron,

On 4/28/2011 2:58 PM, cerr wrote:
> I have been reading the whole morning and will keep doing it for the > rest of today I assume... What I learned so far is, I don't need the D
The Derivative term allows your controller to *anticipate* (in a sense) the response of the system being controlled. It is useful when you have lots of lag in your measurement+control+system. In your case (as I understand it) you are just looking at a reflection and tweaking the "illumination" to achieve some desired result.
> part and neither do I need to I part. And just as a little > clarification, my pwm that activates the LEDs is having a frequency of > 100kHz and will be active for 200-500uS while a "light pulse" is > active, that light pulse will come in 50 or 60Hz intervals.... does > this make it any more complicated?
You have to look at the timing relationship between your "PWM drive" and your measurement -- along with the response characteristics of the emitter and detector. E.g., if your emitter and detector are *ideal*, then when the emitter is off, you will see "darkness" (nothing reflected because the light is already *gone*). So, if you are sampling the detector "instantaneously* (no averaging or integration), then sampling when the emitter is *on* will give you different signals than when it is *off*. If the timing of your sampling varies relative to the drive of the emitter, then you will see apparent variations in the measured signal that really aren't present in the *actual* signal (sometimes it's on, sometimes it's off, etc.) [I can't say what is right for you as I don't understand the actual application you are facing]
> I might still need the I part as I > need to sample the adc (and run through the whole controller logic) > while the led is on which would directly interfer with the pwm time > being reset, I can't tell right now if the pwm needs to finish it's > current cycle before it starts the next one with the new duty cycle > tho. I'm using a PIC16F883 - maybe someone here knows...?
A "P only" controller, IMO, is harder to tune than an "I only" controller. If you really only want to have *one* term to tweak, then I vote for I (assuming your system can handle the response times consequential to this). If you have "enough headroom" in the integrator, then you can have a painfully low integral gain and still -- eventually -- get the system to be stable (assuming you can tolerate the response time *and* that your system doesn't change "too fast") I'm not sure I understand your comments re: the PWM, here. But, then again, I have already confessed my ignorance of your application! :> In a purely generic sense, I would design: - a measurement system that samples the detector "whenever it *should*" - a drive system that runs the PWM at a particular duty cycle and rate - a control system that straddles the two of these -- taking data from the measurement system and "operating parameters" (setpoint, etc.) from "somewhere" (the user?), computing the required "drive" (Output) for the current state reported by the measurement system, and then passing a new "command" to the drive system to effect the changes required to get the system where you want it. My read of your comments suggested that you were trying to control each individual PWM cycle by instantaneously observing the detector's signal (?)
> Thanks for everything! Your help is greatly appreciated!
> Read this:http://www.wescottdesign.com/articles/Sampling/pidwophd.html
This article is really helpful and for sure the best of all I read today (and that was quite a few). Thank you for that, I rewrote the code and came up with below which should look better than what I had before: typedef struct { signed float iState; float iMax, iMin; float iGain, pGain; }SPid; SPid CntrlData; CntrlData.iGain=1; CntrlData.pGain=1; CntrlData.iMax=50; CntrlData.iMin=0; signed int8 error=0; int8 target=150; error = adcval() - target; //adcval() will return 8bit value CntrlLEDs(&CntrlData, error); //----------------------------------------------------------------------------- signed float CntrlLEDs(Spid *pid, signed int8 error) { signed float pTerm,iTerm; /** P **/ pTerm = pid->pGain * error; /** I **/ pid->iState += error; if (pid->iState > pid->iMax) pid->iState=pid->iMax; else if (pid->iState < pid->iMin) pid->iState=pid->iMin; iTerm = pid->iGain * pid->iState; return pTerm+iTerm; } Thanks again for your help and your article sure is a keeper!
<snip>
Thank you both D & Tim for your contributions!
I have been reading the whole morning and will keep doing it for the
rest of today I assume... What I learned so far is, I don't need the D
part and neither do I need to I part.

** It's the D & P you don't need.

And just as a little clarification, my pwm that activates the LEDs is having 
a frequency of
100kHz and will be active for 200-500uS while a "light pulse" is
active, that light pulse will come in 50 or 60Hz intervals.... does
this make it any more complicated? I might still need the I part as I
need to sample the adc (and run through the whole controller logic)
while the led is on which would directly interfer with the pwm time
being reset, I can't tell right now if the pwm needs to finish it's
current cycle before it starts the next one with the new duty cycle
tho. I'm using a PIC16F883 - maybe someone here knows...?

Thanks for everything! Your help is greatly appreciated! 


In article <ipclva$qq2$1@speranza.aioe.org>, not.going.to.be@seen.com 
says...
> > Hi Ron, > > On 4/28/2011 1:32 PM, cerr wrote: > > I need to resolve following problem: > > I have an led panel with an opto transistor on it that measures the > > light emitted/reflected from the target. I want to control the emitted > > light to be equal to a certain setpoint from what the opto transistor > > measures. Does that make sense? I'm using an 18F pic to control the > > whole circuit and I wanted to come up with a PI if not a PID > > controller algorithm that controls my LEDs. I've been reading about > > PID controllers but am not 100% sure about some things. So far I've > > come up with below code:
......
> Also, depending on what you are controlling and how it is likely > to *fail*, you might want to put some anti-windup protection on > your integral term to keep "Integrator" from becoming *so* > large (positive or negative) that it dominates the loop's > performance for an inordinately long time. E.g., imagine using > "doubles" for these variables. Now, imagine the detector is > obstructed for 10,000 iterations of your control loop. In > that case, you are likely to see a big "Error" *and* accumulate > it repeatedly -- regardless of what your control is trying to > do to compensate for it! When the detector is eventually > unobstructed, the "Output" is way out of whack for a long > time (until the integrator "clears").
As a general rule for any electronics or algorithm (software or hardware) that is measuring light level from photodetectors to imaging sensors should alwasy cope with the error conditions first of a) The output is always minimum (obstruction/lens cap) b) The output is always maximum (pointed at sun or bright light) c) The output of the sensor is disconnected, or failed. At start up I always ignore at least the FIRST two samples to determine what the ambient condition is. In your case I would also every once in a while do a detection cycle with the emitter OFF to get an ambient condition. This is not used in control loop but tests the sensor is working if ambient is not min or max. Then with emmitter ON your error must be at least a minimum away from ambient for operations to be useable. If you sampling regime is 50 or 60 Hz you should be able to fit a test sample inbetween sampling times without effecting the sampling times without affecting the sampling loop.
> Some implementations clamp the magnitude of the Error signal. > > Some loops clear the integrator automagically when the sign > of the Error changes. > > Some loops "damp" changes to the setpoint (since a setpoint > change looks like a disturbance). Bumpless transfer, etc.
.... -- Paul Carpenter | paul@pcserviceselectronics.co.uk <http://www.pcserviceselectronics.co.uk/> PC Services <http://www.pcserviceselectronics.co.uk/fonts/> Timing Diagram Font <http://www.gnuh8.org.uk/> GNU H8 - compiler & Renesas H8/H8S/H8 Tiny <http://www.badweb.org.uk/> For those web sites you hate

The 2024 Embedded Online Conference