Setting values in the PID library?

I have not been able to find anything that explains how you choose the values for Kp, Ki and Kd for the PID library. If you don't get sensible values to start with you can't even begin to tune the thing.

For example, how should be values be chosen relative to the values of Input, Output and Setpoint.

I have read all the stuff in Brett Beauregard's blog and it explains the theory nicely - but it is very weak on practice - how you actually apply the library to a project.

I think I have a lot of it figured out by trial and error and by adding print commands into the library to watch it working.

But if someone else has written about this I would very much like to read it before going much further.

...R

There are quite a number of PID tuning tutorials on the web.

I start with Kp small (with Kd and Ki zero) and ramp it up until oscillatory response is observed. Then add in Kd, then Ki, while possibly increasing or decreasing Kp as appropriate.

Of course, the signs must be correct in order for this to work, and in the beginning it is very important to use print statements to make sure that corrections are working in the appropriate direction.

My most recent project was a boat autopilot. Because of the viscous damping of the water, Kd and Ki were not needed at all.

jremington:
I start with Kp small (with Kd and Ki zero) and ramp it up until oscillatory response is observed. Then add in Kd, then Ki, while possibly increasing or decreasing Kp as appropriate.

I'm trying to find out what people mean by small. Is it 0.001, 10, or 100, and what determines it.

I will try your suggestion for setting Kd and Ki to 0. Although it seems in my tests that the ITerm (which depends on Ki) is the most important.

...R

When Kp is "small", no, or very slow response will be observed.

Again, it is advisable to look at some input/output values while the system is running. That way you get a feel for the reasonableness of choices.

Also, beware of "clamping", which is usually necessary to prevent out-of-control robots. If Kp is very large for example, the response (e.g. output PWM value) may be clamped to the maximum or minimum.

Parallax has a nice tutorial, but using the Basic Stamp.

I do appreciate that you are trying to help, and perhaps I am not making myself clear.

The tutorial you have linked to seems very similar to others i have read. For example it says

To make comparisons easier, Kp, Ki, and Kd are all set to 10.

and in the Arduino PID basic example they are set to 2, 5 and 1

But nowhere is there an explanation of why those values are chosen.

Maybe another way to ask the question is "what are the upper and lower limits for those values?"

...R

Maybe another way to ask the question is "what are the upper and lower limits for those values?"

It really depends on the nature of the input and output, and the values they take on.

Suppose you want to navigate a course, using a rudder that has -128 = full left (to port), 0 = center and 127 = full right (to starboard, byte values). With a simple compass, 1 degree heading accuracy is expected and usually adequate, so Input will be an integer value between 0 and 359.

Now suppose you are off course by 10 degrees (Setpoint = 60, Input = Heading = 70). A rudder setting of -20 might be appropriate to BEGIN to correct the INITIAL error.

In that case, a starting value of Kp=2 (or -2, depending on how you have chosen the signs) might be a reasonable choice.

Obviously, as the course error decreases, the Output value = rudder setting will decrease, so there is no reason to change Kp once a suitable value has been discovered.

Some thought experiments along these lines should help for your particular problem.

Note: navigation has a special problem because of the 0/360 degree ambiguity. In this case is best to arrange the error term such that Setpoint = 0 degrees = on course.

jremington:
A rudder setting of -20 might be appropriate to BEGIN to correct the INITIAL error.

In that case, a starting value of Kp=2 (or -2, depending on how you have chosen the signs) might be a reasonable choice.

Thanks for the example figures - it makes it easier to discuss. (we can ignore the problem at 360deg)

Am I correct to think that the values for the PID library will be

PID myPID(&compassOutput, &rudderAngle, &desiredDirection, 2, 0, 0, DIRECT);

instead of the basic example's

PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

And if so, do you use 2 because it is 10% of 20?

...R

I suggested to start with Kp=2 as a first guess because for the example given:

Output = Kp*Error

and for Error = 10 we think Output=20 might be appropriate. The sign of Kp must be chosen correctly, of course.

Ignoring the 0/360 ambiguity, this would correspond to:

Input = compass_reading(); //assume 70
Setpoint = desired_heading(); //assume 60
PID(&Input,&Output,&Setpoint,2,0,0,DIRECT);

