-
Notifications
You must be signed in to change notification settings - Fork 2
/
multithreadPID.py
150 lines (123 loc) · 4.03 KB
/
multithreadPID.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import os
import glob
import time
import threading
import SSRControl
import readMaxim
#mode BOOST or not?
BOILER_BOOST_MODE = 1
#boiler max temperature for boost mode
BOILER_MAX_TEMP = 124
#boiler threshold to stop boost mode
BOILER_BOOST_GROUP_LIMIT = 84
class TaskControlPID(threading.Thread):
#default target temp is 118C
def __init__(self, taskid = 0, maximGroupe = None, maximBoiler = None, tTarget = 118):
threading.Thread.__init__(self)
self.lok = threading.Lock()
self.taskid = taskid
self._stopevent = threading.Event( )
self.maximBoiler = maximBoiler
self.maximGroupe = maximGroupe
self.currentDrive = 0
#init regulator values
self.m_timeStep = 1.0
self.m_targetTemp = tTarget
self.m_latestTemp = 20.0
self.m_latestPower = 0.0
#init PID values
self.m_dState = 0.0
self.m_iState = 0.0
self.m_iMin = -1.0
self.m_iMax = 1.0
self.m_iGain = 0.0
self.m_pGain = 1.0
self.m_dGain = 0.0
#based on James Ward's PID algorithm
def pid_update(self,error = 0.0, position = 0.0):
# calculate proportional term
pTerm = self.m_pGain * error
# calculate integral state with appropriate limiting
self.m_iState += error
if ( self.m_iState > self.m_iMax ):
self.m_iState = self.m_iMax
if ( self.m_iState < self.m_iMin ):
self.m_iState = self.m_iMin
#calculate integral term
iTerm = self.m_iGain * self.m_iState
#calculate derivative term
dTerm = self.m_dGain * (self.m_dState - position)
self.m_dState = position
return pTerm + dTerm + iTerm
def run(self):
print "Thread PID no", self.taskid, "is readry!\n > Based on James Ward's PID algorithm"
drive = 0.0
lastdrive = 0.0
#based on James Ward's PID algorithm
while not self._stopevent.isSet():
#PID computation
#timestamp
next = time.time()
#get current boiler temp
latestTemp = self.maximBoiler.getTemp()
#controle de la chaudiere
lastdrive = drive
#if temperature read is correct, start algorithm
if ( latestTemp > 0.5 ):
#calculate next time step
next += self.m_timeStep
#get current target temperature
cTargetTemp = self.getTargetTemp()
#calculate PID update
#boost mode only if boiler target temp is higher than 100C (ECO mode is 90)
if((BOILER_BOOST_MODE == 1) and (cTargetTemp > 100)):
tgroupe = self.maximGroupe.getTemp()
#stop the boost mode when group temp is higher than boiler temp - 30C (approximate)
bBoostLimit = cTargetTemp - 30
#boost boiler target temperature if we are under a certain value
if ((tgroupe > 0.5) and (tgroupe < bBoostLimit)):
drive = self.pid_update( BOILER_MAX_TEMP - latestTemp, latestTemp )
else:
drive = self.pid_update( cTargetTemp - latestTemp, latestTemp )
else:
drive = self.pid_update( cTargetTemp - latestTemp, latestTemp )
#drive = self.pid_update( self.getTargetTemp() - latestTemp, latestTemp )
#clamp the output power to sensible range
if ( drive > 1.0 ):
drive = 1.0
if ( drive < 0.0 ):
drive = 0.0
#update the boiler power (with PWM) if last state changed
if ( drive != lastdrive ):
drv = int(drive * 100)
self.setCurrentDrive( drv )
SSRControl.setBoilerPWM( drv )
#wait the remaining time (typically, slot = 1 second)
remain = next - time.time()
if ( remain > 0.0 ):
self._stopevent.wait(remain)
def stop(self):
print "stopping thread no", self.taskid
self._stopevent.set( )
def getTargetTemp(self):
#protect concurrent access with mutex
self.lok.acquire()
tt = self.m_targetTemp
self.lok.release()
return tt
def setTargetTemp(self,ttemp=115):
#protect concurrent access with mutex
self.lok.acquire()
self.m_targetTemp = ttemp
self.lok.release()
def getCurrentDrive(self):
#protect concurrent access with mutex
self.lok.acquire()
tt = self.currentDrive
self.lok.release()
return tt
def setCurrentDrive(self,drive=0):
#protect concurrent access with mutex
self.lok.acquire()
self.currentDrive = drive
self.lok.release()