aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/example.cfg8
-rw-r--r--klippy/extras/pid_calibrate.py2
-rw-r--r--klippy/heater.py51
3 files changed, 36 insertions, 25 deletions
diff --git a/config/example.cfg b/config/example.cfg
index dd4b7d28..cf02bf19 100644
--- a/config/example.cfg
+++ b/config/example.cfg
@@ -161,6 +161,10 @@ sensor_pin: analog13
#adc_voltage: 5.0
# The ADC comparison voltage. This parameter is only valid when the
# sensor is an AD595 or "PT100 INA826". The default is 5 volts.
+#smooth_time: 2.0
+# A time value (in seconds) over which temperature measurements will
+# be smoothed to reduce the impact of measurement noise. The default
+# is 2 seconds.
control: pid
# Control algorithm (either pid or watermark). This parameter must
# be provided.
@@ -173,10 +177,6 @@ pid_Ki: 1.08
pid_Kd: 114
# Kd is the "derivative" constant for the pid. This parameter must
# be provided for PID heaters.
-#pid_deriv_time: 2.0
-# A time value (in seconds) over which the derivative in the pid
-# will be smoothed to reduce the impact of measurement noise. The
-# default is 2 seconds.
#pid_integral_max:
# The maximum "windup" the integral term may accumulate. The default
# is to use the same value as max_power.
diff --git a/klippy/extras/pid_calibrate.py b/klippy/extras/pid_calibrate.py
index 05ec6e99..b087f2b3 100644
--- a/klippy/extras/pid_calibrate.py
+++ b/klippy/extras/pid_calibrate.py
@@ -86,7 +86,7 @@ class ControlAutoTune:
if temp > self.peak:
self.peak = temp
self.peak_time = read_time
- def check_busy(self, eventtime, last_temp, target_temp):
+ def check_busy(self, eventtime, smoothed_temp, target_temp):
if self.heating or len(self.peaks) < 12:
return True
return False
diff --git a/klippy/heater.py b/klippy/heater.py
index 0cb54343..7bbe4a82 100644
--- a/klippy/heater.py
+++ b/klippy/heater.py
@@ -21,23 +21,34 @@ class error(Exception):
class Heater:
error = error
def __init__(self, config, sensor):
- self.sensor = sensor
- self.name = config.get_name()
printer = config.get_printer()
+ self.name = config.get_name()
+ # Setup sensor
+ self.sensor = sensor
self.min_temp = config.getfloat('min_temp', minval=KELVIN_TO_CELCIUS)
self.max_temp = config.getfloat('max_temp', above=self.min_temp)
self.sensor.setup_minmax(self.min_temp, self.max_temp)
self.sensor.setup_callback(self.temperature_callback)
self.pwm_delay = self.sensor.get_report_time_delta()
+ # Setup temperature checks
self.min_extrude_temp = config.getfloat(
'min_extrude_temp', 170., minval=self.min_temp, maxval=self.max_temp)
+ is_fileoutput = printer.get_start_args().get('debugoutput') is not None
+ self.can_extrude = self.min_extrude_temp <= 0. or is_fileoutput
self.max_power = config.getfloat('max_power', 1., above=0., maxval=1.)
+ self.smooth_time = config.getfloat('smooth_time', 2., above=0.)
+ self.inv_smooth_time = 1. / self.smooth_time
self.lock = threading.Lock()
- self.last_temp = 0.
+ self.last_temp = self.smoothed_temp = self.target_temp = 0.
self.last_temp_time = 0.
- self.target_temp = 0.
+ # pwm caching
+ self.next_pwm_time = 0.
+ self.last_pwm_value = 0.
+ # Setup control algorithm sub-class
algos = {'watermark': ControlBangBang, 'pid': ControlPID}
algo = config.getchoice('control', algos)
+ self.control = algo(self, config)
+ # Setup output heater pin
heater_pin = config.get('heater_pin')
ppins = printer.lookup_object('pins')
if algo is ControlBangBang and self.max_power == 1.:
@@ -48,12 +59,6 @@ class Heater:
'pwm_cycle_time', 0.100, above=0., maxval=self.pwm_delay)
self.mcu_pwm.setup_cycle_time(pwm_cycle_time)
self.mcu_pwm.setup_max_duration(MAX_HEAT_TIME)
- is_fileoutput = self.mcu_pwm.get_mcu().is_fileoutput()
- self.can_extrude = self.min_extrude_temp <= 0. or is_fileoutput
- self.control = algo(self, config)
- # pwm caching
- self.next_pwm_time = 0.
- self.last_pwm_value = 0.
# Load additional modules
printer.try_load_module(config, "verify_heater %s" % (self.name,))
printer.try_load_module(config, "pid_calibrate")
@@ -73,16 +78,22 @@ class Heater:
self.mcu_pwm.set_pwm(pwm_time, value)
def temperature_callback(self, read_time, temp):
with self.lock:
+ time_diff = read_time - self.last_temp_time
self.last_temp = temp
self.last_temp_time = read_time
- self.can_extrude = (temp >= self.min_extrude_temp)
self.control.temperature_update(read_time, temp, self.target_temp)
+ temp_diff = temp - self.smoothed_temp
+ adj_time = min(time_diff * self.inv_smooth_time, 1.)
+ self.smoothed_temp += temp_diff * adj_time
+ self.can_extrude = (self.smoothed_temp >= self.min_extrude_temp)
#logging.debug("temp: %.3f %f = %f", read_time, temp)
# External commands
def get_pwm_delay(self):
return self.pwm_delay
def get_max_power(self):
return self.max_power
+ def get_smooth_time(self):
+ return self.smooth_time
def set_temp(self, print_time, degrees):
if degrees and (degrees < self.min_temp or degrees > self.max_temp):
raise error("Requested temperature (%.1f) out of range (%.1f:%.1f)"
@@ -94,11 +105,11 @@ class Heater:
with self.lock:
if self.last_temp_time < print_time:
return 0., self.target_temp
- return self.last_temp, self.target_temp
+ return self.smoothed_temp, self.target_temp
def check_busy(self, eventtime):
with self.lock:
return self.control.check_busy(
- eventtime, self.last_temp, self.target_temp)
+ eventtime, self.smoothed_temp, self.target_temp)
def set_control(self, control):
with self.lock:
old_control = self.control
@@ -120,8 +131,8 @@ class Heater:
def get_status(self, eventtime):
with self.lock:
target_temp = self.target_temp
- last_temp = self.last_temp
- return {'temperature': last_temp, 'target': target_temp}
+ smoothed_temp = self.smoothed_temp
+ return {'temperature': smoothed_temp, 'target': target_temp}
######################################################################
@@ -143,8 +154,8 @@ class ControlBangBang:
self.heater.set_pwm(read_time, self.heater_max_power)
else:
self.heater.set_pwm(read_time, 0.)
- def check_busy(self, eventtime, last_temp, target_temp):
- return last_temp < target_temp-self.max_delta
+ def check_busy(self, eventtime, smoothed_temp, target_temp):
+ return smoothed_temp < target_temp-self.max_delta
######################################################################
@@ -161,7 +172,7 @@ class ControlPID:
self.Kp = config.getfloat('pid_Kp') / PID_PARAM_BASE
self.Ki = config.getfloat('pid_Ki') / PID_PARAM_BASE
self.Kd = config.getfloat('pid_Kd') / PID_PARAM_BASE
- self.min_deriv_time = config.getfloat('pid_deriv_time', 2., above=0.)
+ self.min_deriv_time = heater.get_smooth_time()
imax = config.getfloat('pid_integral_max', self.heater_max_power,
minval=0.)
self.temp_integ_max = imax / self.Ki
@@ -194,8 +205,8 @@ class ControlPID:
self.prev_temp_deriv = temp_deriv
if co == bounded_co:
self.prev_temp_integ = temp_integ
- def check_busy(self, eventtime, last_temp, target_temp):
- temp_diff = target_temp - last_temp
+ def check_busy(self, eventtime, smoothed_temp, target_temp):
+ temp_diff = target_temp - smoothed_temp
return (abs(temp_diff) > PID_SETTLE_DELTA
or abs(self.prev_temp_deriv) > PID_SETTLE_SLOPE)