diff --git a/overlays/firmware-extended/20-klipper-patches/README.md b/overlays/firmware-extended/20-klipper-patches/README.md new file mode 100644 index 00000000..3c61b0e0 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/README.md @@ -0,0 +1,12 @@ +# This overlay integrates upstream klipper changes + +## Upstream commmits: + +1. [toolhead: Reduce LOOKAHEAD_FLUSH_TIME to 0.150 seconds](https://github.com/Klipper3d/klipper/commit/16fc46fe5) +1. [resonance_tester: Fix chips selection, add accel_per_hz selection](https://github.com/Klipper3d/klipper/commit/6d1256ddc) +1. [resonance_tester: Added a new sweeping_vibrations resonance test method](https://github.com/Klipper3d/klipper/commit/16b4b6b30) + +## Formatting of patches + +Patches are ordered, they are stripped of config changes, and minimal amount of amendments are done +to make them as close to upstream as possible. diff --git a/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/01_16fc46fe5.patch b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/01_16fc46fe5.patch new file mode 100644 index 00000000..5d032624 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/01_16fc46fe5.patch @@ -0,0 +1,29 @@ +From 16fc46fe5ff0dbbc5188ee6a7829eee5976c1eb9 Mon Sep 17 00:00:00 2001 +From: Kevin O'Connor +Date: Tue, 30 Sep 2025 19:32:49 -0400 +Subject: [PATCH] toolhead: Reduce LOOKAHEAD_FLUSH_TIME to 0.150 seconds + +The current code is likely to perform a lazy flush of the lookahead +queue around 4 times a second. Increase that to around 6-7 times a +second. This change may slightly improve the responsiveness to user +requests mid-print (eg, changing extrusion ratio) and may make a +"print stall" less likely in some corner cases. + +Signed-off-by: Kevin O'Connor +--- + klippy/toolhead.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/klippy/toolhead.py b/klippy/toolhead.py +index 9163e82cc7a8..da297e966be4 100644 +--- a/klippy/toolhead.py ++++ b/klippy/toolhead.py +@@ -113,7 +113,7 @@ def set_junction(self, start_v2, cruise_v2, end_v2): + self.cruise_t = cruise_d / cruise_v + self.decel_t = decel_d / ((end_v + cruise_v) * 0.5) + +-LOOKAHEAD_FLUSH_TIME = 0.250 ++LOOKAHEAD_FLUSH_TIME = 0.150 + + # Class to track a list of pending move requests and to facilitate + # "look-ahead" across moves to reduce acceleration between moves. diff --git a/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/02_6d1256ddc.patch b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/02_6d1256ddc.patch new file mode 100644 index 00000000..e9ea9c41 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/02_6d1256ddc.patch @@ -0,0 +1,46 @@ +From 6d1256ddcc51cc62ab403fdc29d0b2688116a29e Mon Sep 17 00:00:00 2001 +From: MRX8024 <57844100+MRX8024@users.noreply.github.com> +Date: Wed, 13 Nov 2024 02:55:32 +0200 +Subject: [PATCH] resonance_tester: Fix chips selection, add accel_per_hz + selection (#6726) + +Corrected issue where accelerometer names were incorrectly prefixed +with "adxl345", preventing the selection of other chip types when running TEST_RESONANCES. + +Implemented support for selecting the `accel_per_hz` parameter when running TEST_RESONANCES. + +docs: Update TEST_RESONANCES + SHAPER_CALIBRATE with missing parameters and bracket corrections + +Signed-off-by: Maksim Bolgov +--- + docs/Config_Changes.md | 4 ++++ + docs/G-Codes.md | 18 +++++++++--------- + klippy/extras/resonance_tester.py | 8 +++----- + 3 files changed, 16 insertions(+), 14 deletions(-) + +diff --git a/klippy/extras/resonance_tester.py b/klippy/extras/resonance_tester.py +index fe8717d58545..e9d4e9d92c53 100644 +--- a/klippy/extras/resonance_tester.py ++++ b/klippy/extras/resonance_tester.py +@@ -65,6 +65,8 @@ def prepare_test(self, gcmd): + self.freq_start = gcmd.get_float("FREQ_START", self.min_freq, minval=1.) + self.freq_end = gcmd.get_float("FREQ_END", self.max_freq, + minval=self.freq_start, maxval=300.) ++ self.accel_per_hz = gcmd.get_float("ACCEL_PER_HZ", ++ self.accel_per_hz, above=0.) + self.hz_per_sec = gcmd.get_float("HZ_PER_SEC", self.hz_per_sec, + above=0., maxval=2.) + def run_test(self, axis, gcmd): +@@ -212,11 +214,7 @@ def _run_test(self, gcmd, axes, helper, raw_name_suffix=None, + def _parse_chips(self, accel_chips): + parsed_chips = [] + for chip_name in accel_chips.split(','): +- if "adxl345" in chip_name: +- chip_lookup_name = chip_name.strip() +- else: +- chip_lookup_name = "adxl345 " + chip_name.strip(); +- chip = self.printer.lookup_object(chip_lookup_name) ++ chip = self.printer.lookup_object(chip_name.strip()) + parsed_chips.append(chip) + return parsed_chips + def _get_max_calibration_freq(self): diff --git a/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/03_8291788.patch b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/03_8291788.patch new file mode 100644 index 00000000..17c7e112 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/03_8291788.patch @@ -0,0 +1,37 @@ +From 8291788f40a677b11d6e0e0283411bc5f96936f7 Mon Sep 17 00:00:00 2001 +From: Kevin O'Connor +Date: Wed, 27 Nov 2024 22:45:27 -0500 +Subject: [PATCH] toolhead: Use delta_v2 when calculating centripetal force + +As a minor math optimization, it's possible to calculate: + .5 * self.move_d * self.accel * tan_theta_d2 +using: + self.delta_v2 * .25 * tan_theta_d2 +because self.delta_v2 is "2. * self.move_d * self.accel". + +Signed-off-by: Dmitry Butyugin +Signed-off-by: Kevin O'Connor +--- + klippy/toolhead.py | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/klippy/toolhead.py b/klippy/toolhead.py +index 4149d53b12f6..948ea974fd70 100644 +--- a/klippy/toolhead.py ++++ b/klippy/toolhead.py +@@ -76,10 +76,11 @@ def calc_junction(self, prev_move): + sin_theta_d2 = math.sqrt(0.5*(1.0-junction_cos_theta)) + R_jd = sin_theta_d2 / (1. - sin_theta_d2) + # Approximated circle must contact moves no further away than mid-move +- tan_theta_d2 = sin_theta_d2 / math.sqrt(0.5*(1.0+junction_cos_theta)) +- move_centripetal_v2 = .5 * self.move_d * tan_theta_d2 * self.accel +- prev_move_centripetal_v2 = (.5 * prev_move.move_d * tan_theta_d2 +- * prev_move.accel) ++ # centripetal_v2 = .5 * self.move_d * self.accel * tan_theta_d2 ++ cos_theta_d2 = math.sqrt(0.5*(1.0+junction_cos_theta)) ++ quarter_tan_theta_d2 = .25 * sin_theta_d2 / cos_theta_d2 ++ move_centripetal_v2 = self.delta_v2 * quarter_tan_theta_d2 ++ prev_move_centripetal_v2 = prev_move.delta_v2 * quarter_tan_theta_d2 + # Apply limits + self.max_start_v2 = min( + R_jd * self.junction_deviation * self.accel, diff --git a/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/04_847331260.patch b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/04_847331260.patch new file mode 100644 index 00000000..063b8141 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/04_847331260.patch @@ -0,0 +1,80 @@ +From 847331260c84e9de00404aa98f0029184150a897 Mon Sep 17 00:00:00 2001 +From: Kevin O'Connor +Date: Wed, 27 Nov 2024 22:34:17 -0500 +Subject: [PATCH] toolhead: Remove arbitrary constants controlling junction + deviation + +When calculating the junction speed between two moves the code checked +for angles greater than 0.999999 or less than -0.999999 to avoid math +issues (sqrt of a negative number and/or divide by zero). However, +these arbitrary constants could unnecessarily pessimize junction +speeds when angles are close to 180 or 0 degrees. + +Change the code to explicitly check for negative numbers during sqrt +and to explicilty check for zero values prior to division. This +simplifies the code and avoids unnecessarily reducing some junction +speeds. + +Signed-off-by: Dmitry Butyugin +Signed-off-by: Kevin O'Connor +--- + klippy/toolhead.py | 38 +++++++++++++++++++------------------- + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/klippy/toolhead.py b/klippy/toolhead.py +index 948ea974fd70..ed26092f651d 100644 +--- a/klippy/toolhead.py ++++ b/klippy/toolhead.py +@@ -64,33 +64,33 @@ def calc_junction(self, prev_move): + return + # Allow extruder to calculate its maximum junction + extruder_v2 = self.toolhead.extruder.calc_junction(prev_move, self) ++ max_start_v2 = min( ++ extruder_v2, self.max_cruise_v2, prev_move.max_cruise_v2, ++ prev_move.max_start_v2 + prev_move.delta_v2) + # Find max velocity using "approximated centripetal velocity" + axes_r = self.axes_r + prev_axes_r = prev_move.axes_r + junction_cos_theta = -(axes_r[0] * prev_axes_r[0] + + axes_r[1] * prev_axes_r[1] + + axes_r[2] * prev_axes_r[2]) +- if junction_cos_theta > 0.999999: +- return +- junction_cos_theta = max(junction_cos_theta, -0.999999) +- sin_theta_d2 = math.sqrt(0.5*(1.0-junction_cos_theta)) +- R_jd = sin_theta_d2 / (1. - sin_theta_d2) +- # Approximated circle must contact moves no further away than mid-move +- # centripetal_v2 = .5 * self.move_d * self.accel * tan_theta_d2 +- cos_theta_d2 = math.sqrt(0.5*(1.0+junction_cos_theta)) +- quarter_tan_theta_d2 = .25 * sin_theta_d2 / cos_theta_d2 +- move_centripetal_v2 = self.delta_v2 * quarter_tan_theta_d2 +- prev_move_centripetal_v2 = prev_move.delta_v2 * quarter_tan_theta_d2 ++ sin_theta_d2 = math.sqrt(max(0.5*(1.0-junction_cos_theta), 0.)) ++ cos_theta_d2 = math.sqrt(max(0.5*(1.0+junction_cos_theta), 0.)) ++ one_minus_sin_theta_d2 = 1. - sin_theta_d2 ++ if one_minus_sin_theta_d2 > 0. and cos_theta_d2 > 0.: ++ R_jd = sin_theta_d2 / one_minus_sin_theta_d2 ++ move_jd_v2 = R_jd * self.junction_deviation * self.accel ++ pmove_jd_v2 = R_jd * prev_move.junction_deviation * prev_move.accel ++ # Approximated circle must contact moves no further than mid-move ++ # centripetal_v2 = .5 * self.move_d * self.accel * tan_theta_d2 ++ quarter_tan_theta_d2 = .25 * sin_theta_d2 / cos_theta_d2 ++ move_centripetal_v2 = self.delta_v2 * quarter_tan_theta_d2 ++ pmove_centripetal_v2 = prev_move.delta_v2 * quarter_tan_theta_d2 ++ max_start_v2 = min(max_start_v2, move_jd_v2, pmove_jd_v2, ++ move_centripetal_v2, pmove_centripetal_v2) + # Apply limits +- self.max_start_v2 = min( +- R_jd * self.junction_deviation * self.accel, +- R_jd * prev_move.junction_deviation * prev_move.accel, +- move_centripetal_v2, prev_move_centripetal_v2, +- extruder_v2, self.max_cruise_v2, prev_move.max_cruise_v2, +- prev_move.max_start_v2 + prev_move.delta_v2) ++ self.max_start_v2 = max_start_v2 + self.max_smoothed_v2 = min( +- self.max_start_v2 +- , prev_move.max_smoothed_v2 + prev_move.smooth_delta_v2) ++ max_start_v2, prev_move.max_smoothed_v2 + prev_move.smooth_delta_v2) + def set_junction(self, start_v2, cruise_v2, end_v2): + # Determine accel, cruise, and decel portions of the move distance + half_inv_accel = .5 / self.accel diff --git a/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/05_16b4b6b30.patch b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/05_16b4b6b30.patch new file mode 100644 index 00000000..495530b7 --- /dev/null +++ b/overlays/firmware-extended/20-klipper-patches/patches/home/lava/klipper/05_16b4b6b30.patch @@ -0,0 +1,322 @@ +From 16b4b6b302ac3ffcd55006cd76265aad4e26ecc8 Mon Sep 17 00:00:00 2001 +From: Dmitry Butyugin +Date: Fri, 6 Dec 2024 11:54:26 +0900 +Subject: [PATCH] resonance_tester: Added a new sweeping_vibrations resonance + test method (#6723) + +This adds a new resonance test method that can help if a user has some mechanical problems with the printer. + +Signed-off-by: Dmitry Butyugin +--- + docs/Config_Changes.md | 8 ++ + docs/Config_Reference.md | 12 ++- + docs/Measuring_Resonances.md | 18 ++++ + klippy/extras/resonance_tester.py | 167 ++++++++++++++++++++++-------- + klippy/extras/shaper_calibrate.py | 4 +- + klippy/toolhead.py | 13 ++- + 6 files changed, 171 insertions(+), 51 deletions(-) + +diff --git a/klippy/extras/resonance_tester.py b/klippy/extras/resonance_tester.py +index e9d4e9d92c53..76e56f536b9a 100644 +--- a/klippy/extras/resonance_tester.py ++++ b/klippy/extras/resonance_tester.py +@@ -45,42 +45,96 @@ def _parse_axis(gcmd, raw_axis): + "Unable to parse axis direction '%s'" % (raw_axis,)) + return TestAxis(vib_dir=(dir_x, dir_y)) + +-class VibrationPulseTest: ++class VibrationPulseTestGenerator: + def __init__(self, config): +- self.printer = config.get_printer() +- self.gcode = self.printer.lookup_object('gcode') + self.min_freq = config.getfloat('min_freq', 5., minval=1.) +- # Defaults are such that max_freq * accel_per_hz == 10000 (max_accel) +- self.max_freq = config.getfloat('max_freq', 10000. / 75., ++ self.max_freq = config.getfloat('max_freq', 135., + minval=self.min_freq, maxval=300.) +- self.accel_per_hz = config.getfloat('accel_per_hz', 75., above=0.) ++ self.accel_per_hz = config.getfloat('accel_per_hz', 60., above=0.) + self.hz_per_sec = config.getfloat('hz_per_sec', 1., + minval=0.1, maxval=2.) +- +- self.probe_points = config.getlists('probe_points', seps=(',', '\n'), +- parser=float, count=3) +- def get_start_test_points(self): +- return self.probe_points + def prepare_test(self, gcmd): + self.freq_start = gcmd.get_float("FREQ_START", self.min_freq, minval=1.) + self.freq_end = gcmd.get_float("FREQ_END", self.max_freq, + minval=self.freq_start, maxval=300.) +- self.accel_per_hz = gcmd.get_float("ACCEL_PER_HZ", +- self.accel_per_hz, above=0.) +- self.hz_per_sec = gcmd.get_float("HZ_PER_SEC", self.hz_per_sec, +- above=0., maxval=2.) +- def run_test(self, axis, gcmd): ++ self.test_accel_per_hz = gcmd.get_float("ACCEL_PER_HZ", ++ self.accel_per_hz, above=0.) ++ self.test_hz_per_sec = gcmd.get_float("HZ_PER_SEC", self.hz_per_sec, ++ above=0., maxval=2.) ++ def gen_test(self): ++ freq = self.freq_start ++ res = [] ++ sign = 1. ++ time = 0. ++ while freq <= self.freq_end + 0.000001: ++ t_seg = .25 / freq ++ accel = self.test_accel_per_hz * freq ++ time += t_seg ++ res.append((time, sign * accel, freq)) ++ time += t_seg ++ res.append((time, -sign * accel, freq)) ++ freq += 2. * t_seg * self.test_hz_per_sec ++ sign = -sign ++ return res ++ def get_max_freq(self): ++ return self.freq_end ++ ++class SweepingVibrationsTestGenerator: ++ def __init__(self, config): ++ self.vibration_generator = VibrationPulseTestGenerator(config) ++ self.sweeping_accel = config.getfloat('sweeping_accel', 400., above=0.) ++ self.sweeping_period = config.getfloat('sweeping_period', 1.2, ++ minval=0.) ++ def prepare_test(self, gcmd): ++ self.vibration_generator.prepare_test(gcmd) ++ self.test_sweeping_accel = gcmd.get_float( ++ "SWEEPING_ACCEL", self.sweeping_accel, above=0.) ++ self.test_sweeping_period = gcmd.get_float( ++ "SWEEPING_PERIOD", self.sweeping_period, minval=0.) ++ def gen_test(self): ++ test_seq = self.vibration_generator.gen_test() ++ accel_fraction = math.sqrt(2.0) * 0.125 ++ if self.test_sweeping_period: ++ t_rem = self.test_sweeping_period * accel_fraction ++ sweeping_accel = self.test_sweeping_accel ++ else: ++ t_rem = float('inf') ++ sweeping_accel = 0. ++ res = [] ++ last_t = 0. ++ sig = 1. ++ accel_fraction += 0.25 ++ for next_t, accel, freq in test_seq: ++ t_seg = next_t - last_t ++ while t_rem <= t_seg: ++ last_t += t_rem ++ res.append((last_t, accel + sweeping_accel * sig, freq)) ++ t_seg -= t_rem ++ t_rem = self.test_sweeping_period * accel_fraction ++ accel_fraction = 0.5 ++ sig = -sig ++ t_rem -= t_seg ++ res.append((next_t, accel + sweeping_accel * sig, freq)) ++ last_t = next_t ++ return res ++ def get_max_freq(self): ++ return self.vibration_generator.get_max_freq() ++ ++class ResonanceTestExecutor: ++ def __init__(self, config): ++ self.printer = config.get_printer() ++ self.gcode = self.printer.lookup_object('gcode') ++ def run_test(self, test_seq, axis, gcmd): ++ reactor = self.printer.get_reactor() + toolhead = self.printer.lookup_object('toolhead') + X, Y, Z, E = toolhead.get_position() +- sign = 1. +- freq = self.freq_start + # Override maximum acceleration and acceleration to + # deceleration based on the maximum test frequency +- systime = self.printer.get_reactor().monotonic() ++ systime = reactor.monotonic() + toolhead_info = toolhead.get_status(systime) + old_max_accel = toolhead_info['max_accel'] + old_minimum_cruise_ratio = toolhead_info['minimum_cruise_ratio'] +- max_accel = self.freq_end * self.accel_per_hz ++ max_accel = max([abs(a) for _, a, _ in test_seq]) + self.gcode.run_script_from_command( + "SET_VELOCITY_LIMIT ACCEL=%.3f MINIMUM_CRUISE_RATIO=0" + % (max_accel,)) +@@ -90,24 +144,46 @@ def run_test(self, axis, gcmd): + gcmd.respond_info("Disabled [input_shaper] for resonance testing") + else: + input_shaper = None +- gcmd.respond_info("Testing frequency %.0f Hz" % (freq,)) +- while freq <= self.freq_end + 0.000001: +- t_seg = .25 / freq +- accel = self.accel_per_hz * freq +- max_v = accel * t_seg ++ last_v = last_t = last_accel = last_freq = 0. ++ for next_t, accel, freq in test_seq: ++ t_seg = next_t - last_t + toolhead.cmd_M204(self.gcode.create_gcode_command( +- "M204", "M204", {"S": accel})) +- L = .5 * accel * t_seg**2 +- dX, dY = axis.get_point(L) +- nX = X + sign * dX +- nY = Y + sign * dY +- toolhead.move([nX, nY, Z, E], max_v) +- toolhead.move([X, Y, Z, E], max_v) +- sign = -sign +- old_freq = freq +- freq += 2. * t_seg * self.hz_per_sec +- if math.floor(freq) > math.floor(old_freq): ++ "M204", "M204", {"S": abs(accel)})) ++ v = last_v + accel * t_seg ++ abs_v = abs(v) ++ if abs_v < 0.000001: ++ v = abs_v = 0. ++ abs_last_v = abs(last_v) ++ v2 = v * v ++ last_v2 = last_v * last_v ++ half_inv_accel = .5 / accel ++ d = (v2 - last_v2) * half_inv_accel ++ dX, dY = axis.get_point(d) ++ nX = X + dX ++ nY = Y + dY ++ toolhead.limit_next_junction_speed(abs_last_v) ++ if v * last_v < 0: ++ # The move first goes to a complete stop, then changes direction ++ d_decel = -last_v2 * half_inv_accel ++ decel_X, decel_Y = axis.get_point(d_decel) ++ toolhead.move([X + decel_X, Y + decel_Y, Z, E], abs_last_v) ++ toolhead.move([nX, nY, Z, E], abs_v) ++ else: ++ toolhead.move([nX, nY, Z, E], max(abs_v, abs_last_v)) ++ if math.floor(freq) > math.floor(last_freq): + gcmd.respond_info("Testing frequency %.0f Hz" % (freq,)) ++ reactor.pause(reactor.monotonic() + 0.01) ++ X, Y = nX, nY ++ last_t = next_t ++ last_v = v ++ last_accel = accel ++ last_freq = freq ++ if last_v: ++ d_decel = -.5 * last_v2 / old_max_accel ++ decel_X, decel_Y = axis.get_point(d_decel) ++ toolhead.cmd_M204(self.gcode.create_gcode_command( ++ "M204", "M204", {"S": old_max_accel})) ++ toolhead.move([X + decel_X, Y + decel_Y, Z, E], abs(last_v)) + # Restore the original acceleration values + self.gcode.run_script_from_command( + "SET_VELOCITY_LIMIT ACCEL=%.3f MINIMUM_CRUISE_RATIO=%.3f" +@@ -116,14 +192,13 @@ def run_test(self, axis, gcmd): + if input_shaper is not None: + input_shaper.enable_shaping() + gcmd.respond_info("Re-enabled [input_shaper]") +- def get_max_freq(self): +- return self.freq_end + + class ResonanceTester: + def __init__(self, config): + self.printer = config.get_printer() + self.move_speed = config.getfloat('move_speed', 50., above=0.) +- self.test = VibrationPulseTest(config) ++ self.generator = SweepingVibrationsTestGenerator(config) ++ self.executor = ResonanceTestExecutor(config) + self.state = STATE_IDLE + if not config.get('accel_chip_x', None): + self.accel_chip_names = [('xy', config.get('accel_chip').strip())] +@@ -133,6 +208,8 @@ def __init__(self, config): + if self.accel_chip_names[0][1] == self.accel_chip_names[1][1]: + self.accel_chip_names = [('xy', self.accel_chip_names[0][1])] + self.max_smoothing = config.getfloat('max_smoothing', None, minval=0.05) ++ self.probe_points = config.getlists('probe_points', seps=(',', '\n'), ++ parser=float, count=3) + self.delta_freq = config.getfloat('delta_freq', 10., minval=5.) + self.log_path = config.get('log_path', None) + debug = config.getint('debug', 0) +@@ -156,12 +233,9 @@ def _run_test(self, gcmd, axes, helper, raw_name_suffix=None, + toolhead = self.printer.lookup_object('toolhead') + calibration_data = {axis: None for axis in axes} + +- self.test.prepare_test(gcmd) ++ self.generator.prepare_test(gcmd) + +- if test_point is not None: +- test_points = [test_point] +- else: +- test_points = self.test.get_start_test_points() ++ test_points = [test_point] if test_point else self.probe_points + + for point in test_points: + toolhead.manual_move(point, self.move_speed) +@@ -186,7 +260,8 @@ def _run_test(self, gcmd, axes, helper, raw_name_suffix=None, + raw_values.append((axis, aclient, chip.name)) + + # Generate moves +- self.test.run_test(axis, gcmd) ++ test_seq = self.generator.gen_test() ++ self.executor.run_test(test_seq, axis, gcmd) + for chip_axis, aclient, chip_name in raw_values: + aclient.finish_measurements() + if raw_name_suffix is not None: +@@ -218,7 +293,7 @@ def _parse_chips(self, accel_chips): + parsed_chips.append(chip) + return parsed_chips + def _get_max_calibration_freq(self): +- return 1.5 * self.test.get_max_freq() ++ return 1.5 * self.generator.get_max_freq() + + def check_homed(self): + curtime = self.printer.get_reactor().monotonic() +diff --git a/klippy/extras/shaper_calibrate.py b/klippy/extras/shaper_calibrate.py +index 6891fefb3bf9..f497171f67c0 100644 +--- a/klippy/extras/shaper_calibrate.py ++++ b/klippy/extras/shaper_calibrate.py +@@ -48,7 +48,9 @@ def normalize_to_frequencies(self): + # Avoid division by zero errors + psd /= self.freq_bins + .1 + # Remove low-frequency noise +- psd[self.freq_bins < MIN_FREQ] = 0. ++ low_freqs = self.freq_bins < 2. * MIN_FREQ ++ psd[low_freqs] *= self.numpy.exp( ++ -(2. * MIN_FREQ / (self.freq_bins[low_freqs] + .1))**2 + 1.) + def get_psd(self, axis='all'): + return self._psd_map[axis] + +diff --git a/klippy/toolhead.py b/klippy/toolhead.py +index ed26092f651d..256915daabf9 100644 +--- a/klippy/toolhead.py ++++ b/klippy/toolhead.py +@@ -47,6 +47,7 @@ def __init__(self, toolhead, start_pos, end_pos, speed): + self.delta_v2 = 2.0 * move_d * self.accel + self.max_smoothed_v2 = 0. + self.smooth_delta_v2 = 2.0 * move_d * toolhead.max_accel_to_decel ++ self.next_junction_v2 = 999999999.9 + def limit_speed(self, speed, accel): + speed2 = speed**2 + if speed2 < self.max_cruise_v2: +@@ -55,6 +56,8 @@ def limit_speed(self, speed, accel): + self.accel = min(self.accel, accel) + self.delta_v2 = 2.0 * self.move_d * self.accel + self.smooth_delta_v2 = min(self.smooth_delta_v2, self.delta_v2) ++ def limit_next_junction_speed(self, speed): ++ self.next_junction_v2 = min(self.next_junction_v2, speed**2) + def move_error(self, msg="Move out of range"): + ep = self.end_pos + m = "%s: %.3f %.3f %.3f [%.3f]" % (msg, ep[0], ep[1], ep[2], ep[3]) +@@ -64,9 +67,9 @@ def calc_junction(self, prev_move): + return + # Allow extruder to calculate its maximum junction + extruder_v2 = self.toolhead.extruder.calc_junction(prev_move, self) +- max_start_v2 = min( +- extruder_v2, self.max_cruise_v2, prev_move.max_cruise_v2, +- prev_move.max_start_v2 + prev_move.delta_v2) ++ max_start_v2 = min(extruder_v2, self.max_cruise_v2, ++ prev_move.max_cruise_v2, prev_move.next_junction_v2, ++ prev_move.max_start_v2 + prev_move.delta_v2) + # Find max velocity using "approximated centripetal velocity" + axes_r = self.axes_r + prev_axes_r = prev_move.axes_r +@@ -462,6 +465,10 @@ def set_position(self, newpos, homing_axes=()): + self.commanded_pos[:] = newpos + self.kin.set_position(newpos, homing_axes) + self.printer.send_event("toolhead:set_position") ++ def limit_next_junction_speed(self, speed): ++ last_move = self.lookahead.get_last() ++ if last_move is not None: ++ last_move.limit_next_junction_speed(speed) + def move(self, newpos, speed, line=None): + move = Move(self, self.commanded_pos, newpos, speed, line) + if not move.move_d: diff --git a/scripts/create_firmware.sh b/scripts/create_firmware.sh index 00a4f96a..bfee0d27 100755 --- a/scripts/create_firmware.sh +++ b/scripts/create_firmware.sh @@ -80,7 +80,7 @@ for overlay; do while read -r patchfile; do echo "[+] Applying patch: $(basename "$patchfile") in subdir $(dirname "$patchfile")" patch -F 0 -d "$ROOTFS_DIR/$(dirname "$patchfile")" -p1 < "$patchfile" - done < <(find -type f -name "*.patch") + done < <(find -type f -name "*.patch" | sort) popd > /dev/null fi