Shop OBEX P1 Docs P2 Docs Learn Events
PID heater help — Parallax Forums

PID heater help

TCTC Posts: 1,019
edited 2014-04-19 06:48 in General Discussion
Hello all,

I am building a reflow oven, and I am trying to get it to heat up right. I can get it to heat to a set point, but it insanely over shoots (20-40°C). But when it stablizes, it is within 1°C. I know it is my PID that is doing it. The code gets updated about once a second.
VAR

  long  error
  long  last_error
  long  Pterm
  long  Iterm
  long  Dterm
  long  CV

PUB PID (set, current, Pgain, Igain, Dgain)

'=== This algorithm must be executed at a consistent guaranteed periodic rate (such as once/second) to function correctly ===

'set = value you want
'current = current value
'Pgain = Proportional gain value, use "0" if not needed
'Igain = Integral gain value,     use "0" if not needed
'Dgain = Derivative gain value,   use "0" if not needed

'*** Find Error ***
  error := set - current

'*** Find Proportional Value *** 
  Pterm := Pgain * error

'*** Find Integral Value ***
  Iterm := Iterm + (error * Igain) #>0 <#100 'anti-windup

'*** Find Derivative Value ***
  Dterm := (error - last_error) * Dgain

'*** Save current error ***
  last_error := error

