diff --git a/config/example-extras.cfg b/config/example-extras.cfg index e72e4645..2d9387ee 100644 --- a/config/example-extras.cfg +++ b/config/example-extras.cfg @@ -626,20 +626,20 @@ # The default is 1.0. #min_speed: 0.3 # 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 -# value. The default is 0.3. +# the fan will be set to for PID temperature fans. +# The default is 0.3. #control: watermark # Control algorithm (either watermark or pid). This parameter must # be provided. #pid_Kp: 40 # 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 # 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 # 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 # A time value (in seconds) over which the derivative in the pid # will be smoothed to reduce the impact of measurement noise. The diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md index c632ebf4..04e6499f 100644 --- a/docs/Config_Changes.md +++ b/docs/Config_Changes.md @@ -6,6 +6,10 @@ All dates in this document are approximate. # 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 sections was changed from 6 to 3. The "driver_VSENSE" field was removed (it is now automatically calculated from run_current). diff --git a/klippy/extras/temperature_fan.py b/klippy/extras/temperature_fan.py old mode 100644 new mode 100755 index f699e4fb..56fe76c9 --- a/klippy/extras/temperature_fan.py +++ b/klippy/extras/temperature_fan.py @@ -15,7 +15,6 @@ class TemperatureFan: self.name = config.get_name().split()[1] self.printer = config.get_printer() 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.max_temp = config.getfloat('max_temp', above=self.min_temp) self.sensor = self.printer.lookup_object('heater').setup_sensor(config) @@ -36,8 +35,10 @@ class TemperatureFan: self.next_speed_time = 0. self.last_speed_value = 0. def set_speed(self, read_time, value): - if value < self.min_speed: + if value <= 0.: value = 0. + elif value < self.min_speed: + value = self.min_speed if self.target_temp <= 0.: value = 0. 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) def get_temp(self, eventtime): 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 @@ -64,17 +69,18 @@ class ControlBangBang: self.max_delta = config.getfloat('max_delta', 2.0, above=0.) self.heating = False def temperature_callback(self, read_time, temp): + current_temp, target_temp = self.temperature_fan.get_temp(read_time) if (self.heating - and temp >= self.temperature_fan.target_temp+self.max_delta): + and temp >= target_temp+self.max_delta): self.heating = False elif (not self.heating - and temp <= self.temperature_fan.target_temp-self.max_delta): + and temp <= target_temp-self.max_delta): self.heating = True if self.heating: self.temperature_fan.set_speed(read_time, 0.) else: self.temperature_fan.set_speed(read_time, - self.temperature_fan.max_speed) + self.temperature_fan.get_max_speed()) ###################################################################### # Proportional Integral Derivative (PID) control algo @@ -90,14 +96,15 @@ class ControlPID: 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.) - imax = config.getfloat('pid_integral_max', temperature_fan.max_speed, - minval=0.) + imax = config.getfloat('pid_integral_max', + self.temperature_fan.get_max_speed(), minval=0.) self.temp_integ_max = imax / self.Ki self.prev_temp = AMBIENT_TEMP self.prev_temp_time = 0. self.prev_temp_deriv = 0. self.prev_temp_integ = 0. 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 # Calculate change of temperature 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_diff) / self.min_deriv_time # 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 = max(0., min(self.temp_integ_max, temp_integ)) # Calculate output 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( - 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 self.prev_temp = temp self.prev_temp_time = read_time