compute() should deliver Output = 20. If the sign is wrong use REVERSE instead of DIRECT.

Thanks that makes sense.

After more reading and thinking and programming I reckon the PID library is very very poor as a teaching tool. It would be much better IMHO if it was normalized so that the Kp etc values would all be limited to the range 0 to 1 (or 0 to 10) regardless of the real-world values being used. Alternatively the user could be required to present it with input, output and setpoint values within some range.

In my case I am trying to control a small DC motor. I have a sensor to measure the micros per revolution which gives values in the range 30,000 to 9,000. I use my potentiometer to give desired values in the range 40,000 to 8,000. But the "output" required by analogWrite() is in the range 0-255. So my required Kp etc values are about 0.001. NOTHING about the examples suggested I would need values that small.

I still haven't figured the role of time intervals. All the tutorials I have read are about processes where time can be measured with a stopwatch :slight_smile:

Thanks again for your assistance.

...R

Agreed, some published real world examples would be very helpful.

In your case I agree that Kp of 0.001 would be a reasonable place to start, and you could try exploring in powers of ten (i.e. set Kp = 0.0001, 0.001, 0.01 etc) in the initial trials.

HOWEVER, your measurement (microseconds/revolution) is inversely proportional to PWM. It is best for PID if all variables scale linearly, so I suggest to convert microseconds/revolution to RPMs or similar, which would be roughly proportional to PWM.

30,000 microseconds/rev = 33 revs/second
9,000 microseconds/rev = 111 revs/second

So revs/second could be a reasonable measurement, as it would scale to PWM by roughly a factor of 1. Similarly the pot value could be scaled arbitrarily to a target revs/sec value or Setpoint of 0-255 revs/second.

The program I had been working on before I started exploring the PID library is sufficiently close to the concept in the library that it is easier to continue with my own program with my new knowledge. Also my code does not waste CPU cycles on floating point doubles.

And I don't want to waste CPU cycles calculating RPM or RPS when the information is no use to me.

It occurred to me in bed this morning that controlling a motor may be different from your rudder example because a motor needs power (some non-zero PWM value) all the time (whereas a sailor would like to trim his boat so that little or no rudder input is needed). It may be that the PID library does not adequately deal with that - but I won't have time to explore it today. Maybe some part of the output should be proportional to the average RPM.

...R

And I don't want to waste CPU cycles calculating RPM or RPS when the information is no use to me.

PID works much better if the input and output variables are linearly related. In your case they are not.

If you write your own PID calculation (a couple of lines), you can add an offset to the output. In many cases that is required.

jremington:
PID works much better if the input and output variables are linearly related. In your case they are not.

There can't be a linear relationship between the PWM duty cycle and the speed of an electric motor faced with a variable load. In fact my whole purpose for using something like PID is to maintain a constant speed in the face of that non-linear relationship.

On the other hand, perhaps you mean that it would help to scale the input and setpoint values so that they have a similar size to the output value?

If so that is one the things that prompted me to start this Thread - it does not even hint at that in anything I have read about the library. Actually I don't think that is required but I do think the author of the library constructed it to suit that situation - perhaps without realizing that it needs extra explanation if that condition is not met.

...R

I think that if you read a bit about the terms. proportional, integral and derivative it will make more sense.

derivative is used for fast processes, speed, pressure, steering, balance,.....
not needed for slow like temperature or level.

crudely put, proportional is how much the control output changes based on how far from setpoint you are and if you are heading away from setpoint or heading towards it.

integral is very simple.
error = setpoint - process reading
old_error = old_error + error

if old_error >= 1,000 then make a nudge in the controls

if you are off, it will add up fast.
if you are close, it will add slowly
if some readings are positive, some negative (noise around setpoint) then it can take a long time before integral kicks in

first tuning is with 0 integral and 0 derivative. you need to get your proportional to get the process to stabilize.

if you think of a window as your acceptable error. you want 25 degrees.... that is your setpoint
you open your proportional window until there is no action., the reading could be 35 or 50 degrees or 5 or -10 a HUGE window, but stable.

