temperature_fan: Fix. Temperature fan min speed should be used (#1405)

Signed-off-by: Douglas Hammond <wizhippo@gmail.com>
This commit is contained in:
Douglas Hammond 2019-03-28 14:07:40 -04:00 committed by KevinOConnor
parent 5913170b6b
commit c105adc80b
3 changed files with 27 additions and 15 deletions

View File

@ -626,20 +626,20 @@
# The default is 1.0. # The default is 1.0.
#min_speed: 0.3 #min_speed: 0.3
# The minimum fan speed (expressed as a value from 0.0 to 1.0) that # The minimum fan speed (expressed as a value from 0.0 to 1.0) that
# the fan will be set to when the sensor temperature is the set # the fan will be set to for PID temperature fans.
# value. The default is 0.3. # The default is 0.3.
#control: watermark #control: watermark
# Control algorithm (either watermark or pid). This parameter must # Control algorithm (either watermark or pid). This parameter must
# be provided. # be provided.
#pid_Kp: 40 #pid_Kp: 40
# Kp is the "proportional" constant for the pid. This parameter must # Kp is the "proportional" constant for the pid. This parameter must
# be provided for PID heaters. # be provided for PID temperature fans.
#pid_Ki: 0.2 #pid_Ki: 0.2
# Ki is the "integral" constant for the pid. This parameter must be # Ki is the "integral" constant for the pid. This parameter must be
# provided for PID heaters. # provided for PID temperature fans.
#pid_Kd: 0.1 #pid_Kd: 0.1
# Kd is the "derivative" constant for the pid. This parameter must # Kd is the "derivative" constant for the pid. This parameter must
# be provided for PID heaters. # be provided for PID temperature fans.
#pid_deriv_time: 2.0 #pid_deriv_time: 2.0
# A time value (in seconds) over which the derivative in the pid # A time value (in seconds) over which the derivative in the pid
# will be smoothed to reduce the impact of measurement noise. The # will be smoothed to reduce the impact of measurement noise. The

View File

@ -6,6 +6,10 @@ All dates in this document are approximate.
# Changes # Changes
20190328: The min_speed value in [temperature_fan] config
will now be respected and the fan will always run at this
speed or higher in PID mode.
20190322: The default value for "driver_HEND" in [tmc2660] config 20190322: The default value for "driver_HEND" in [tmc2660] config
sections was changed from 6 to 3. The "driver_VSENSE" field was sections was changed from 6 to 3. The "driver_VSENSE" field was
removed (it is now automatically calculated from run_current). removed (it is now automatically calculated from run_current).

28
klippy/extras/temperature_fan.py Normal file → Executable file
View File

@ -15,7 +15,6 @@ class TemperatureFan:
self.name = config.get_name().split()[1] self.name = config.get_name().split()[1]
self.printer = config.get_printer() self.printer = config.get_printer()
self.fan = fan.PrinterFan(config, default_shutdown_speed=1.) self.fan = fan.PrinterFan(config, default_shutdown_speed=1.)
self.mcu = self.fan.mcu_fan.get_mcu()
self.min_temp = config.getfloat('min_temp', minval=KELVIN_TO_CELCIUS) self.min_temp = config.getfloat('min_temp', minval=KELVIN_TO_CELCIUS)
self.max_temp = config.getfloat('max_temp', above=self.min_temp) self.max_temp = config.getfloat('max_temp', above=self.min_temp)
self.sensor = self.printer.lookup_object('heater').setup_sensor(config) self.sensor = self.printer.lookup_object('heater').setup_sensor(config)
@ -36,8 +35,10 @@ class TemperatureFan:
self.next_speed_time = 0. self.next_speed_time = 0.
self.last_speed_value = 0. self.last_speed_value = 0.
def set_speed(self, read_time, value): def set_speed(self, read_time, value):
if value < self.min_speed: if value <= 0.:
value = 0. value = 0.
elif value < self.min_speed:
value = self.min_speed
if self.target_temp <= 0.: if self.target_temp <= 0.:
value = 0. value = 0.
if ((read_time < self.next_speed_time or not self.last_speed_value) if ((read_time < self.next_speed_time or not self.last_speed_value)
@ -53,6 +54,10 @@ class TemperatureFan:
self.control.temperature_callback(read_time, temp) self.control.temperature_callback(read_time, temp)
def get_temp(self, eventtime): def get_temp(self, eventtime):
return self.last_temp, self.target_temp return self.last_temp, self.target_temp
def get_min_speed(self):
return self.min_speed
def get_max_speed(self):
return self.max_speed
###################################################################### ######################################################################
# Bang-bang control algo # Bang-bang control algo
@ -64,17 +69,18 @@ class ControlBangBang:
self.max_delta = config.getfloat('max_delta', 2.0, above=0.) self.max_delta = config.getfloat('max_delta', 2.0, above=0.)
self.heating = False self.heating = False
def temperature_callback(self, read_time, temp): def temperature_callback(self, read_time, temp):
current_temp, target_temp = self.temperature_fan.get_temp(read_time)
if (self.heating if (self.heating
and temp >= self.temperature_fan.target_temp+self.max_delta): and temp >= target_temp+self.max_delta):
self.heating = False self.heating = False
elif (not self.heating elif (not self.heating
and temp <= self.temperature_fan.target_temp-self.max_delta): and temp <= target_temp-self.max_delta):
self.heating = True self.heating = True
if self.heating: if self.heating:
self.temperature_fan.set_speed(read_time, 0.) self.temperature_fan.set_speed(read_time, 0.)
else: else:
self.temperature_fan.set_speed(read_time, self.temperature_fan.set_speed(read_time,
self.temperature_fan.max_speed) self.temperature_fan.get_max_speed())
###################################################################### ######################################################################
# Proportional Integral Derivative (PID) control algo # Proportional Integral Derivative (PID) control algo
@ -90,14 +96,15 @@ class ControlPID:
self.Ki = config.getfloat('pid_Ki') / PID_PARAM_BASE self.Ki = config.getfloat('pid_Ki') / PID_PARAM_BASE
self.Kd = config.getfloat('pid_Kd') / 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 = config.getfloat('pid_deriv_time', 2., above=0.)
imax = config.getfloat('pid_integral_max', temperature_fan.max_speed, imax = config.getfloat('pid_integral_max',
minval=0.) self.temperature_fan.get_max_speed(), minval=0.)
self.temp_integ_max = imax / self.Ki self.temp_integ_max = imax / self.Ki
self.prev_temp = AMBIENT_TEMP self.prev_temp = AMBIENT_TEMP
self.prev_temp_time = 0. self.prev_temp_time = 0.
self.prev_temp_deriv = 0. self.prev_temp_deriv = 0.
self.prev_temp_integ = 0. self.prev_temp_integ = 0.
def temperature_callback(self, read_time, temp): def temperature_callback(self, read_time, temp):
current_temp, target_temp = self.temperature_fan.get_temp(read_time)
time_diff = read_time - self.prev_temp_time time_diff = read_time - self.prev_temp_time
# Calculate change of temperature # Calculate change of temperature
temp_diff = temp - self.prev_temp temp_diff = temp - self.prev_temp
@ -107,14 +114,15 @@ class ControlPID:
temp_deriv = (self.prev_temp_deriv * (self.min_deriv_time-time_diff) temp_deriv = (self.prev_temp_deriv * (self.min_deriv_time-time_diff)
+ temp_diff) / self.min_deriv_time + temp_diff) / self.min_deriv_time
# Calculate accumulated temperature "error" # Calculate accumulated temperature "error"
temp_err = self.temperature_fan.target_temp - temp temp_err = target_temp - temp
temp_integ = self.prev_temp_integ + temp_err * time_diff temp_integ = self.prev_temp_integ + temp_err * time_diff
temp_integ = max(0., min(self.temp_integ_max, temp_integ)) temp_integ = max(0., min(self.temp_integ_max, temp_integ))
# Calculate output # Calculate output
co = self.Kp*temp_err + self.Ki*temp_integ - self.Kd*temp_deriv co = self.Kp*temp_err + self.Ki*temp_integ - self.Kd*temp_deriv
bounded_co = max(0., min(self.temperature_fan.max_speed, co)) bounded_co = max(0., min(self.temperature_fan.get_max_speed(), co))
self.temperature_fan.set_speed( self.temperature_fan.set_speed(
read_time, self.temperature_fan.max_speed - bounded_co) read_time, max(self.temperature_fan.get_min_speed(),
self.temperature_fan.get_max_speed() - bounded_co))
# Store state for next measurement # Store state for next measurement
self.prev_temp = temp self.prev_temp = temp
self.prev_temp_time = read_time self.prev_temp_time = read_time