'*** Sum PID values ***
'''' If set_value is off (0) make CV off
  if set == 0
    CV := 0

  else
    CV := Pterm + Iterm + Dterm #>0 <#100 ' output limiting

I have Pterm, Iterm, Dterm, CV, set_value, & current_value displayed on my display so I can see what is going on.

Here are the gain values I have, I have been changing them one by one to try to get it to work.
 P             = 1
 I              = 10
 D             = 30

Starting from a cold start(32°C), I notice Iterm will max out real fast(that's good I think), but it will stay like that until the temp goes past the set point. So I use Dterm to counter Iterm and try to slow down the PWM before the temp gets to the set point.

I don't know much about PIDs,I know what they are, and what they do. But I don't fully understand how they work. Wikipedia is not much help to me. I have never learned advance math, so the equations Wikipedia has mean nothing to me.

I found a post on control.com, that looked promising. So I copied it for the prop.

Could someone please take a look at it, and tell me if there is something wrong. Or do I have to keep trying different gain settings. Or if you might have a better option.

Thanks
TC
«1

Comments

  • Heater.Heater. Posts: 21,230
    edited 2014-02-18 04:21
    TC,

    We just had a good long discussion on temperature control here : http://forums.parallax.com/showthread.php/153551-Modifying-an-old-thermostatic-chamber-can-t-get-precise-temperature-control.

    Lot's of tips and pointers re: PID and temperature control in there.
  • TCTC Posts: 1,019
    edited 2014-02-18 04:35
    Wonderful, Thank You
  • T ChapT Chap Posts: 4,223
    edited 2014-02-18 05:00
    Overshoot is usually just that, over-windup. Start out with low integral max numbers, then move up. You don't really need D in temperature so you can get rid of it. Proportional should be a larger factor and predominant factor, with integral + windup max being lessor important.
  • MicksterMickster Posts: 2,694
    edited 2014-02-18 05:08
    I agree. That Integral looks way high! You might want to start with a very small value and maybe a low "IL" (integrator limit). How does it perform with "P" only?
  • TCTC Posts: 1,019
    edited 2014-02-18 05:43
    With values of
    P = 1
    I = 0
    D = 0
    

    it will over shoot by 12°C, and hover around -1°C and -14°C from the set point.

    With values of
    P = 5
    I = 1
    D = 0
    

    it will over shoot by 35°C and hover around -5°C to 10°C from the set point.

    Iterm is still going to 100 right out of the gate, and stays there until the current > set. then it starts decreasing. but by that time, it is to late. That is why I had such a large I gain, to make the decreasing faster.
  • TCTC Posts: 1,019
    edited 2014-02-18 05:45
    Right now, I am testing Iterm <#50
  • Heater.Heater. Posts: 21,230
    edited 2014-02-18 05:50
    I would like to be able to set P less than one. That is you should used scaled fixed point numbers.
  • T ChapT Chap Posts: 4,223
    edited 2014-02-18 06:01
    You can't really start guessing at values without having a clear idea of what the output stage is doing. You need to show where CV is going so a better idea of scale can be understood. Floating is not needed if your output is 0 - 1000 for example. Is the Pwm to an SSR on a heater element? I would do this at 0 - 1000 controlling PWM. I always use a tweaked PASM PWM object with a greater range that 0 - 100.

    To understand PID, you need a method to see the effect of the output versus an error. Without fully understanding each element, you can't tackle the more complicated issue of summing the elements in a useful manner. I would think it is not easy to grab an PID examples off the nest and immediately apply to a custom project. I spent countless hours looking at examples for motor control, but only when I started viewing each component and the sum did it all start to come together.
  • TCTC Posts: 1,019
    edited 2014-02-18 06:31
    Heater. wrote: »
    I would like to be able to set P less than one. That is you should used scaled fixed point numbers.

    What do you think my best option is? should I toss out what I have, and go floating point? Becaus I tried
    P = 1//2
    I = 0
    D = 0
    

    I got no change.
    T Chap wrote: »
    You can't really start guessing at values without having a clear idea of what the output stage is doing.

    I started at P = 1, then seen what happend on my display. Then went from there. Adding more to P, and seeing what happend. Then I started on I, same way. then D. Until I came up with what I had in my first post. As I said in my first post, I can see the values of SET, CURRENT, Pterm, Iterm, Dterm, and PID output

    display.jpg


    Don't mind the set value and the current value, that is not what the PID sees. If you take the value/25 that is the value the PID sees. IE 17500 / 25 = 700. The thermocouple adapter outputs in .25°C per bit. I just have the display converting so I can understand it.
    Floating is not needed if your output is 0 - 1000 for example. Is the Pwm to an SSR on a heater element? I would do this at 0 - 1000 controlling PWM. I always use a tweaked PASM PWM object with a greater range that 0 - 100.

    I am using a home built SSR. It works great, no problems. I am using a Spin object for the PWM, that waits for the AC to zero-cross so it knows when to turn off the Triac.
    To understand PID, you need a method to see the effect of the output versus an error. Without fully understanding each element, you can't tackle the more complicated issue of summing the elements in a useful manner. I would think it is not easy to grab an PID examples off the nest and immediately apply to a custom project. I spent countless hours looking at examples for motor control, but only when I started viewing each component and the sum did it all start to come together.

    I agree, why do you think I have the display.
    1024 x 577 - 104K
  • Heater.Heater. Posts: 21,230
    edited 2014-02-18 06:42
    You don't need floating point. Just hold all your number scaled up by a hundred or a thousand.
    When you want 1 store it as 1000 and so on.
    Then you can add and subtract as normal.
    If you want to multiply just multiply but divide by a thousand afterwards.
    e.g. For 10 x 10 you have stored them multiplied by a thousand so you now have 10,000 x 10,000 = 100,000,000.
    Which needs dividing by 1000 to get the correct scaled result of 100,000 which is 100 in back in the real world.

    Now you can multiply by 0.5 which is stored as 500.

    Don't forget you numbers are scaled when you come to print them out or use them.

    If you actually need this in your PID is another matter. Perhaps all the required scaling can be done on the error measurement input and the output drive.
  • T ChapT Chap Posts: 4,223
    edited 2014-02-18 07:15
    You may want to include a Deadband range, so that if the error is within a range then the output turns off. Also, in some cases you may use a dynamic input method so that if error > x, output max = y, so that you can drop the output as you get closer to the error = 0.
    PUB TempConvert  | int,deci, f
        int~
        deci~
        'tempnew := 368       'fake temp here to calibrate scale and bias rate  ie 2315
        repeat tempnew       ' converts binary bits celcius .0625 per bit to LCD display
          if deci == 16
            deci~
            int++
          deci++
        if deci*625  == 10000
           deci~
           int++
        go(1, 10)
        ser.str(3, string("BIN"))
        ser.decx(3, tempnew, 3)       'show raw binary temp  .0625 c per bit
        go1
        ser.decx(3, int, 3)
        ser.str(3, string("."))
        'if deci == 1
          'ser.dec(3, 0)
        ser.decx(3, deci*625, 4)
        ser.str(3, string("C"))
        int := (int * 10000) + (deci * 625)
        int := ((int * 9)  / 5)  + 320_000
        go0
        F := int/10000
        ser.decx(3, F, 3)
        ser.str(3, string("."))
        int := int - (F*10000)
        ser.decx(3, int, 4)
        ser.str(3, string("F"))
        'go(0,7)
        'ser.decf(3,(  ||(TripLevel + ClosingTripLevelOffset) ), 8)
    
    

    I have a device that outputs .0625 c per bit. You may be able to look at this and see if this can be adjusted and used for your temp sensor.

    It would be useful to see on the screen:
    Error =
    P =
    I =
    iMax =
    D =
    Output =
  • TCTC Posts: 1,019
    edited 2014-02-18 08:51
    Heater. wrote: »
    You don't need floating point. Just hold all your number scaled up by a hundred or a thousand.
    When you want 1 store it as 1000 and so on.
    Then you can add and subtract as normal.
    If you want to multiply just multiply but divide by a thousand afterwards.
    e.g. For 10 x 10 you have stored them multiplied by a thousand so you now have 10,000 x 10,000 = 100,000,000.
    Which needs dividing by 1000 to get the correct scaled result of 100,000 which is 100 in back in the real world.

    Now you can multiply by 0.5 which is stored as 500.

    Don't forget you numbers are scaled when you come to print them out or use them.

    If you actually need this in your PID is another matter. Perhaps all the required scaling can be done on the error measurement input and the output drive.

    I tried that, but I am getting some strange results.
    Pterm = current error * Pgain

    Lets say current error = 1, and Pgain = .5

    1 * .5 = .5

    now lets adjust the scale;

    1 * 1,000 (error * 1,000) = 1,000
    .5 * 1,000 (Pgain * 1,000) = 500

    1,000 * 500 = 500,000
    500,000 / 1,000 (bring back to real world) = 500
    Now lets say my PWM has a range of 0 to 1000, the PWM would have a 50% duty cycle at an error of 1

    I'm still thinking this through. I was hoping by me writing it down, i would see the answer.

    I was thinking of changing the real world 1,000 to 100,000
  • Heater.Heater. Posts: 21,230
    edited 2014-02-18 11:30
    TC,

    Sorry, perhaps I'm confusing you.

    When I talk about scaled arithmetic I mean that when you want the value 1 in your program you write 1000.
    // Set a to 1.0
    a := 1000
    

    If you want a half it's:
    // Set a to 0.5
    a := 500
    

    You cannot use Spin's floating point assignments like:
    // Set a to 0.5
    a := 0.5
    
    That will set "a" to some floating point representation of 0.5 which is not what we want.

    Just imagine that all your variables are representations of multiples of 1/1000 rather than just 1 as normal.
  • TCTC Posts: 1,019
    edited 2014-02-18 12:42
    Heater. wrote: »
    TC,

    Sorry, perhaps I'm confusing you.

    When I talk about scaled arithmetic I mean that when you want the value 1 in your program you write 1000.

    I honestly don't know, if I am over thinking it, or I am just wrong.

    I have
    Pgain = 500
    
    set = 300_000
    current = 299_000
    

    that gives me an error of 1_000
    '*** Find Proportional Value *** 
      Pterm := Pgain * error
    

    500 * 1000 = 500_000
    so now Pterm = 500_000
        CV := (Pterm + Iterm + Dterm)
        CV := CV / 1000
    

    500_000 + 0 + 0 = 500_000
    500_000 / 1_000 = 500 <
    this should be 0.5 in the real world (scaled)?

    Am I wanting a value of 5, instead of 500? Because I could just do
        CV := (Pterm + Iterm + Dterm)
        CV := CV / 100_000
    

    This is why I wish I could understand the PID equation on Wikipedia, I could check my work.
  • Heater.Heater. Posts: 21,230
    edited 2014-02-18 13:31
    TC,

    I'm afraid we are getting into a confusion between the PID, which you need, and fixed point arithmetic, which you may or may not need to get the PID to work.

    Anyway, an example. I want to calculate 5 * 6 using fixed point arithmetic:
    a := 5000    'Set a to 5.0
    b := 6000    'Set b to 6.0
    
    c := a * b / 1000      'Calculate a * b
    
    At the end of that code sequence "c" equals 5000 * 6000 / 1000 equals 30,000. Which is 5 x 6 if we are counting in "one thousandths" rather than "ones".
  • TCTC Posts: 1,019
    edited 2014-02-18 15:39
    Well, I have to start over anyway. I found out my thermocouple probe is an un-grounded type. The junction is separated from the probe by an insulator. So it is not responsive enough. I had to go with thermocouple wires, where the junction is unrestricted. I found this out by doing a manual reflow profile. the perf-board came out burnt. Using a thermocouple wire, I found out the temperature would go 50°C to 60°C over the probe, then after a little time, both the probe and the wire would say the same thing. I could see the probe taking longer to heat up.
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-02-18 16:53
    TC
    My oven overshoots too. Some of this is really not possible to control without some form of data transformation control (ie some manual feedback from a table). The time lag between turning the element on or off has an effect that I would expect a normal PID loop to be unable to control properly.
    I notice my oven shuts off the temp before it reaches the temp, then uses shorter bursts to get it up to temp.
    Hope this helps.

    BTW my thermocouple wire only goes to ~200C and I thought this was typical of that form of thermocouple??? I understand a probe will have a time lag.
  • TCTC Posts: 1,019
    edited 2014-02-18 16:59
    Well I think I got it.

    For my gains I am using
    CON
    
      '
      set_temp      = 900
      P             = 5
      I             = 1
      D             = 0
      bias          = 20000
    

    For the code I did what Heater suggested, I changed the scale of the values. Here is the code
    PUB PID (set, current, Pgain, Igain, Dgain)
    
    '=== This algorithim must be executed at a consistent guarenteed periodic rate (such as once/second) to function correctly ===
    
    'set = value you want
    'current = current value
    'Pgain = Proportional gain value, use "0" if not needed
    'Igain = Integral gain value,     use "0" if not needed
    'Dgain = Derivative gain value,   use "0" if not needed
    
      set := set * 100
      current := current * 100
    
    '*** Find Error ***
      error := (set) - (current)
    
    '*** Find Proportional Value *** 
      Pterm := Pgain * error
    
    '*** Find Integral Value ***
      Iterm := Iterm + (error * Igain) #>0 <#10000 'anti-windup
    
    '*** Find Derivative Value ***
      Dterm := (error - last_error) * Dgain
    
    '*** Save current error ***
      last_error := error
    
    '*** Sum PID values ***
      if set == 0                   'If set = 0 make output 0
        CV := 0
    
      else   
        CV := bias + (Pterm + Iterm + Dterm)
        CV := CV / 1000 #>0 <#100
    

    With this setup, I can go from 35°C to 225°C in no time. I have little to no overshoot. And the temperature will hover +1°C to -1°C.

    Thank you everyone.
  • kwinnkwinn Posts: 8,697
    edited 2014-02-18 22:01
    Nice work TC. It's impressive to see how you're jumping in to these projects with both feet.
  • Heater.Heater. Posts: 21,230
    edited 2014-02-19 00:34
    TC,

    That is a great result. Temperature control is not so easy and you seem to have it very well under control.

    I haven't looked at the code so had but this caught my eye:
    Pterm := Pgain * error
    

    Seems to be missing some scaling.

    For example we have gain = 3 and error = 6 so Pterm should be 18. In real world numbers. So in the code I would have:
    gain := 3 * 100
    error := 6 * 100
    Pterm := error * gain / 100
    
    Now Pterm is 1800 which is the correct scaled value of the real world value of 18.

    You are missing that divide on all your multiples so I wonder how this works. Perhaps you input and output scaling is taking care of it though.
  • TCTC Posts: 1,019
    edited 2014-02-19 03:31
    Thank you, I was so happy when the temperature hit its set point for the first time. I could not believe it, so I tried it 5 or 6 times. Now to make it work in it own COG, and a long list of other things I have to do.

    I was saying around the same lines as you. Things were not adding up, I was not getting the scaling that I thought I should've had. I did not think of adding the scaling to everything, just to the input and output. I think it would be better anyway to leave the scaling high through all the formulas, then bring it back down once everything is calculated. To me, it would be less chance of clipping the result.
  • Heater.Heater. Posts: 21,230
    edited 2014-02-19 04:25
    TC,

    You can do the scaling wherever you like that works.

    But be careful. If you start working with more complex formulae you might have problems. For examble:

    x := a * b

    Is 100 times to big in our scaled world. Which you might take or on output. But:

    x := a * b * c

    Is now 10000 times to big. And so on. Overflowing what can fit in a 32 bit integer is a possibility.

    Also:

    x := a * b
    x := x + c

    Goes a bit weird as after the first statement x is 100 times to big. If you scale back after the second statement then the effect of adding c is 100 times to small!

    So I like to keep the scaling correct at every step of the way.
  • nathantranthamnathantrantham Posts: 5
    edited 2014-04-14 18:31
    TC wrote: »
    I could not believe it, so I tried it 5 or 6 times. Now to make it work in it own COG, and a long list of other things I have to do.

    Hi TC,

    I saw on another post you were working on a reflow oven and I'm lucky I've stumbled upon this thread. Awesome insight from lots of helpful people.

    Is your code and oven still performing the way you want to? Can you expand on how you solved your overshoot issues? I'm having the same exact problem.

    Also, if you don't mind, could you post your most recent PID control code for me to use/look at please?

    Thanks a ton!
  • Duane C. JohnsonDuane C. Johnson Posts: 955
    edited 2014-04-14 19:20
    Hi nathantrantham;

    Try a bit less P and a bit more D.

    Duane J
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-04-15 01:08
    Hi all, I know I am rather late to join in. I have a 3D printer project which seems to indicate that PID temperature control is supported. On the other hand, the source code also mentions simple hysteresis control offers a more compact code solution.

    And so I am wondering if I really need PID for heater control. I certainly appreciate PID with motor control for tight positioning and tight rate control. It is just hard for me to believe I need that tightness with heat regulation.
  • TCTC Posts: 1,019
    edited 2014-04-15 03:18
    Hi TC,

    I saw on another post you were working on a reflow oven and I'm lucky I've stumbled upon this thread. Awesome insight from lots of helpful people.

    Is your code and oven still performing the way you want to? Can you expand on how you solved your overshoot issues? I'm having the same exact problem.

    Also, if you don't mind, could you post your most recent PID control code for me to use/look at please?

    Thanks a ton!

    Hello nathantrantham, and welcome to the forums.

    As Duane said, more D....

    It is still a work in progress. I keep changing things because I find A better idea. When I get home tonight, I will post the heater control I was using. The heater control works in another COG and all that would have to be done is to pass the set temperature value. it does assume A zero cross circuit is used, because at the time I was going to make my own SSR's.

    The object would read the temperature from a MAX31855, calculate the CV (control value) from the PID, then do a very simple PWM. It is very dirty, and I found a couple things I could make better. So instead of patching what I had, I started new.
  • nathantranthamnathantrantham Posts: 5
    edited 2014-04-16 17:38
    Duane and TC - thanks I'll increase the D contribution and see how things look.

    TC - yes, that's how I have mine setup too. Did you keep the scaling method? Or move to floating point? I'd still be interested in seeing your code if you would be so kind.

    Thanks.
  • TCTC Posts: 1,019
    edited 2014-04-16 18:30
    Duane and TC - thanks I'll increase the D contribution and see how things look.

    TC - yes, that's how I have mine setup too. Did you keep the scaling method? Or move to floating point? I'd still be interested in seeing your code if you would be so kind.

    Thanks.

    Yes, I scaled mine up by 1000.

    I included the code. I am in no way saying that this code is perfect, so use it at your own risk.
  • Duane C. JohnsonDuane C. Johnson Posts: 955
    edited 2014-04-16 20:57
    Hi TC;

    PID for dummies.
    proportional-integral-derivative
    Lets think about the old fashioned round Honywell thermostat.
    P=proportional
    The power delivered to the house, the rate heat is added from the furnace, is proportional to the the difference between the set point on my T87 and the room temperature.
    A P controller must have an error to output power. The gain factor defines how much error there will be.
    So, when its cold outside the room temperature will be colder than the set point.
    A P controller should be fast acting to track quick changes in the heat load.
    However, with high gain factors the system may go into oscillation and overshoot.

    I=integral
    On that cold night when I feel a bit chilly I may slowly adjust the set point on my T87 to compensate for the set point error.
    This is integration. A slow fudging of the dial until there is minimal error.
    In this example I am the I for the T87.
    I should be slow acting.

    D=derivative
    Ok, my house has settled down and I am comfortable but somebody opens the door and a bunch of heat escapes.
    Since the thermostat will sense this immediately the P controller would try to turn the furnace on immediately and strongly which can cause the P and I controllers to go unstable.
    However, the whole house has a lot of thermal mass and really doesn't need to change much.
    The D derivative controller watches the changes in the room temperature. D reduces the power output caused by the D controller.
    Essentially D is a limiting factor, the higher the D gain the less power that can be delivered.
    The faster the sensed temperature changes the less power delivered by the furnace.
    Don't go to high as D can not control the temperature.

    Unfortunately the T87 has no I nor D function but electronic thermostats do.

    Generalizations:
    System with high thermal mass can use hi P, low I, and low D.
    Systems with low thermal mass can use low P, hi I, and hi D.
    Systems with long time constants can use low P, low I, and hi D.

    Tuning:
    1. Start with pure P and increase the gain until it oscillates then back off the gain. There will be error, were just looking for stability.
    2. Add some I until the error is acceptable.
    3. Cause a transient heat load. Add some D to limit overshoots. You may need to reduce P.
    This should at least get the controller going.

    I keep meticulous notes when tuning PIDs as it can be very confusing with 3 interacting unknowns.

    Duane J
  • CuriousOneCuriousOne Posts: 931
    edited 2014-04-17 22:32
    I had similar task, I was given description of PID. I've read it and understood some kind, but can't "see" how to do it in code. So I've invented my own method:

    Say we have to heat something to X degrees. The heater is on up to X-certain value (say 10). Time taken to get it to that temperature is measured. Then heater is off, and time for it's cooldown to say X-20 is also measured. According to these timing values, initial PWM percentage is calculated and heater is PWMed with decreasing percentage while it reaches the desired X value. Kinda tricky, but no overshoot.
Sign In or Register to comment.