PID controlling Relay from User inputs


Quentin

Recommended Posts

I am trying to setup a PID loop with 5 different temperatures setpoints and 5 distinct durations for each setpoint. How do you suggest I proceed? 

The goal is to basically have a 5 setpoint entries on the page0 and 5 duration entries. The PID is controlling a relay that truns On/Off a heat pad. I am reading the temperature from a K-type thermocouple. 

I am using a labjack U6

Link to comment
Share on other sites

You aren't talking about a PID loop but rather a ramp and soak, albeit presumably a steep (instant) ramp.  The PID portion is totally separate and is just designed to maintain the current setpoint.  You should start there.  Create a variable to hold your current setpoint and setup a PID loop or script to control the relay to maintain the desired temperature. 

Note that with a relay, unless it is solid state you will likely NOT want to use PID, but instead do a simple thermostatic control.  For PID to be effective it really needs an analog output, which can be achieved with a relay through PWM, but that is not advised with mechanical relays as they can't really handle the rapid switching, especially under load.

Once you have it controlling at a particular setpoint, you can create two variables to hold the 5 target setpoints and durations.  These are separate to the actual current setpoint that your loop is controlling to.  Those two variables will be arrays, in your case with 5 elements each.  So, for example, if the you wanted to step up from 25 to 45 in 5 degree increments with a duration of 60 seconds each as a default, you would do:

global tempSPs = {25,30,35,40,45}
global tempDuration = {60,60,60,60,60}

(Note that you could use seqadd() and fill() functions instead of hard coding, but the above is clearer).

You can then access any particular SP or duration using subsetting.  So, the 3rd setpoint is:

tempSPs[2]

(everything is numbered from 0).

Then you just need to create a sequence that ramps it.  It is a rather simple sequence.  Let's assume your control loop is using a global variable called "curSP" as the current setpoint it is controlling to.  Then the sequence to (instantaneous) ramp and soak is simply:

for (private i = 0, i < numrows(tempSPs), i++)
   curSP = tempSPs[i]
   delay(tempDuration[i]
endfor

 

Link to comment
Share on other sites

Thank you for the clairifications. Sorry I am very new to this...

I confirm that I am using an SSR relay. 

Would it be possible to read in those setpoints and durations from the page0? And then how could I communicate with my relay to ask it to stop/restart when it has reach the setpoint in question. 

 

Would I write the script in the sequence or in the PID loop - event script? 

 

Example:

Trying to reach 115 degrees and stay there for 2min, then 125 degrees and stay there for 3 min, then 135 degrees and stay there for 4min, then back to 120 and stay there for 5min and back to 110degrees and stay there for 5min with the minimum amount of overshoot.

 

I have attached my .ctl

Test2.ctl

Link to comment
Share on other sites

The script I provided will handle the ramp/soak which is what you describe in your example.  My script, however, uses seconds, not minutes.  You can use screen controls to edit the variables, tempSPs[0], tempSPs[1] etc, and tempDuration[0], tempDuration[1]...  I do not recommend using edit boxes on the main page of any HMI (see 

).  You can use regular variable value controls with the Set To action.

Separately you need to figure out the control.  SSR means you could do PWM but you should figure out whether you really need it and a PID loop, or if a simple thermostatic control would work.  That script would be as simple as:

global tempHyst = 1
while(1)
   if (TC[0] > curSP)
      relay_control = 0
   endif
   if (TC[0] < curSP - tempHyst)
      relay_control = 1
   endif
   delay(1)
endwhile

This script should keep you within a degree of your SP (the tempHyst variable).  Considering thermocouples have an accuracy of about +/- 1 degree C, you are probably good.  To get tighter control you would first need to make sure your thermocouple was well calibrated and then you'd have to implement some PWM, again possible just in script instead of a PID.  I personally find that most temperature control applications are easier to manage with simple scripts than PID.

Link to comment
Share on other sites

Great, thank you!

Two follow up questions:

1/     Where do I write this script? Sequence (which thread priority... PID?) or PID loop/ event tab?

global tempHyst = 1
while(1)
   if (TC[0] > curSP)
      relay_control = 0
   endif
   if (TC[0] < curSP - tempHyst)
      relay_control = 1
   endif
   delay(1)
endwhile

 

2/     Where can I read in the temperature setpoints from the page0 button/ set to as you suggested? How can IU communicate with the blue box/ "set point" input or do I have to add these directly from a sequence loop? If so can the button create a variable or I would have to create a distinct channel to store all of these values like in the exemple below? 

 

global tempSPs = {Temp1[0],Temp2[0],Temp3[0],Temp4[0],Temp5[0]}
global tempDuration = {time1[0],time2[0],time3[0],time4[0],time5[0]}
Link to comment
Share on other sites

OK.  So first you'll need to get the digital output to work correctly per your other post.  Once you have that you'll want to get a PWM setup.  That is relatively straight forward in software, but you might consider using the LabJack's PWM feature of its counter.  If so, refer to 10.5.1 of the DAQFactory - LabJack Application Guide PDF included with the DAQFactory download.

For software PWM, I'm going to assume you are going to stick with the name "relay_control" for your output channel.  In that case you will want to create a sequence.  Call it, say, PWMRelayController:

global relay_control_PWM = -100 // -100 to 100
while(1)
   relay_control = (systime() % 1) * 200 < (relay_control_PWM+100)
   delay(0.02)
endwhile

This gives a PWM with a period of 1 second and a resolution of 50 steps, which is probably plenty.   You can mark this sequence Auto-Start and just let it run all the time.  Then, you can change the new relay_control_PWM variable from -100 (always off) to 100 (always on) or anywhere in between and it will PWM the relay.  The easiest way to see this is to create a graph of relay_control vs time.  I chose -100 to 100 because those are the best numbers for the PID loop.  The Output Channel of your PID loop will be  the variable relay_control_PWM.

Once you have that working, you can work on the PID loop.  The process variable will be TC[0] or whichever channel has the temperature reading you are controlling.  The output channel will be Relay_control_pwm as I mentioned.  For now, set the setpoint manually to a single value, say 10.  You can change it and hit Apply and it will update.  We will work on doing your Ramp/Soak later.  It is important that you get this part working first before making things more complicated.  

For anyone who wants to understand the logic of the PWM script I provided, specifically the 3rd line:

(systime() % 1) returns a number between 0 and 1 corresponding to the decimal part of the current second.  This gets multiplied by 200 to get it into the full range of relay_control_PWM (which as I mentioned should go from -100 to 100 because that is what the PID loop likes), so a number from 0 - 200 depending on when in the second the code gets executed.  We then compare it to our current relay_control_PWM setting which we shift by 100 to make also 0-200.  DAQFactory boolean is similar to other languages, where 1 is true, and 0 is false, so the result of that comparison sends a 0 or 1 to the actual relay output.

 

Link to comment
Share on other sites

Great!

Like this then? Or do i need to setup globals first?

while(1)
   for (private i = 0, i < numrows(tempSPs), i++)
      curSP = tempSPs[i]
         if(Out < 0)
            Relay_control[0] = 0
            delay(0.02)
         else
            Relay_control[0] = 1
            delay(0.02)
         endif
      delay(SPduration[i])
   endfor
endwhile

image.png.f980785d921abd2b033708953307c268.png

Link to comment
Share on other sites

New issue, the if loop control the relay will only run once per for loop. 

i.e. it will iterate through the for loop run the if loop once and then wait for the delay to be completed.

for (private i = 0, i < numrows(tempSPs), i++)
   curSP = tempSPs[i]
   if(Out < 0)
      Relay_control[0] = 0
      delay(0.02)
   else
      Relay_control[0] = 1
      delay(0.02)
   endif
   delay(tempDuration[i])
   ?tempSPs[i]
   ?tempDuration[i]
endfor

What is required is for the if loop to actually run continuously during the whole delay of the for loop, would this work?

for (private i = 0, i < numrows(tempSPs), i++)
   curSP = tempSPs[i]
   private startTime = systime()
   private elapsedTime = 0
   while (elapsedTime < tempDuration[i])
      if(Out < 0)
         Relay_control[0] = 0
         delay(0.02)
      else
         Relay_control[0] = 1
         delay(0.02)
      endif
      elapsedTime = systime() - startTime
   endwhile
   delay(tempDuration[i])
   ?tempSPs[i]
   ?tempDuration[i]
endfor


 

Link to comment
Share on other sites

You'd be best served by simply putting the relay control part inside its own sequence inside its own while() loop and just run that at the same time.  Alternatively, you could just use the Event of the PID and control the relay directly.  The other possibility is to put a Conversion on relay_control.  It would just be:

Value >= 0

Then if you set relay_control to any value > 0 it will turn on, but if you set it to any value < 0 it will turn off.  Then you don't need the loop, the if() or even the Out channel and can simply have the PID update relay_control directly.

Link to comment
Share on other sites

No idea, but that graph is just like the regular trend graph component on your pages.  You can open its properties by double clicking on the center of it.  Then check for three expressions.  They all will start with "PID.PID1." and then you'll have PVHistory, OVHistory and SPHistory.  Also check the axis scaling.

As a side note, these variables, PID.PID1.PVHistory etc, are globally available so you can create your own graph of the PID parameters and their history on your own pages.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.