then you change proportional until the process starts to oscillate, then back off.
then start in with your integral.
integral will eventually get you spot on (if your final element, valve, throttle, pump can get you there)

your sensor should be at least 4 to 10 times more sensitive than your desired error.
your final control element should be at least 4 times more sensitive than your desired error.

hysteresis in your final element will drive you nuts.

dave-in-nj:
I think that if you read a bit about the terms. proportional, integral and derivative it will make more sense.
-----SNIP-----
first tuning is with 0 integral and 0 derivative. you need to get your proportional to get the process to stabilize.

I have done a lot of reading and I think I have a reasonable grasp of the concept (as you have described it).

I started this Thread because I could find no advice about how to set the initial values. For example, you say to set Ki and Kd to 0, but you give no guidance about Kp.

your sensor should be at least 4 to 10 times more sensitive than your desired error.
your final control element should be at least 4 times more sensitive than your desired error.

hysteresis in your final element will drive you nuts.

This sounds like it may be interesting but I don't understand what you mean by "your final control element". I have only one sensor and one control (PWM).

Also, I'm not sure how I can relate your "4 to 10 times" to my sensor. It records micros() for every revolution and I can then calculate how long a revolution takes. I have no other measuring device so I do not know what error there may be in my micros()/revolution figure.

The more I study this the more I get the impression that PID is being sold as a magic bullet or black box. No doubt the theory is solid. But like many theories developed in the classroom it can be overkill in the real world. And there needs to be more advice about applying it in practice.

I should get a chance to do more experiments today.

...R

final control element might be a damper or valve. mechanical devices often have horrible hysteresys.
I have used those DIN PID controllers on some dampers and tried the auto-tune, only to have them report that the damper is uncontrollable !

motors and pumps that are controlled by motor speed controllers have ranges.

pretending your pump is linear, output = input.
if your pump goes to 2,560 RPM, your pwm of 256 = 10 RPM per step. if your pump puts out 256 LPM then each step might be 1 LPM.

this means that you cannot control to anything better than +/-1LPM
to have better control. you would want to select a pump or controller that could output to 1/4LPM - 4 times more resolution that your desired control point.

as for measuring, say you want to measure your oven an use a thermocouple.
it measures from 0 to 1000 degrees. your 10 bit ADC will reslove to 1 degrees.
you could not control to any better than +/-1 degree.
you should be able to read much better, from 1/4 a degree to 1/10th of a degree.

when starting out tuning, you first need to know the boundaries of your control.
at one extreme, there is no control and the process runs to whatever balance it has.

for instance, a pump will lift water, with a small lift, it will push a lot of water
with a high lift, almost no water.
as an example, you have a pump that does 200lmp with no lift, but with your lift, it does 97 lpm at full speed.

so, with whatever lift you have, say you want your setpoint to be half. you set proportional so it is swinging wildly at setpoint, every movement is exaggerated and it over-corrects continuously. this should result in a specific frequency that is dependant on the process.

think of it this way, the pump can deliver 100 lpm, you want 50
you set the P for 49.9999 and 50.001
it is not possible, so the control over corrects no matter what.
but, there will be a magnitude and a frequency. both measurable.

you de-tune, that to say, 47 and 53 and the magnitude gets smaller and the frequency of correction lengthens.
you de-tune it more and say at 45/55 it gets to 54 and does not change. you have set the window wider than the controller needs for a correction and the frequency goes to infinity.

a note here is that from this point, 44/56 or 25/75 will act the same way, no attempt to change as you are within the window. you want to tighten up your P so as to find that point where there is instability. note that, then back off slightly.

from that point, you can set your integral and that will look at that 4 lpm offset and just add itself up
0 + 4 = 4
4 + 4 = 8
8 + 4 = 12......
in short order you hit 100 (your integral setting) and nudge it back towards your setpoint.

after the first nudge, the process goes to 53.5
now,
old_error = setpoint (50) - error (53.5)
0 + 3.5 = 3.5
3.5 + 3.5 = 7
it will take longer before the next nudge
and each nudge will take longer and longer as you get closer to your setpoint

once you are near to setpoint, say 50.5, AND you have some noise on your readings.

