@@ -2,10 +2,42 @@ import tkinter as tk
2
2
import numpy as np
3
3
import matplotlib .pyplot as plt
4
4
import random
5
+ import threading
6
+ import time
5
7
from matplotlib import animation
6
8
from scipy .integrate import odeint
7
9
from pylogix import PLC
8
10
11
+ class PeriodicInterval (threading .Thread ):
12
+ def __init__ (self , task_function , period ):
13
+ super ().__init__ ()
14
+ self .daemon = True
15
+ self .task_function = task_function
16
+ self .period = period
17
+ self .i = 0
18
+ self .t0 = time .time ()
19
+ self .stopper = 0
20
+ self .start ()
21
+
22
+ def sleep (self ):
23
+ self .i += 1
24
+ delta = self .t0 + self .period * self .i - time .time ()
25
+ if delta > 0 :
26
+ time .sleep (delta )
27
+
28
+ def run (self ):
29
+ while self .stopper == 0 :
30
+ self .task_function ()
31
+ self .sleep ()
32
+
33
+ def stop (self ):
34
+ self .stopper = 1
35
+
36
+ def starter (self ):
37
+ self .stopper = 0
38
+ self .i = 0
39
+ self .t0 = time .time ()
40
+
9
41
class data (object ):
10
42
def __init__ (self ):
11
43
self .PV = np .zeros (0 )
@@ -28,10 +60,12 @@ class FOPDTModel(object):
28
60
self .Gain , self .TimeConstant , self .DeadTime , self .Bias = ModelData
29
61
30
62
def calc (self ,PV ,ts ):
31
- if (self . t - self .DeadTime * 10 ) <= 0 :
63
+ if (ts - self .DeadTime * 10 ) <= 0 :
32
64
um = 0
65
+ elif int (ts - self .DeadTime * 10 )>= len (self .CV ):
66
+ um = self .CV [- 1 ]
33
67
else :
34
- um = self .CV [self . t - int (self .DeadTime * 10 )]
68
+ um = self .CV [int (ts - self .DeadTime * 10 )]
35
69
dydt = (- (PV - self .Bias ) + self .Gain * um )/ (self .TimeConstant * 10 )
36
70
return dydt
37
71
@@ -52,11 +86,9 @@ def fopdtsetup():
52
86
spstatus .set ("" )
53
87
pvstatus .set ("" )
54
88
cvstatus .set ("" )
55
-
56
- def start ():
57
- global looper
58
89
comm .IPAddress = ip .get ()
59
90
comm .ProcessorSlot = int (slot .get ())
91
+ comm .SocketTimeout = 1
60
92
button_start ["state" ] = "disabled"
61
93
button_stop ["state" ] = "normal"
62
94
button_trend ["state" ] = "normal"
@@ -66,7 +98,12 @@ def start():
66
98
modeltc .configure (state = "disabled" )
67
99
modeldt .configure (state = "disabled" )
68
100
ambient .configure (state = "disabled" )
101
+
102
+ def thread_start ():
103
+ global looper
104
+ looper = PeriodicInterval (start , 0.1 )
69
105
106
+ def start ():
70
107
try :
71
108
ret = comm .Read ([cvtag .get (),sptag .get ()])
72
109
if ret [0 ].Status == 'Success' :
@@ -115,8 +152,6 @@ def start():
115
152
116
153
except Exception as e :
117
154
pvstatus .set ('An exception occurred: {}' .format (e ))
118
-
119
- looper = root .after (100 , start )
120
155
121
156
def stop ():
122
157
button_start ["state" ] = "normal"
@@ -131,16 +166,17 @@ def stop():
131
166
sptag .configure (state = "normal" )
132
167
ambient .configure (state = "normal" )
133
168
gData .livetrend = 0
134
- root .after_cancel (looper )
169
+ if 'looper' in globals ():
170
+ looper .stop ()
135
171
comm .Close ()
136
172
137
173
def livetrend ():
138
174
#Set up the figure
139
175
fig = plt .figure ()
140
176
ax = plt .axes (xlim = (0 ,100 ),ylim = (0 , 100 ))
141
- SP , = ax .plot ([], [], lw = 2 , label = 'SP' )
142
- PV , = ax .plot ([], [], lw = 2 , label = 'PV ' )
143
- CV , = ax .plot ([], [], lw = 2 , label = 'CV ' )
177
+ SP , = ax .plot ([], [], lw = 2 , color = "Red" , label = 'SP' )
178
+ CV , = ax .plot ([], [], lw = 2 , color = "Green" , label = 'CV ' )
179
+ PV , = ax .plot ([], [], lw = 2 , color = "Blue" , label = 'PV ' )
144
180
145
181
#Setup Func
146
182
def init ():
@@ -161,7 +197,7 @@ def livetrend():
161
197
ax .set_xlim (0 ,max (x )* 1.1 )
162
198
max_y = max (max (gData .PV ),max (gData .CV ),max (gData .SP ))
163
199
min_y = min (min (gData .PV ),min (gData .CV ),min (gData .SP ))
164
- ax .set_ylim (min_y - 10 ,max_y + 10 )
200
+ ax .set_ylim (min_y - 1 ,max_y + 1 )
165
201
SP .set_data (x ,gData .SP )
166
202
CV .set_data (x ,gData .CV )
167
203
PV .set_data (x ,gData .PV )
@@ -253,7 +289,7 @@ ambient.insert(5, "13.5")
253
289
254
290
#Buttons
255
291
#Start Button Placement
256
- button_start = tk .Button (root , text = "Start Simulator" , command = lambda :[fopdtsetup (),start ()])
292
+ button_start = tk .Button (root , text = "Start Simulator" , command = lambda :[fopdtsetup (),thread_start ()])
257
293
button_start .grid (row = 4 ,column = 0 ,columnspan = 1 ,padx = 10 ,pady = 2 ,sticky = "NESW" )
258
294
259
295
#Stop Button Placement
@@ -265,13 +301,11 @@ button_trend = tk.Button(root, text="Show Trend", command=lambda :[livetrend()])
265
301
button_trend .grid (row = 5 ,column = 0 ,columnspan = 2 ,padx = 10 ,pady = 2 ,sticky = "NESW" )
266
302
button_trend ["state" ] = "disabled"
267
303
268
- comm = PLC ()
269
-
270
- #default process
304
+ #default setup
271
305
params = 0 ,0
272
306
model = (modelgain .get (),modeltc .get (),modeldt .get (),13.1 )
273
307
process = FOPDTModel (params , model )
274
-
275
308
gData = data ()
309
+ comm = PLC ()
276
310
277
311
root .mainloop ()
0 commit comments