PI controller algorithm

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

Reply to
cerr
Loading thread data ...

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%).

Reply to
cerr

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

Reply to
D Yuniskis

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:

formatting link

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
Reply to
Tim Wescott

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!

Reply to
cerr

d
e
e
l
-
e

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

Reply to
cerr

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.

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]

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 (?)

Reply to
D Yuniskis

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!

Reply to
cerr

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!

Reply to
Bruce Varley

......

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.

....

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
 Timing Diagram Font
  GNU H8 - compiler & Renesas H8/H8S/H8 Tiny
 For those web sites you hate
Reply to
Paul

-- ----

Well, I'll use above PI controller for now, built it into my software but can't test it yet as i don't have the hardware available yet... any one know of a free controller tune application where i an enter my possible values and maybe even let it run with my code...?

Thanks, Ron

Reply to
cerr

d

Well, I have a software low passfilter after I read thwe adc and i let it swing it on bootup, meaning i loop 20 * FILTER in order to get a valid value, I determined that 20x is a pretty good value to get a decent start value with a filter like this: MyVal =3D (MyVal * FILTER + ADCVal) / (FILTER + 1) and i'm currently using a FILTER value of 10.

Yep, that's actually the plan, in between the LED-on cycles, I'm sampling the ambient brightness which is fed back to the "main-brain" of the system.

Thanks for your contribution too! roN

Reply to
cerr

You have heard of 'Garbage In Garbage Out' If all the readings are due to pointing at a bright light, so reading is out of normal range, your filter will still produce an out of output.

Do you do any the reading is meaningless do NOT process, flag error states.

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
 Timing Diagram Font
  GNU H8 - compiler & Renesas H8/H8S/H8 Tiny
 For those web sites you hate
Reply to
Paul

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.