0 + 0.5 = 0.5
0.5 + 0 = 0.5 // noise has reading at 50 , so there was no error
as you can see, this could take a long time between nudges.

if you over shoot, it will be by a count of 1 as your nudge is just changing your output by a small count.

the, your error will be just under yoursetpoint and close, so the frequency of correction will be very long, but control will be very close to setpoint.

so, your question about where to start is, anywhere. then make changes, double or half, to make an an upset.

response time is dependant on the process being controlled.
air pressure moves at the speed of sound.
temperature moves slightly faster than paint dries.
there are ways to calculate based on the process and the reaction of your final control element, but in the end, you will tweak your numbers based on how the control works.

as for derivative, that only comes into use with highly dynamic processes. pressure, flow, balance, etc.
and as the process becomes so dynamic is is almost unstable, then inverse derivative comes into use.

my background has been HVAC ; pressure, flow and temperature.
an industrial engineer calls HVAC 'casual' engineering where 'close enough' is the goal.
the Segway and other balance devices are like magic in comparison.

dave-in-nj:
so, your question about where to start is, anywhere. then make changes, double or half, to make an an upset.

I really do appreciate that you have given the time to write these two replies.

But it all still sounds very theoretical to me.

I can see the logic behind the piece I have quoted. But I don't think it is sufficient (and please don't think I am making a personal criticism)

For example, if I had started with a Kp of 2.00 I don't know how I might have reached the necessary 0.001 by following that advice. I only got to 0.001 by taking the maths in the code apart and seeing what sort of values it would produce.

And these numbers are clearly very closely related to the time interval between sampling the results and making changes to the power - I haven't figured out how to deal with that yet. The small motor I am trying to control seems to have a response time measured in millisecs and I have no means to measure that. Some of the other PID stuff I have read has also been about HVAC and it seems that time can be measured with a stopwatch.

It may be that the people applying PID in the real world are (consciously or subconsciously) relying on a lot of accumulated experience in their specific field.

I will muddle through to a solution for my project but I have been (am) hoping there might be a paper I could read in which someone bridges the gap between theory and application for different types of project.

Once again thanks for the input, and more will be welcome from you or anyone else who wishes to contribute. It is all helping to grow my knowledge.

...R

You can't really know ahead of time what values you
will need unless you have a mathematical model
of your system.
Kp is usually tuned as stated. You bring the value up until
it over shoots and oscillates.
The problem wit Kp is that there is always some error. If you run
it right below where is oscillates, there will be some measurable
error.
In comes Ki. This looks at the error and slowly advances the
the output until there is no more error. The gain of this has to
be small enough that it doesn't cause overshoot.
Kd is there to react to quick changes. It just does a reaction
to the changes. The problem with it is that it can also react to
noise and quantization noise if digital. Too much usually shows
up as excess jitter. Since it is usually looking at the same sensor
that every thing else is, it is not a perfect control. I did a system
where I knew the needed response to a known change in load.
I knew how much this change would be to the proportional output.
It was a simple matter of subtracting it. This was for a temperature
control system.
With a pulse width to run a motor, if you put an interrupt
on the off cycle and measure the voltage of the motors as a generator,
it is proportional to the RPM. It has some temperature sensitivity
but doesn't require a lot of extra hardware to add to the system.
If you really want to know how to choose the coefficients, get a
college level book for mechanical engineering on control systems.
The modeling can be quite complex. You need to know a lot of
things that may not be in the specs.
If you are using a reduction gear of more than 20 or 40, most of
your inertial load with be the motor and first gears.

dwightthinker:
Kp is usually tuned as stated. You bring the value up until it over shoots and oscillates.

Bring it up from what starting number?
That is my principal question!

In comes Ki. This looks at the error and slowly advances the
the output until there is no more error.

What do you mean by slowly - several millisecs, or several seconds?
And how does the value of Ki interact with the time interval.

With a pulse width to run a motor, if you put an interrupt on the off cycle and measure the voltage of the motors as a generator, it is proportional to the RPM.

That is not adequate for my system. AFAIK it cannot work when analogWrite() is at 255 and I need to count revolutions. I already have an optical sensor to detect the time for each revolution.

...R