diff --git a/README.md b/README.md index 3c7b78cd5..281383cf6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Our goal is to support features and behavior that could be "risky" if used incor If I want my printer to light itself on fire, I should be able to make my printer light itself on fire. ## Features merged into the master branch: -- [heater: Dual Loop PID](https://github.com/DangerKlippers/danger-klipper/issues/58) ([klipper#5972](https://github.com/Klipper3d/klipper/pull/5972)) - [core: no Python2 tests; no PRU boards](https://github.com/DangerKlippers/danger-klipper/pull/39) @@ -23,6 +22,8 @@ If I want my printer to light itself on fire, I should be able to make my printe - [heater: velocity PID](https://github.com/DangerKlippers/danger-klipper/pull/47) ([klipper#6272](https://github.com/Klipper3d/klipper/pull/6272)) +- [heater: Dual Loop PID](https://github.com/DangerKlippers/danger-klipper/issues/58) ([klipper#5972](https://github.com/Klipper3d/klipper/pull/5972)) + - [gcode: jinja2.ext.do extension](https://github.com/DangerKlippers/danger-klipper/pull/26) ([klipper#5149](https://github.com/Klipper3d/klipper/pull/5149)) - [gcode: gcode_shell_command](https://github.com/DangerKlippers/danger-klipper/pull/26) ([klipper#2173](https://github.com/Klipper3d/klipper/pull/2173) / [kiuah](https://github.com/dw-0/kiauh/blob/master/resources/gcode_shell_command.py) ) diff --git a/klippy/extras/pid_calibrate.py b/klippy/extras/pid_calibrate.py index c4cb89140..690d53fe9 100644 --- a/klippy/extras/pid_calibrate.py +++ b/klippy/extras/pid_calibrate.py @@ -21,8 +21,14 @@ def __init__(self, config): cmd_PID_CALIBRATE_help = "Run PID calibration test" def _calibrate( - self, pheaters, heater, target, tolerance, fname, gcmd, - calibrate_secondary + self, + pheaters, + heater, + target, + tolerance, + fname, + gcmd, + calibrate_secondary, ): if ( isinstance(heater.control, heaters.ControlDualLoopPID) @@ -48,9 +54,7 @@ def _calibrate( calibrate_secondary=calibrate_secondary, ) else: - calibrate = ControlAutoTune(heater, - target, - tolerance) + calibrate = ControlAutoTune(heater, target, tolerance) old_control = heater.set_control(calibrate) try: @@ -84,7 +88,13 @@ def cmd_PID_CALIBRATE(self, gcmd): if isinstance(heater.control, heaters.ControlDualLoopPID): fname = "/tmp/heattest_secondary.txt" if write_file else None kp_s, ki_s, kd_s, _ = self._calibrate( - pheaters, heater, target, tolerance, fname, gcmd, calibrate_secondary=True + pheaters, + heater, + target, + tolerance, + fname, + gcmd, + calibrate_secondary=True, ) old_kp = heater.control.secondary_pid.Kp old_ki = heater.control.secondary_pid.Ki @@ -95,7 +105,13 @@ def cmd_PID_CALIBRATE(self, gcmd): fname = "/tmp/heattest_primary.txt" if write_file else None kp_p, ki_p, kd_p, _ = self._calibrate( - pheaters, heater, target, tolerance, fname, gcmd, calibrate_secondary=False + pheaters, + heater, + target, + tolerance, + fname, + gcmd, + calibrate_secondary=False, ) heater.control.secondary_pid.kp = old_kp @@ -122,7 +138,13 @@ def cmd_PID_CALIBRATE(self, gcmd): else: fname = "/tmp/heattest.txt" if write_file else None Kp, Ki, Kd, old_control = self._calibrate( - pheaters, heater, target, tolerance, fname, gcmd, calibrate_secondary=False + pheaters, + heater, + target, + tolerance, + fname, + gcmd, + calibrate_secondary=False, ) logging.info("Autotune: final: Kp=%f Ki=%f Kd=%f", Kp, Ki, Kd) gcmd.respond_info( @@ -138,6 +160,7 @@ def cmd_PID_CALIBRATE(self, gcmd): configfile.set(heater_name, "pid_Ki", "%.3f" % (Ki,)) configfile.set(heater_name, "pid_Kd", "%.3f" % (Kd,)) + TUNE_PID_DELTA = 5.0 TUNE_PID_TOL = 0.02 TUNE_PID_SAMPLES = 3 @@ -145,7 +168,9 @@ def cmd_PID_CALIBRATE(self, gcmd): class ControlAutoTune: - def __init__(self, heater, target, tolerance, control=None, calibrate_secondary=False): + def __init__( + self, heater, target, tolerance, control=None, calibrate_secondary=False + ): self.heater = heater self.heater_max_power = heater.get_max_power() # store the reference so we can push messages if needed @@ -185,8 +210,9 @@ def __init__(self, heater, target, tolerance, control=None, calibrate_secondary= self._control = control self._calibrate_secondary = calibrate_secondary - def temperature_update(self, read_time, primary_temp, target_temp, - secondary_temp=None): + def temperature_update( + self, read_time, primary_temp, target_temp, secondary_temp=None + ): if self._calibrate_secondary: ref_temp = secondary_temp @@ -201,7 +227,11 @@ def temperature_update(self, read_time, primary_temp, target_temp, (read_time, ref_temp, self.heater.last_pwm_value, self.target) ) # ensure the starting temp is low enough to run the test. - if not self.started and ref_temp >= self.temp_low and self._control is None: + if ( + not self.started + and ref_temp >= self.temp_low + and self._control is None + ): self.errored = True self.finish(read_time) self.gcode.respond_info("temperature to high to start calibration") @@ -253,8 +283,10 @@ def temperature_update(self, read_time, primary_temp, target_temp, if self._control is not None and not self._calibrate_secondary: pid = self._control.secondary_pid sec_target = self._control.sec_max_temp_target - _, bounded_co = pid.calculate_output(read_time, secondary_temp, - sec_target) + _, bounded_co = pid.calculate_output( + read_time, secondary_temp, sec_target + ) + bounded_co = min(bounded_co, self.powers[-1]) self.heater.set_pwm(read_time, bounded_co) else: self.heater.set_pwm(read_time, self.powers[-1]) diff --git a/test/klippy/dual_loop_pid.cfg b/test/klippy/dual_loop_pid.cfg new file mode 100644 index 000000000..408858fb9 --- /dev/null +++ b/test/klippy/dual_loop_pid.cfg @@ -0,0 +1,80 @@ +# Config for extruder testing +[stepper_x] +step_pin: PF0 +dir_pin: PF1 +enable_pin: !PD7 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PE5 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_y] +step_pin: PF6 +dir_pin: !PF7 +enable_pin: !PF2 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PJ1 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_z] +step_pin: PL3 +dir_pin: PL1 +enable_pin: !PK0 +microsteps: 16 +rotation_distance: 8 +endstop_pin: ^PD3 +position_endstop: 0.5 +position_max: 200 + +[temperature_sensor myExtraSensor] +sensor_type: Generic 3950 +sensor_pin: PF4 +min_temp: 0 +max_temp: 80 + +[extruder] +step_pin: PA4 +dir_pin: PA6 +enable_pin: !PA2 +microsteps: 16 +rotation_distance: 33.5 +nozzle_diameter: 0.500 +filament_diameter: 3.500 +heater_pin: PB4 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PK5 +min_temp: 0 +max_temp: 400 + +secondary_sensor_name: myExtraSensor +secondary_max_temp_target: 280 +control: dual_loop_pid +primary_pid_kp: 22.2 +primary_pid_ki: 1.08 +primary_pid_kd: 114 +secondary_pid_kp: 22.2 +secondary_pid_ki: 1.08 +secondary_pid_kd: 114 + +[extruder_stepper my_extra_stepper] +extruder: extruder +step_pin: PH5 +dir_pin: PH6 +enable_pin: !PB5 +microsteps: 16 +rotation_distance: 28.2 + +[mcu] +serial: /dev/ttyACM0 + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 5 +max_z_accel: 100 diff --git a/test/klippy/dual_loop_pid.test b/test/klippy/dual_loop_pid.test new file mode 100644 index 000000000..5eff019c2 --- /dev/null +++ b/test/klippy/dual_loop_pid.test @@ -0,0 +1,13 @@ +# Pid hot modify tests +DICTIONARY atmega2560.dict +CONFIG dual_loop_pid.cfg + +# Extrude only +G1 E5 +G1 E-2 +G1 E7 + +# Home and extrusion moves +G28 +G1 X20 Y20 Z1 +G1 X25 Y25 E7.5