mkelly Posted May 1, 2012 Share Posted May 1, 2012 System Configuration: Labjack controlling relays via PWM from DAQFactory. Relays control heat wires that set the system temperature. Process variable is monitored by thermocouples. PWM Setup is obtained via the TimerPWM.ctl example file. Modified to allow for 3 channels. Works fine when inputting a value directly from a variable text box. // configure PWM timer: //Set the timer/counter pin offset to 4, which will put the first timer/counter on FIO4. AddRequest (ID, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, 4, 0, 0) // use system clock so works on U3 and UE9: AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc1MHZ_DIV, 0, 0) AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, 15, 0, 0) //Enable 1 timer. It will use FIO4. AddRequest(ID, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 4, 0, 0) //Configure Timer0 as 16-bit PWM. AddRequest(ID, LJ_ioPUT_TIMER_MODE, 0, LJ_tmPWM16, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_MODE, 1, LJ_tmPWM16, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_MODE, 2, LJ_tmPWM16, 0, 0) //Set the PWM duty cycle. AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 0, 65535 * PWMWidth / 100, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 1, 65535 * PWMWidth2 / 100, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 2, 65535 * PWMWidth3 / 100, 0, 0) //Execute the requests. GoOne(ID) ErrorHandler(ID) As mentioned, this controls the heat fine if set to a value. As the relays open when the signal grounds, a 90% PWMwidth value relates to a 10% duty. So 100% would be always closed, and a 0% would be always open. I'm trying now to have them be controlled via a PID loop. Configurations of each PID can be seen in GB_control.PNG and GT_control.png If I remove Reverse Acting the output channel value shoots up to .1 and if I apply it it shoots down to 99.9 However the real issue is that these changes of PWMWidth and PWMWidth2 values have no observable affect on the PWM signal. I'm stumped as to how to output this value to the SetupPWM sequence. Attached as well is the ctl file I'm using for this. HAS DAQ Rev A GA1.ctl Link to comment Share on other sites More sharing options...
AzeoTech Posted May 3, 2012 Share Posted May 3, 2012 The problem is that the math in PID requires that the output center on 0. My typical recommendation is to have setup the PID loop to range from -100 to 100, and then scale that to the appropriate output value, in your case 0 to 100. The scaling factor is simply: (PIDOutput + 100) / 2. You can put that right in the AddRequest() line where you have PWMWidth. I didn't look at your file, but note that once you have the PWM setup, to change the width, you only have to do the PUT_TIMER_VALUE command. Link to comment Share on other sites More sharing options...
mkelly Posted May 7, 2012 Author Share Posted May 7, 2012 I set the range to be -100 to 100 and added the scaling factory into the Add request. It looks like this works, but initially only one of my 2 PID loops looked like it was working. I did some tweaking and now it seems like they're both responding to the output. An hour or 2 till it reaches the setpoint and I'm concerned it won't slow it's ascent if the output isn't getting passed through and stays at fully open. I didn't look at your file, but note that once you have the PWM setup, to change the width, you only have to do the PUT_TIMER_VALUE command. If it necessary to call this command value every time I change my PWMWidth value? If yes would I have to create a sequence files that acts as the output channel? Or will it just modify the sequence value once the PWMWidth value changes? Link to comment Share on other sites More sharing options...
AzeoTech Posted May 7, 2012 Share Posted May 7, 2012 First part: if you fear the ascent rate won't slow, you need to adjust the PID parameters, in particular probably the D parameter as that is used to dampen rate of change. Second part: simply changing PWMWidth should change the timer value, provided PWMWidth is a Timer channel. Link to comment Share on other sites More sharing options...
mkelly Posted May 7, 2012 Author Share Posted May 7, 2012 Ok I'm stumped. It really seems like there's a disconnect between the Output channel of my PID loop and the PUT_TIMER_VALUE command. So here's a graph of my test runs. The reactor has 2 heat wraps that can control the upper and bottom half seperately Brown = Top Magenta = Mid 1 Pink = Mid 2 Light Pink = Mid 3 Teal = Bottom As you can see at around 1:45 I reset the PID loops. I also manually set the PWMWidth2 for the bottom heat tape to -100 (100% duty) After around 10 minutes the PID loop sees that it's reaching the set point and ramps up to 100 (0%) duty as seen in dark red. Well 5 minutes after that I notice that neither the bottom temperatures are continueing to climb so I manually set the the PWMWidth2 to 100 (0% duty). I also noticed that the top heat tape was not responsing, so I set PWMWidth to -100 (100% duty) After around another 15 minutes I notice again the output from the PID (as seen in green) is not showing a response so I set the PWMWidth value to 100 (0% duty) I'm currently waiting to see what happens once it stabalized back down. Though I'm fearful that it will not reactivate like it did prior. So it seems to me like the error in my program is the Output channel. Can I not set it directly to PWMWidth? Do I have to make it a channel or a sequence? Can I just add something to the event tab on the PID loop? Link to comment Share on other sites More sharing options...
mkelly Posted May 7, 2012 Author Share Posted May 7, 2012 Update: I made a new sequence called "VaryPWM" //Set the PWM duty cycle. AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 0, 65535 * ((PWMWidth+100)/2) / 100, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 1, 65535 * ((PWMWidth2+100)/2) / 100, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 2, 65535 * ((PWMWidth3+100)/2) / 100, 0, 0) AddRequest(ID, LJ_ioPUT_TIMER_VALUE, 3, 65535 * ((PWMWidth4+100)/2) / 100, 0, 0) AddRequest(ID2, LJ_ioPUT_TIMER_VALUE, 0, 65535 * ((PWMWidth5+100)/2) / 100, 0, 0) AddRequest(ID2, LJ_ioPUT_TIMER_VALUE, 1, 65535 * ((PWMWidth6+100)/2) / 100, 0, 0) AddRequest(ID2, LJ_ioPUT_TIMER_VALUE, 2, 65535 * ((PWMWidth7+100)/2) / 100, 0, 0) AddRequest(ID2, LJ_ioPUT_TIMER_VALUE, 3, 65535 * ((PWMWidth8+100)/2) / 100, 0, 0) //Execute the requests. GoOne(ID) ErrorHandler(ID) GoOne(ID2) ErrorHandler(ID2) then I added a call to this sequence in the PID loops VaryPWM() and it looks like it is responding to changes in PWMWidth now. One (hopefully) final question: While my system is operating I want the PID to control the high temperature in it's control zone. Typically this occurs on Mid 1 and Mid 3 during heat up. Once the system is operating the max point tends to move from Mid 1 to Mid 2 and Mid 3 to Bottom. Is it possible to have it pick the maximum temperature to use in the PID loop. I tried some things with the Max() function but I wasn't sure if it could do the calculation with a channel instead of a variable or something else. Link to comment Share on other sites More sharing options...
mkelly Posted May 8, 2012 Author Share Posted May 8, 2012 Ok now I'm trying to understand the autotune function. I have the system oscilating and am trying to tune in the values but I don't understand what relay height means? Link to comment Share on other sites More sharing options...
AzeoTech Posted May 9, 2012 Share Posted May 9, 2012 From post #6: I'm not quite sure what you mean. Do you want to use the max of 4 channels as the process variable for the PID loop? If so, do something like: max(concat(mid1[0], mid2[0], mid3[0], bottom[0])) Note that concat can only have 20 parameters. You are a long way from this, but I thought I'd mention it. As for auto-tune: the relay height is how much it changes the output with each iteration. Basically, it will do this: when you start the autotune, which should be done on a stable system, it will capture the current output (OV). Then it will look at PV compared to SP. If PV > SP, it will change the OV to OV - relay height. If PV < SP, it will change the OV to OV + relay height. It will repeat this evaluation every iteration, thus causing an oscillation of PV. It then uses the timing of this oscillation to give you auto-tune parameters. This is one of two common ways of doing auto-tune and typically the preferred method when the system can't be deviated from some SP by a lot during auto-tune for physical reasons. The other common method is to trigger a big change in SP and then look at the slope and timing of the curve that follows. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.