kopia lustrzana https://github.com/jbruce12000/kiln-controller
add recorder code
rodzic
b78c28068f
commit
a7fafeed65
|
|
@ -0,0 +1,83 @@
|
|||
import os
|
||||
import sys
|
||||
import csv
|
||||
import time
|
||||
import argparse
|
||||
|
||||
|
||||
try:
|
||||
sys.dont_write_bytecode = True
|
||||
import config
|
||||
sys.dont_write_bytecode = False
|
||||
|
||||
except:
|
||||
print("Could not import config file.")
|
||||
print("Copy config.py.EXAMPLE to config.py and adapt it for your setup.")
|
||||
exit(1)
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.insert(0, script_dir + '/lib/')
|
||||
profile_path = os.path.join(script_dir, "storage", "profiles")
|
||||
|
||||
from oven import RealOven, SimulatedOven
|
||||
|
||||
|
||||
def tune(csvfile, targettemp):
|
||||
# open the file to log data to
|
||||
f = open(csvfile, 'w')
|
||||
csvout = csv.writer(f)
|
||||
csvout.write(['time', 'temperature'])
|
||||
|
||||
# construct the oven
|
||||
if config.simulate:
|
||||
oven = SimulatedOven()
|
||||
else:
|
||||
oven = RealOven()
|
||||
|
||||
# Main loop:
|
||||
#
|
||||
# * heat the oven to the target temperature at maximum burn.
|
||||
# * when we reach it turn the heating off completely.
|
||||
# * wait for it to decay back to the target again.
|
||||
# * quit
|
||||
#
|
||||
# We record the temperature every config.sensor_time_wait
|
||||
try:
|
||||
stage = 'heating'
|
||||
if not config.simulate:
|
||||
oven.output.heat(1, tuning=True)
|
||||
|
||||
while True:
|
||||
temp = oven.board.temp_sensor.temperature + \
|
||||
config.thermocouple_offset
|
||||
|
||||
csvout.writerow([time.time(), temp])
|
||||
csvout.flush()
|
||||
|
||||
if stage == 'heating':
|
||||
if temp > targettemp:
|
||||
if not config.simulate:
|
||||
oven.output.heat(0)
|
||||
stage = 'decaying'
|
||||
|
||||
elif stage == 'decaying':
|
||||
if temp < targettemp:
|
||||
break
|
||||
|
||||
time.sleep(config.sensor_time_wait)
|
||||
|
||||
f.close()
|
||||
|
||||
finally:
|
||||
# ensure we always shut the oven down!
|
||||
if not config.simulate:
|
||||
oven.output.heat(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Record data for kiln tuning')
|
||||
parser.add_argument('csvfile', type=str, help="The CSV file to write to.")
|
||||
parser.add_argument('--targettemp', type='int', default=400, help="The target temperature to drive the kiln to.")
|
||||
args = parser.parse_args()
|
||||
|
||||
tune(args.csvfile, args.targettemp)
|
||||
30
lib/oven.py
30
lib/oven.py
|
|
@ -26,8 +26,10 @@ class Output(object):
|
|||
log.warning(msg)
|
||||
self.active = False
|
||||
|
||||
def heat(self,sleepfor):
|
||||
def heat(self,sleepfor, tuning=False):
|
||||
self.GPIO.output(config.gpio_heat, self.GPIO.HIGH)
|
||||
if tuning:
|
||||
return
|
||||
time.sleep(sleepfor)
|
||||
self.GPIO.output(config.gpio_heat, self.GPIO.LOW)
|
||||
|
||||
|
|
@ -54,7 +56,7 @@ class Board(object):
|
|||
self.active = True
|
||||
log.info("import %s " % (self.name))
|
||||
except ImportError:
|
||||
msg = "max31855 config set, but import failed"
|
||||
msg = "max31855 config set, but import failed"
|
||||
log.warning(msg)
|
||||
|
||||
if config.max31856:
|
||||
|
|
@ -64,7 +66,7 @@ class Board(object):
|
|||
self.active = True
|
||||
log.info("import %s " % (self.name))
|
||||
except ImportError:
|
||||
msg = "max31856 config set, but import failed"
|
||||
msg = "max31856 config set, but import failed"
|
||||
log.warning(msg)
|
||||
|
||||
def create_temp_sensor(self):
|
||||
|
|
@ -76,7 +78,7 @@ class Board(object):
|
|||
class BoardSimulated(object):
|
||||
def __init__(self):
|
||||
self.temp_sensor = TempSensorSimulated()
|
||||
|
||||
|
||||
class TempSensor(threading.Thread):
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
|
|
@ -118,7 +120,7 @@ class TempSensorReal(TempSensor):
|
|||
'''take 5 measurements over each time period and return the
|
||||
average'''
|
||||
while True:
|
||||
maxtries = 5
|
||||
maxtries = 5
|
||||
sleeptime = self.time_step / float(maxtries)
|
||||
temps = []
|
||||
for x in range(0,maxtries):
|
||||
|
|
@ -245,10 +247,10 @@ class SimulatedOven(Oven):
|
|||
# set temps to the temp of the surrounding environment
|
||||
self.t = self.t_env # deg C temp of oven
|
||||
self.t_h = self.t_env #deg C temp of heating element
|
||||
|
||||
|
||||
# call parent init
|
||||
Oven.__init__(self)
|
||||
|
||||
|
||||
# start thread
|
||||
self.start()
|
||||
log.info("SimulatedOven started")
|
||||
|
|
@ -306,9 +308,9 @@ class SimulatedOven(Oven):
|
|||
self.runtime,
|
||||
self.totaltime,
|
||||
time_left))
|
||||
|
||||
|
||||
# we don't actually spend time heating & cooling during
|
||||
# a simulation, so sleep.
|
||||
# a simulation, so sleep.
|
||||
time.sleep(self.time_step)
|
||||
|
||||
|
||||
|
|
@ -396,7 +398,7 @@ class PID():
|
|||
self.lastErr = 0
|
||||
|
||||
# FIX - this was using a really small window where the PID control
|
||||
# takes effect from -1 to 1. I changed this to various numbers and
|
||||
# takes effect from -1 to 1. I changed this to various numbers and
|
||||
# settled on -50 to 50 and then divide by 50 at the end. This results
|
||||
# in a larger PID control window and much more accurate control...
|
||||
# instead of what used to be binary on/off control.
|
||||
|
|
@ -410,7 +412,7 @@ class PID():
|
|||
|
||||
if self.ki > 0:
|
||||
self.iterm += (error * timeDelta * (1/self.ki))
|
||||
|
||||
|
||||
dErr = (error - self.lastErr) / timeDelta
|
||||
output = self.kp * error + self.iterm + self.kd * dErr
|
||||
out4logs = output
|
||||
|
|
@ -427,10 +429,10 @@ class PID():
|
|||
|
||||
output = float(output / window_size)
|
||||
|
||||
if out4logs > 0:
|
||||
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.kp * error)/out4logs)*100,
|
||||
(self.iterm/out4logs)*100,
|
||||
((self.kd * dErr)/out4logs)*100))
|
||||
((self.kd * dErr)/out4logs)*100))
|
||||
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import csv
|
|||
import argparse
|
||||
|
||||
|
||||
# Using the method from https://www.ias.ac.in/article/fulltext/reso/025/10/1385-1397 or https://www.youtube.com/watch?v=nvAQHSe-Ax4
|
||||
# Using the method described in "Ziegler–Nichols Tuning Method∗" by Vishakha Vijay Patel
|
||||
# (https://www.ias.ac.in/article/fulltext/reso/025/10/1385-1397)
|
||||
|
||||
|
||||
def line(a, b, x):
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue