10 ! *********************************************************************
20 ! Example: PID Controller
30 !
40 ! This example program simulates a PID Controller.
50 !
60 ! **************************************************************
70 !
80 DIM Points(3),Errors(64),Enum$(2)[10]
90 !
100 ! Construct the panel that controls the PID itself.
110 ! The panel indicates the current error and whether the loop is locked.
120 !
130 ASSIGN @Pid_panel TO WIDGET "PANEL";SET ("X":0,"Y":0,"WIDTH":400,"HEIGHT":245,"TITLE":"PID Controller","RESIZABLE":0,"MAXIMIZABLE":0)
140 CONTROL @Pid_panel;SET ("TITLE":" Example: PID Controller")
150 CONTROL @Pid_panel;SET ("SYSTEM MENU":"Quit")
160 ON EVENT @Pid_panel,"SYSTEM MENU" GOTO Finis
170 !
180 ! Slider to control Kp
190 !
200 ASSIGN @Kp_slider TO WIDGET "SLIDER";PARENT @Pid_panel,SET ("X":5,"Y":30,"WIDTH":70,"HEIGHT":180,"DECIMAL DIGITS":2)
210 CONTROL @Kp_slider;SET ("MINIMUM":0,"MAXIMUM":1,"MINOR INCREMENT":.01)
220 ASSIGN @Kp_note TO WIDGET "STRING";PARENT @Pid_panel,SET ("X":5,"Y":0,"WIDTH":70,"HEIGHT":20,"VALUE":" Kp")
230 !
240 ! Slider to control Ki
250 !
260 ASSIGN @Ki_slider TO WIDGET "SLIDER";PARENT @Pid_panel,SET ("X":80,"Y":30,"WIDTH":70,"HEIGHT":180,"DECIMAL DIGITS":2)
270 CONTROL @Ki_slider;SET ("MINIMUM":0,"MAXIMUM":1,"MINOR INCREMENT":.01)
280 ASSIGN @Ki_note TO WIDGET "STRING";PARENT @Pid_panel,SET ("X":80,"Y":0,"WIDTH":70,"HEIGHT":20,"VALUE":" Ki")
290 !
300 ! Slider to control Kd
310 !
320 ASSIGN @Kd_slider TO WIDGET "SLIDER";PARENT @Pid_panel,SET ("X":155,"Y":30,"WIDTH":70,"HEIGHT":180,"DECIMAL DIGITS":2)
330 CONTROL @Kd_slider;SET ("MINIMUM":0,"MAXIMUM":1,"MINOR INCREMENT":.01)
340 ASSIGN @Kd_note TO WIDGET "STRING";PARENT @Pid_panel,SET ("X":155,"Y":0,"WIDTH":70,"HEIGHT":20,"VALUE":" Kd")
350 !
360 ! Meter that displays the error
370 !
380 ASSIGN @Error_meter TO WIDGET "METER";PARENT @Pid_panel,SET ("X":235,"Y":30,"WIDTH":150,"HEIGHT":140,"MINIMUM":-1,"MAXIMUM":1,"AUTOSCALE":0)
390 ASSIGN @Meter_note TO WIDGET "STRING";PARENT @Pid_panel,SET ("X":235,"Y":0,"WIDTH":150,"HEIGHT":20,"VALUE":" Error")
400 !
410 ! String that displays whether the loop is locked or unlocked
420 !
430 ASSIGN @Lock_indicate TO WIDGET "STRING";PARENT @Pid_panel,SET ("X":270,"Y":180,"VALUE":"UNLOCKED","WIDTH":80,"HEIGHT":30,"BACKGROUND":2)
440 !
450 ! Slider that sets the set point for the loop
460 !
470 ASSIGN @Setpt_slider TO WIDGET "SLIDER";SET ("X":410,"Y":0,"WIDTH":150,"TITLE":"Set Point","DECIMAL DIGITS":2)
480 CONTROL @Setpt_slider;SET ("MINIMUM":0,"MAXIMUM":1,"MAJOR INCREMENT":.01,"MINOR INCREMENT":.1)
490 !
500 ! Strip chart to plot the set point and actual value
510 !
520 ASSIGN @Graph TO WIDGET "STRIPCHART";SET ("X":0,"Y":245,"TRACE COUNT":2,"SHARED X":1,"HEIGHT":235,"RESIZABLE":0,"MAXIMIZABLE":0)
530 CONTROL @Graph;SET ("CURRENT AXIS":"Y","ORIGIN":-.25,"RANGE":1.5)
540 CONTROL @Graph;SET ("CURRENT AXIS":"X","ORIGIN":0,"RANGE":100)
550 CONTROL @Graph;SET ("CURRENT TRACE":1,"TRACE LABEL":"Set point")
560 CONTROL @Graph;SET ("CURRENT TRACE":2,"TRACE LABEL":"Actual")
570 CONTROL @Graph;SET ("TITLE":" Set Point Value")
580 !
590 ! Cyclic control for the order of the load
600 !
610 Enum$(0)="1st"
620 Enum$(1)="2nd"
630 Load_order=1
640 ASSIGN @Load TO WIDGET "PUSHBUTTON";SET ("X":410,"Y":250,"WIDTH":150,"HEIGHT":50)
650 CONTROL @Load;SET ("TITLE":"Load Order","RESIZABLE":0,"MAXIMIZABLE":0,"LABEL":Enum$(Load_order))
660 ON EVENT @Load,"ACTIVATED",1 GOSUB Load_change
670 !
680 ! Initialize the sliders that control the PID
690 !
700 Ki=.17
710 CONTROL @Ki_slider;SET ("VALUE":Ki)
720 Kp=.4
730 CONTROL @Kp_slider;SET ("VALUE":Kp)
740 Kd=.37
750 CONTROL @Kd_slider;SET ("VALUE":Kd)
760 !
770 ! Initialize the setpoint slider
780 !
790 Setpt=.9
800 CONTROL @Setpt_slider;SET ("VALUE":Setpt)
810 !
820 ! Enable the event handling for the sliders
830 !
840 ON EVENT @Ki_slider,"DONE",2 GOSUB Ki_input
850 ON EVENT @Kp_slider,"DONE",2 GOSUB Kp_input
860 ON EVENT @Kd_slider,"DONE",2 GOSUB Kd_input
870 ON EVENT @Setpt_slider,"DONE",2 GOSUB Setpt_input
880 !
890 ! Initialize the actual value of the output and the array
900 ! that contains previous error values
910 !
920 Actual=0
930 FOR I=0 TO 62
940 Errors(I)=0
950 NEXT I
960 Sample=0
970 LOOP
980 Avg=0
990 FOR I=62 TO 0 STEP -1
1000 Avg=Avg+Errors(I)
1010 Errors(I+1)=Errors(I)
1020 NEXT I
1030 Errors(0)=Setpt-Actual
1040 Avg=(Avg+Errors(0))/64
1050 To_load=(Kp*Errors(0)+Ki*Avg+Kd*(Errors(0)-Errors(1)))
1060 SELECT Load_order
1070 CASE 0
1080 !
1090 ! First order load
1100 !
1110 Actual=(To_load*1.7)+Actual
1120 CASE 1
1130 !
1140 ! Second order load
1150 !
1160 Temp=To_load*5+Temp
1170 Actual=(Temp*.52+Actual)/2
1180 END SELECT
1190 Points(0)=Setpt
1200 Points(1)=Actual
1210 CONTROL @Graph;SET ("POINT LOCATION":Sample,"VALUES":Points(*))
1220 Sample=Sample+1
1230 CONTROL @Error_meter;SET ("VALUE":Errors(0))
1240 IF ABS(Errors(0))+ABS(Errors(1))<.02 THEN
1250 CONTROL @Lock_indicate;SET ("VALUE":"LOCKED","BACKGROUND":4)
1260 ELSE
1270 CONTROL @Lock_indicate;SET ("VALUE":"UNLOCKED","BACKGROUND":2)
1280 END IF
1290 END LOOP
1300 Ki_input: STATUS @Ki_slider;RETURN ("VALUE":Ki)
1310 Ki=PROUND(Ki,-2)
1320 RETURN
1330 Kp_input: STATUS @Kp_slider;RETURN ("VALUE":Kp)
1340 Kp=PROUND(Kp,-2)
1350 RETURN
1360 Kd_input: STATUS @Kd_slider;RETURN ("VALUE":Kd)
1370 Kd=PROUND(Kd,-2)
1380 RETURN
1390 Setpt_input: STATUS @Setpt_slider;RETURN ("VALUE":Setpt)
1400 Setpt=PROUND(Setpt,-2)
1410 RETURN
1420 Load_change: Load_order=Load_order+1
1430 IF Load_order>1 THEN Load_order=0
1440 CONTROL @Load;SET ("LABEL":Enum$(Load_order))
1450 RETURN
1460 Finis: !
1470 ASSIGN @Pid_panel TO * ! Delete PANEL widget
1480 END