How do I use a PID controller?
Asked Answered
H

3

11

I'm currently working on a temperature controller.

I have a Temperature_PID() function that returns the manipulated variable (which is the sum of the P, I, and D terms) but what do I do with this output?

The temperature is controlled by PWM, so 0% duty cycle = heater off and 100% duty cycle = heater on.

So far I tried

Duty_Cycle += Temperature_PID();
if(Duty_Cycle > 100) Duty_Cycle = 100;
else if(Duty_Cycle < 0) Duty_Cycle = 0;

This didn't work for me because the I term is basically makes this system very unstable. Imagine integrating an area, adding another small data point, and integrating the area again, and summing them. Over and over. That means each data point makes this control scheme exponentially worse.

The other thing I would like to try is

Duty_Cycle = Expected_Duty_Cycle + Temperature_PID();

where Expected_Duty_Cycle is what the temperature should be set to once the controller reaches a stable point and Temperature_PID() is 0. However, this also doesn't work because the Expected_Duty_Cycle would always be changing depending on the conditions of the heater, e.g. different weather.

So my question is what exactly do I do with the output of PID? I don't understand how to assign a duty cycle based on the PID output. Ideally this will stay at 100% duty cycle until the temperature almost reaches the set point and start dropping off to a lower duty cycle. But using my first method (with my I gain set to zero) it only starts lowering the duty cycle after it already overshoots.

Here's my PID function.

double TempCtrl_PID(PID_Data *pid)
{
    Thermo_Data tc;
    double error, pTerm, iTerm, dTerm;

    Thermo_Read(CHIP_TC1, &tc);

    pid->last_pv = pid->pv;
    pid->pv = Thermo_Temperature(&tc);
    error = pid->sp - pid->pv;
    if(error/pid->sp < 0.1)
        pid->err_sum += error;

    pTerm = pid->kp * error;
    iTerm = pid->ki * pid->err_sum;
    dTerm = pid->kd * (pid->last_pv - pid->pv);

    return pTerm + iTerm + dTerm;
}

https://picasaweb.google.com/113881440334423462633/January302013

Sorry, Excel is crashing on me when I try to rename axes or the title. Note: there isn't a fan in the system yet so I can't cool the heater as fast as I can get it to heat up, so it spends very little time below the set point compared to above. The first picture is a simple on-off controller. The second picture is my PD controller. As you can see, it takes a lot longer for the temperature to decrease because it doesn't subtract before the temperature overshoots, it waits until the temperature overshoots before subtracting from the duty cycle, and does so too slowly. How exactly do I tell my controller to lower the duty cycle before it hits the max temperature?

Hilaire answered 30/1, 2013 at 21:27 Comment(11)
Here are some good links: en.wikipedia.org/wiki/PID_controller expertune.com/tutor.aspx library.cmu.edu/ctms/ctms/pid/pid.htmApulia
So the situation is a little more complicated. You need to read up on PID (en.wikipedia.org/wiki/PID_controller). It is a feedback loop control system. What you need to do is change the duty cycle, read the actual temperature (called PV in that wiki article), compute the error to be the difference between target temperature (SP in the wiki article) and the actual, and feed the error back into the PID controller. And note that you can adjust parameters to change behavior of the PV as a function of time (en.wikipedia.org/wiki/File:Change_with_Kp.png).Codpiece
I imagine you're supposed to subtract the output, as the model normally involves negative feedback. That said, it's difficult to say for sure without knowing more details about your system and code.Cecillececily
Can you post your TemperaturePID() function? It sounds like you need to do some tuning of your PID parameters.Cantilever
Thanks Leor! My PID code "works" because a positive error from PID means I need to increase the temperature, which means increasing the duty cycle.Hilaire
Check this out: igor.chudov.com/manuals/Servo-Tuning/PID-without-a-PhD.pdfYukikoyukio
Sorry, not sure how to edit comments. The problem with my PID controller is it doesn't behave how it should. It gets to the temperature set point but very poorly. What's the easiest way to post images to stack overflow?Hilaire
post an image somewhere and link to it. crappy behavior means your parameters are set wrong.Codpiece
I think in this case "crappy behavior" means I don't understand how to assign a duty cycle from the output of the PID controller. What is the proper way to go about doing this? Right now I was just adding and subtracting the PID output directly from the duty cycle, which is obviously wrong.Hilaire
that's where the issue is. it depends on what is implemented in your pid, but the output should actually be the duty cycle.Codpiece
There is an online PID tuner tool at ninja-calc.mbedded.ninja/tool/pid-tuner which can help you learn about PID control and see how changing the P, I and D can affect the system in real-time. Disclaimer: I am the author of this tool.Beebeebe
S
12

