diff --git a/config.py b/config.py index df4a05f..e49e716 100644 --- a/config.py +++ b/config.py @@ -65,7 +65,7 @@ sensor_time_wait = 2 # your specific kiln. Note that the integral pid_ki is # inverted so that a smaller number means more integral action. pid_kp = 25 # Proportional 25,200,200 -pid_ki = 1 # Integral +pid_ki = 20 # Integral pid_kd = 200 # Derivative diff --git a/lib/oven.py b/lib/oven.py index 4512a13..0bc7d59 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -219,12 +219,10 @@ class Oven(threading.Thread): if self.target - temp > config.pid_control_window: log.info("kiln must catch up, too cold, shifting schedule") self.start_time = datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000) - self.pid.iterm = 0 # kiln too hot, wait for it to cool down if temp - self.target > config.pid_control_window: log.info("kiln must catch up, too hot, shifting schedule") self.start_time = datetime.datetime.now() - datetime.timedelta(milliseconds = self.runtime * 1000) - self.pid.iterm = 0 def update_runtime(self): @@ -363,15 +361,20 @@ class SimulatedOven(Oven): int(self.p_env))) time_left = self.totaltime - self.runtime - log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % - (self.board.temp_sensor.temperature + config.thermocouple_offset, - self.target, - pid, - heat_on, - heat_off, - self.runtime, - self.totaltime, - time_left)) + + log.info("temp=%.2f, target=%.2f, error=%.2f, pid=%.2f, p=%.2f, i=%.2f, d=%.2f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % + (self.pid.pidstats['ispoint'], + self.pid.pidstats['setpoint'], + self.pid.pidstats['err'], + self.pid.pidstats['pid'], + self.pid.pidstats['p'], + self.pid.pidstats['i'], + self.pid.pidstats['d'], + heat_on, + heat_off, + self.runtime, + self.totaltime, + time_left)) # we don't actually spend time heating & cooling during # a simulation, so sleep. @@ -412,15 +415,20 @@ class RealOven(Oven): if heat_off: self.output.cool(heat_off) time_left = self.totaltime - self.runtime - log.info("temp=%.2f, target=%.2f, pid=%.3f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % - (self.board.temp_sensor.temperature + config.thermocouple_offset, - self.target, - pid, - heat_on, - heat_off, - self.runtime, - self.totaltime, - time_left)) + + log.info("temp=%.2f, target=%.2f, error=%.2f, pid=%.2f, p=%.2f, i=%.2f, d=%.2f, heat_on=%.2f, heat_off=%.2f, run_time=%d, total_time=%d, time_left=%d" % + (self.pid.pidstats['ispoint'], + self.pid.pidstats['setpoint'], + self.pid.pidstats['err'], + self.pid.pidstats['pid'], + self.pid.pidstats['p'], + self.pid.pidstats['i'], + self.pid.pidstats['d'], + heat_on, + heat_off, + self.runtime, + self.totaltime, + time_left)) class Profile(): def __init__(self, json_data): @@ -489,10 +497,11 @@ class PID(): output = 0 out4logs = 0 dErr = 0 - if error < (-1 * config.pid_control_window): log.info("kiln outside pid control window, max cooling") output = 0 + # it is possible to set self.iterm=0 here and also below + # but I dont think its needed elif error > (1 * config.pid_control_window): log.info("kiln outside pid control window, max heating") output = 1 @@ -508,6 +517,10 @@ class PID(): self.lastErr = error self.lastNow = now + # no active cooling + if output < 0: + output = 0 + self.pidstats = { 'time': time.mktime(now.timetuple()), 'timeDelta': timeDelta, @@ -525,16 +538,4 @@ class PID(): 'out': output, } -# if out4logs > 0: -# log.info("pid percents pid=%0.2f p=%0.2f i=%0.2f d=%0.2f" % (out4logs, -# ((self.kp * error)/out4logs)*100, -# (self.iterm/out4logs)*100, -# ((self.kd * dErr)/out4logs)*100)) - log.info("pid actuals pid=%0.2f p=%0.2f i=%0.2f d=%0.2f icomp=%0.2f error=%0.2f" % (out4logs, - self.kp * error, - self.iterm, - self.kd * dErr, - icomp, - error)) - return output