Skip to content

Commit

Permalink
Add logging capability
Browse files Browse the repository at this point in the history
  • Loading branch information
hirschmann committed Jan 25, 2017
1 parent 9e98d2f commit 7a266eb
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
27 changes: 21 additions & 6 deletions brewapp/base/automatic/pid_arduino.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
import logging
from brewapp import app, socketio
from automaticlogic import *

Expand All @@ -18,7 +19,7 @@ def run(self):
p = float(self.config["P"])
i = float(self.config["I"])
d = float(self.config["D"])
pid = PIDArduino(wait_time, p, i, d)
pid = PIDArduino(wait_time, p, i, d, 0, 100)

while self.isRunning():
heat_percent = pid.calc(self.getCurrentTemp(), self.getTargetTemp())
Expand All @@ -34,8 +35,8 @@ def run(self):
# See https://github.com/br3ttb/Arduino-PID-Library
class PIDArduino(object):

def __init__(self, kp, ki, kd, sampleTimeSec,
outputMin=float('-inf'), outputMax=float('inf')):
def __init__(self, sampleTimeSec, kp, ki, kd, outputMin=float('-inf'),
outputMax=float('inf'), getTimeMs=None):
if kp is None:
raise ValueError('kp must be specified')
if ki is None:
Expand All @@ -47,6 +48,7 @@ def __init__(self, kp, ki, kd, sampleTimeSec,
if outputMin >= outputMax:
raise ValueError('outputMin must be less than outputMax')

self._logger = logging.getLogger(type(self).__name__)
self._Kp = kp
self._Ki = ki * sampleTimeSec
self._Kd = kd / sampleTimeSec
Expand All @@ -58,8 +60,13 @@ def __init__(self, kp, ki, kd, sampleTimeSec,
self._lastOutput = 0
self._lastCalc = 0

if getTimeMs is None:
self._getTimeMs = PIDArduino._currentTimeMs
else:
self._getTimeMs = getTimeMs

def calc(self, inputValue, setpoint):
now = PIDArduino._currentTimeMs()
now = self._getTimeMs()

if (now - self._lastCalc) < self._sampleTime:
return self._lastOutput
Expand All @@ -71,12 +78,20 @@ def calc(self, inputValue, setpoint):
self._iTerm = max(self._iTerm, self._outputMin)
dInput = inputValue - self._lastInput

p = self._Kp * error
i = self._iTerm
d = -(self._Kd * dInput)

# Compute PID Output
self._lastOutput = self._Kp * error + self._iTerm - self._Kd * dInput
self._lastOutput = p + i + d
self._lastOutput = min(self._lastOutput, self._outputMax)
self._lastOutput = max(self._lastOutput, self._outputMin)

# Remember some variables for next time*/
self._logger.debug('P: {0}'.format(p))
self._logger.debug('I: {0}'.format(i))
self._logger.debug('D: {0}'.format(d))

# Remember some variables for next time
self._lastInput = inputValue
self._lastCalc = now
return self._lastOutput
Expand Down
20 changes: 17 additions & 3 deletions brewapp/base/automatic/pid_autotune.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import time
import math
import logging
from collections import deque
from collections import namedtuple
from brewapp import app, socketio
Expand Down Expand Up @@ -60,7 +61,7 @@ class PIDAutotune(object):
"no-overshoot": [100, 40, 60]
}

def __init__(self, setpoint, outputstep=10, lookbacksec=10, noiseband=0.5,
def __init__(self, setpoint, outputstep=10, lookbacksec=10, noiseband=0.5, getTimeMs=None,
outputMin=float('-inf'), outputMax=float('inf')):
if setpoint is None:
raise ValueError('setpoint must be specified')
Expand All @@ -78,6 +79,7 @@ def __init__(self, setpoint, outputstep=10, lookbacksec=10, noiseband=0.5,
self._inputs = deque(maxlen=100)
self._sampleTime = lookbacksec * 10

self._logger = logging.getLogger(type(self).__name__)
self._setpoint = setpoint
self._outputstep = outputstep
self._noiseband = noiseband
Expand All @@ -97,6 +99,11 @@ def __init__(self, setpoint, outputstep=10, lookbacksec=10, noiseband=0.5,
self._Ku = 0
self._Pu = 0

if getTimeMs is None:
self._getTimeMs = PIDAutotune._currentTimeMs
else:
self._getTimeMs = getTimeMs

@property
def state(self):
return self._state
Expand All @@ -107,7 +114,7 @@ def output(self):

@property
def tuningRules(self):
return self._tuning_rules.keys
return self._tuning_rules.keys()

def getPIDParameters(self, tuningRule='ziegler-nichols'):
divisors = self._tuning_rules[tuningRule]
Expand All @@ -117,7 +124,7 @@ def getPIDParameters(self, tuningRule='ziegler-nichols'):
return PIDAutotune.PIDParams(kp, ki, kd)

def run(self, inputValue):
now = PIDAutotune._currentTimeMs()
now = self._getTimeMs()

if (self._state == PIDAutotune.STATE_OFF
or self._state == PIDAutotune.STATE_SUCCEEDED
Expand All @@ -132,9 +139,11 @@ def run(self, inputValue):
if (self._state == PIDAutotune.STATE_RELAY_STEP_UP
and inputValue > self._setpoint + self._noiseband):
self._state = PIDAutotune.STATE_RELAY_STEP_DOWN
self._logger.debug('switched state: {0}'.format(self._state))
elif (self._state == PIDAutotune.STATE_RELAY_STEP_DOWN
and inputValue < self._setpoint - self._noiseband):
self._state = PIDAutotune.STATE_RELAY_STEP_UP
self._logger.debug('switched state: {0}'.format(self._state))

# set output
if (self._state == PIDAutotune.STATE_RELAY_STEP_UP):
Expand Down Expand Up @@ -182,6 +191,8 @@ def run(self, inputValue):
self._peakCount += 1
self._peaks.append(inputValue)
self._peakTimestamps.append(now)
self._logger.debug('found peak: {0}'.format(inputValue))
self._logger.debug('peak count: {0}'.format(self._peakCount))

# check for convergence of induced oscillation
# convergence of amplitude assessed on last 4 peaks (1.5 cycles)
Expand All @@ -201,6 +212,9 @@ def run(self, inputValue):
amplitudeDev = ((0.5 * (absMax - absMin) - self._inducedAmplitude)
/ self._inducedAmplitude)

self._logger.debug('amplitude: {0}'.format(self._inducedAmplitude))
self._logger.debug('amplitude deviation: {0}'.format(amplitudeDev))

if amplitudeDev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE:
self._state = PIDAutotune.STATE_SUCCEEDED

Expand Down

0 comments on commit 7a266eb

Please sign in to comment.