The output of the PID is the duty cycle. You must adjust kp, ki, and kd to put the PID output in the range of the Duty_Cycle, e.g., 0 to 100. It is usually a good idea to explicitly limit the output in the PID function itself.

You should "tune" your PID in simple steps.

  1. Turn off the integral and derivative terms (set ki and kd to zero)

  2. Slowly increase your kp until a 10% step change in the setpoint makes the output oscillate

  3. Reduce kp by 30% or so, which should eliminate the oscillations

  4. Set ki to a fraction of kp and adjust to get your desired tradeoff of overshoot versus time to reach setpoint

  5. Hopefully, you will not need kd, but if you do, make it smaller still

Spinthariscope answered 30/1, 2013 at 22:13 Comment(1)
Ohhhh. Okay. Your first sentence explains everything. That makes a lot more sense. Thanks. I set my gains from my PID output to simply be small fractions so I thought if I summed them it would make sense to sum them to get the duty cycle. Guess I messed that up haha.Hilaire
C
4

Your PID controller output should be setting the value of the duty cycle directly.

Basically you are going to be controlling the heater settings based on the difference in the actual temperature versus the temperature setpoint.

You will need to adjust the values of the PID parameters to obtain the performance you are looking for.

First, set I and D to zero and put in a value for P, say 2 to start.

Change the setpoint and see what your response is. Increase P and make another setpoint change and see what happens. Eventually you will see the temperature oscillate consistently and never come to any stable value. This value is known as the "ulitmate gain". Pay attention to the frequency of the oscillation as well. Set P equal to half of the ultimate gain.

Start with a value of 1.2(ultimate gain)/(Oscillation Frequency) for I and change the setpoint. Adjust the values of P and I from those values to get to where you want to go, tracking the process and seeing if increasing or decreasing values improves things.

Once you have P and I you can work on D but depending on the process dynamics giving a value for D might make your life worse.

The Ziegler-Nichols method gives you some guidelines for PID values which should get you in the ballpark. From there you can make adjustments to get better performance.

You will have to weigh the options of having overshoot with the amount of time the temperature takes to reach the new setpoint. The faster the temperature adjusts the more overshoot you will have. To have no overshoot will increase that amount of time considerably.

Cantilever answered 30/1, 2013 at 22:20 Comment(2)
Thanks! I guess Doug answered my question a tad bit earlier so I voted his best but still upvoted you. I'll keep this in mind for tuning. I definitely want to minimize overshoot since the current system without a fan simply can't cool down quickly, which means minimizing overshoot will definitely stabilize faster.Hilaire
No worries, happy to help. It basically boils down to trial and error but there are a bunch of different methods in the links above to give you guidelines about where to start.Cantilever
C
2

A few suggestions:

  • You seem to be integrating twice. Once inside your TempCtrl_PID function and once outside. Duty_Cycle += . So now your P term is really I.
  • Start with only a P term and keep increasing it until the system becomes unstable. Then back off (e.g. use 1/2 to 1/4 the value where it becomes unstable) and start adding an I term. Start with very low values on the I term and then gradually increase. This process is a way of tuning the loop. Because the system will probably have a pretty long time constant this may be time consuming...
  • You can add some feed-forward as you suggest (expected duty cycle for a given setpoint - map it out by setting the duty cycle and letting the system stabilize.). It doesn't matter if that term isn't perfect since the loop will take out the remaining error. You can also simply add some constant bias to the duty cycle. Keep in mind a constant wouldn't really make any difference as the integrator will take it out. It will only affect a cold start.
  • Make sure you have some sort of fixed time base for this loop. E.g. make an adjustment every 10ms.
  • I would not worry about the D term for now. A PI controller should be good enough for most applications.
Carduaceous answered 30/1, 2013 at 22:19 Comment(1)
I didn't think about your first bullet. That would definitely be why my system with the I term was very unstable. You didn't answer my initial question I asked, but I definitely appreciate the suggestions for tuning.Hilaire

© 2022 - 2024 — McMap. All rights reserved.