diff --git a/docs/G-Codes.md b/docs/G-Codes.md index 0c93f21db143..ca302dc24987 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -989,15 +989,20 @@ in the config file. #### PID_PROFILE `PID_PROFILE LOAD= HEATER= [DEFAULT=] -[VERBOSE=] [RESET_TARGET=0|1]`: +[VERBOSE=] [RESET_TARGET=0|1] [LOAD_CLEAN=0|1]`: Loads the given PID_PROFILE for the specified heater. If DEFAULT is specified, the Profile specified in DEFAULT will be loaded when then given Profile for LOAD can't be found (like a getOrDefault method). If VERBOSE is set to LOW, minimal info will be written in console. If set to NONE, no console outputs will be given. -If RESET_TARGET is set to 1, the target temperature of the heater will be set -to 0 when changing profiles. -By default the target temperature of the heater will not be reset. +If KEEP_TARGET is set to 1, the heater will keep it's target temperature, +if set to 0, the target temperature will be set to 0. +By default the target temperature of the heater will be set to 0 so the +algorithm has time to settle in. +If LOAD_CLEAN is set to 1, the profile would be loaded as if the printer just +started up, if set to 0, the profile will retain previous heating information. +By default the information will be kept to reduce overshoot, change this value +if you encounter weird behaviour while switching profiles. `PID_PROFILE SAVE= HEATER=`: Saves the currently loaded profile of the specified heater to the config under @@ -1011,9 +1016,14 @@ CONTROL= KP= KI= KD= [RESET_TARGET=0|1]`: Creates a new profile with the given PID values, CONTROL must either be `pid` or `pid_v`, TOLERANCE and TARGET must be specified to create a valid profile, though the values themselves don't matter. -If RESET_TARGET is set to 1, the target temperature of the heater will be set -to 0 when setting the values. -By default the target temperature of the heater will not be reset. +If KEEP_TARGET is set to 1, the heater will keep it's target temperature, +if set to 0, the target temperature will be set to 0. +By default the target temperature of the heater will be set to 0 so the +algorithm has time to settle in. +If LOAD_CLEAN is set to 1, the profile would be loaded as if the printer just +started up, if set to 0, the profile will retain previous heating information. +By default the information will be kept to reduce overshoot, change this value +if you encounter weird behaviour while switching profiles. diff --git a/klippy/extras/heaters.py b/klippy/extras/heaters.py index bff481ad7b9e..56bc1d4eb1c7 100644 --- a/klippy/extras/heaters.py +++ b/klippy/extras/heaters.py @@ -101,7 +101,7 @@ def __init__(self, config, sensor): self.pmgr.cmd_PID_PROFILE, desc= self.pmgr.cmd_PID_PROFILE_help) - def lookup_control(self, profile, reset_temp=True): + def lookup_control(self, profile, load_clean=True): algos = collections.OrderedDict({ 'watermark': ControlBangBang, 'pid': ControlPID, @@ -110,7 +110,7 @@ def lookup_control(self, profile, reset_temp=True): return algos[profile['control']](profile, self, None - if reset_temp else + if load_clean else self.get_temp(self.reactor.monotonic()) ) def set_pwm(self, read_time, value): @@ -165,11 +165,11 @@ def check_busy(self, eventtime): with self.lock: return self.control.check_busy( eventtime, self.smoothed_temp, self.target_temp) - def set_control(self, control, reset_target=False): + def set_control(self, control, keep_target=True): with self.lock: old_control = self.control self.control = control - if reset_target: + if not keep_target: self.target_temp = 0. return old_control def get_control(self): @@ -294,11 +294,24 @@ def _compute_section_name(self, profile_name): + " " + profile_name) ) - def _check_value_gcmd(self, name, default, gcmd, type, can_be_none): + def _check_value_gcmd(self, + name, + default, + gcmd, + type, + can_be_none, + minval=None, + maxval=None, ): if type is int: - value = gcmd.get_int(name, default) + value = gcmd.get_int(name, + default, + minval=minval, + maxval=maxval) elif type is float: - value = gcmd.get_float(name, default) + value = gcmd.get_float(name, + default, + minval=minval, + maxval=maxval) else: value = gcmd.get(name, default) if not can_be_none and value is None: @@ -347,11 +360,20 @@ def set_values(self, profile_name, gcmd, verbose): gcmd, float, True) - reset_target = self._check_value_gcmd('RESET_TARGET', - 0, - gcmd, - int, - False) + keep_target = self._check_value_gcmd('KEEP_TARGET', + 0, + gcmd, + int, + True, + minval=0, + maxval=1) + load_clean = self._check_value_gcmd('LOAD_CLEAN', + 0, + gcmd, + int, + True, + minval=0, + maxval=1) temp_profile = {'pid_target': target, 'pid_tolerance': tolerance, 'control': control, @@ -360,8 +382,8 @@ def set_values(self, profile_name, gcmd, verbose): 'pid_ki': ki, 'pid_kd': kd} temp_control = self.outer_instance.lookup_control(temp_profile, - False) - self.outer_instance.set_control(temp_control, reset_target) + load_clean) + self.outer_instance.set_control(temp_control, keep_target) msg = ("PID Parameters:\n" "Target: %.2f,\n" "Tolerance: %.4f\n" @@ -427,21 +449,30 @@ def load_profile(self, profile_name, gcmd, verbose): gcmd, 'lower', True) + load_clean = self._check_value_gcmd('LOAD_CLEAN', + 0, + gcmd, + int, + True, + minval=0, + maxval=1) if (profile_name == self.outer_instance.get_control().get_profile()['name'] - and - (verbose == 'high' or verbose == 'low')): - self.outer_instance.gcode.respond_info( - "PID Profile [%s] already loaded for heater [%s]." - % (profile_name, self.outer_instance.name) - ) + and not load_clean): + if verbose == 'high' or verbose == 'low': + self.outer_instance.gcode.respond_info( + "PID Profile [%s] already loaded for heater [%s]." + % (profile_name, self.outer_instance.name) + ) return - reset_target = self._check_value_gcmd('RESET_TARGET', - 0, - gcmd, - int, - True) + keep_target = self._check_value_gcmd('KEEP_TARGET', + 0, + gcmd, + int, + True, + minval=0, + maxval=1) profile = self.profiles.get(profile_name, None) defaulted = False default = gcmd.get('DEFAULT', None) @@ -460,8 +491,8 @@ def load_profile(self, profile_name, gcmd, verbose): % (default, self.outer_instance.name) ) - control = self.outer_instance.lookup_control(profile, False) - self.outer_instance.set_control(control, reset_target) + control = self.outer_instance.lookup_control(profile, load_clean) + self.outer_instance.set_control(control, keep_target) if verbose != 'high' and verbose != 'low': return diff --git a/klippy/extras/pid_calibrate.py b/klippy/extras/pid_calibrate.py index 521d8affdaba..93a7b8de9d6f 100644 --- a/klippy/extras/pid_calibrate.py +++ b/klippy/extras/pid_calibrate.py @@ -27,11 +27,11 @@ def cmd_PID_CALIBRATE(self, gcmd): raise gcmd.error(str(e)) self.printer.lookup_object('toolhead').get_last_move_time() calibrate = ControlAutoTune(heater, target, tolerance, tune_pid_delta) - old_control = heater.set_control(calibrate, True) + old_control = heater.set_control(calibrate, False) try: pheaters.set_temperature(heater, target, True) except self.printer.command_error as e: - heater.set_control(old_control, True) + heater.set_control(old_control, False) raise if write_file: calibrate.write_file('/tmp/heattest.csv') @@ -58,7 +58,7 @@ def cmd_PID_CALIBRATE(self, gcmd): 'smooth_time': None, 'name': profile_name} - heater.set_control(heater.lookup_control(profile, True), True) + heater.set_control(heater.lookup_control(profile, True), False) heater.pmgr.save_profile(profile_name=profile_name, verbose=False) TUNE_PID_TOL = 0.02