forked from M-Labs/thermostat
add autotune
This commit is contained in:
parent
be4383a447
commit
059dd0bbb6
|
@ -17,6 +17,7 @@ class PIDAutotuneState(Enum):
|
||||||
STATE_RELAY_STEP_DOWN = 'relay step down'
|
STATE_RELAY_STEP_DOWN = 'relay step down'
|
||||||
STATE_SUCCEEDED = 'succeeded'
|
STATE_SUCCEEDED = 'succeeded'
|
||||||
STATE_FAILED = 'failed'
|
STATE_FAILED = 'failed'
|
||||||
|
STATE_READY = 'ready'
|
||||||
|
|
||||||
|
|
||||||
class PIDAutotune:
|
class PIDAutotune:
|
||||||
|
@ -56,6 +57,20 @@ class PIDAutotune:
|
||||||
self._Ku = 0
|
self._Ku = 0
|
||||||
self._Pu = 0
|
self._Pu = 0
|
||||||
|
|
||||||
|
def setParam(self, target, step, noiseband, sampletime, lookback):
|
||||||
|
self._setpoint = target
|
||||||
|
self._outputstep = step
|
||||||
|
self._out_max = step
|
||||||
|
self._out_min = -step
|
||||||
|
self._noiseband = noiseband
|
||||||
|
self._inputs = deque(maxlen=round(lookback / sampletime))
|
||||||
|
|
||||||
|
def setReady(self):
|
||||||
|
self._state = PIDAutotuneState.STATE_READY
|
||||||
|
|
||||||
|
def setOff(self):
|
||||||
|
self._state = PIDAutotuneState.STATE_OFF
|
||||||
|
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Get the current state."""
|
"""Get the current state."""
|
||||||
return self._state
|
return self._state
|
||||||
|
@ -81,6 +96,13 @@ class PIDAutotune:
|
||||||
kd = divisors[2] * self._Ku * self._Pu
|
kd = divisors[2] * self._Ku * self._Pu
|
||||||
return PIDAutotune.PIDParams(kp, ki, kd)
|
return PIDAutotune.PIDParams(kp, ki, kd)
|
||||||
|
|
||||||
|
def get_tec_pid (self):
|
||||||
|
divisors = self._tuning_rules["tyreus-luyben"]
|
||||||
|
kp = self._Ku * divisors[0]
|
||||||
|
ki = divisors[1] * self._Ku / self._Pu
|
||||||
|
kd = divisors[2] * self._Ku * self._Pu
|
||||||
|
return kp, ki, kd
|
||||||
|
|
||||||
def run(self, input_val, time_input):
|
def run(self, input_val, time_input):
|
||||||
"""To autotune a system, this method must be called periodically.
|
"""To autotune a system, this method must be called periodically.
|
||||||
|
|
||||||
|
@ -95,7 +117,8 @@ class PIDAutotune:
|
||||||
|
|
||||||
if (self._state == PIDAutotuneState.STATE_OFF
|
if (self._state == PIDAutotuneState.STATE_OFF
|
||||||
or self._state == PIDAutotuneState.STATE_SUCCEEDED
|
or self._state == PIDAutotuneState.STATE_SUCCEEDED
|
||||||
or self._state == PIDAutotuneState.STATE_FAILED):
|
or self._state == PIDAutotuneState.STATE_FAILED
|
||||||
|
or self._state == PIDAutotuneState.STATE_READY):
|
||||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||||
|
|
||||||
self._last_run_timestamp = now
|
self._last_run_timestamp = now
|
||||||
|
|
|
@ -68,7 +68,8 @@ GUIparams = [[
|
||||||
{'name': 'Save to flash', 'type': 'action', 'tip': 'Save to flash'},
|
{'name': 'Save to flash', 'type': 'action', 'tip': 'Save to flash'},
|
||||||
] for _ in range(2)]
|
] for _ in range(2)]
|
||||||
|
|
||||||
autoTuneState = [PIDAutotuneState.STATE_OFF, 'idle']
|
autoTuner = [PIDAutotune(20, 1, 1, 1.5, refresh_period / 1000),
|
||||||
|
PIDAutotune(20, 1, 1, 1.5, refresh_period / 1000)]
|
||||||
|
|
||||||
## If anything changes in the tree, print a message
|
## If anything changes in the tree, print a message
|
||||||
def change(param, changes, ch):
|
def change(param, changes, ch):
|
||||||
|
@ -88,6 +89,7 @@ def change(param, changes, ch):
|
||||||
tec.set_param('pwm', ch, 'i_set', 0)
|
tec.set_param('pwm', ch, 'i_set', 0)
|
||||||
paramList[ch].child('Constant Current').child('Set Current').setValue(0)
|
paramList[ch].child('Constant Current').child('Set Current').setValue(0)
|
||||||
paramList[ch].child('Temperature PID').setValue(False)
|
paramList[ch].child('Temperature PID').setValue(False)
|
||||||
|
autoTuner[ch].setOff()
|
||||||
|
|
||||||
if (childName == 'Temperature PID'):
|
if (childName == 'Temperature PID'):
|
||||||
if (data):
|
if (data):
|
||||||
|
@ -130,7 +132,13 @@ def change(param, changes, ch):
|
||||||
tec.set_param('pid', ch, 'kd', data)
|
tec.set_param('pid', ch, 'kd', data)
|
||||||
|
|
||||||
if (childName == 'PID Config.PID Auto Tune.Run'):
|
if (childName == 'PID Config.PID Auto Tune.Run'):
|
||||||
autoTuneState[ch] = 'triggered'
|
autoTuner[ch].setParam(paramList[ch].child('PID Config').child('PID Auto Tune').child('Target Temperature').value(),
|
||||||
|
paramList[ch].child('PID Config').child('PID Auto Tune').child('Test Current').value(),
|
||||||
|
paramList[ch].child('PID Config').child('PID Auto Tune').child('Temperature Swing').value(),
|
||||||
|
refresh_period / 1000,
|
||||||
|
1)
|
||||||
|
autoTuner[ch].setReady()
|
||||||
|
paramList[ch].child('Temperature PID').setValue(False)
|
||||||
|
|
||||||
if (childName == 'Save to flash'):
|
if (childName == 'Save to flash'):
|
||||||
tec.save_config()
|
tec.save_config()
|
||||||
|
@ -185,8 +193,8 @@ def TECsync():
|
||||||
if parents['tag'] == 'report':
|
if parents['tag'] == 'report':
|
||||||
for data in tec.report_mode():
|
for data in tec.report_mode():
|
||||||
for children in parents['children']:
|
for children in parents['children']:
|
||||||
|
print(data)
|
||||||
children['value'] = data[channel][children['tag']]
|
children['value'] = data[channel][children['tag']]
|
||||||
print(data[channel][children['tag']])
|
|
||||||
if quit:
|
if quit:
|
||||||
break
|
break
|
||||||
if parents['tag'] == 'pwm':
|
if parents['tag'] == 'pwm':
|
||||||
|
@ -226,10 +234,24 @@ def updateData():
|
||||||
ch0currentGraph.update(data, cnt)
|
ch0currentGraph.update(data, cnt)
|
||||||
ch1currentGraph.update(data, cnt)
|
ch1currentGraph.update(data, cnt)
|
||||||
|
|
||||||
for state in autoTuneState:
|
for channel in range (2):
|
||||||
if state == 'triggered':
|
if (autoTuner[channel].state() == PIDAutotuneState.STATE_READY or
|
||||||
state = 'tuning'
|
autoTuner[channel].state() == PIDAutotuneState.STATE_RELAY_STEP_UP or
|
||||||
|
autoTuner[channel].state() == PIDAutotuneState.STATE_RELAY_STEP_DOWN):
|
||||||
|
autoTuner[channel].run(data[channel]['temperature'], data[channel]['time'])
|
||||||
|
tec.set_param('pwm', channel, 'i_set', autoTuner[channel].output())
|
||||||
|
elif (autoTuner[channel].state() == PIDAutotuneState.STATE_SUCCEEDED):
|
||||||
|
kp, ki, kd = autoTuner[channel].get_tec_pid()
|
||||||
|
autoTuner[channel].setOff()
|
||||||
|
paramList[channel].child('PID Config').child('kP').setValue(kp)
|
||||||
|
paramList[channel].child('PID Config').child('kI').setValue(ki)
|
||||||
|
paramList[channel].child('PID Config').child('kD').setValue(kd)
|
||||||
|
tec.set_param('pid', channel, 'kp', kp)
|
||||||
|
tec.set_param('pid', channel, 'ki', ki)
|
||||||
|
tec.set_param('pid', channel, 'kd', kd)
|
||||||
|
elif (autoTuner[channel].state() == PIDAutotuneState.STATE_FAILED):
|
||||||
|
tec.set_param('pwm', channel, 'i_set', 0)
|
||||||
|
autoTuner[channel].setOff()
|
||||||
|
|
||||||
if quit:
|
if quit:
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in New Issue