From a231de7cb54137021a2cd68dac65ef04eeed248d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Boisselier?= Date: Mon, 24 Jun 2024 18:47:25 +0200 Subject: [PATCH] moved the checks in the onconnect handler --- README.md | 12 +++--- shaketune/motor_res_filter.py | 14 ++++++- shaketune/shaketune.py | 79 +++++++++++++++++++---------------- 3 files changed, 60 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 1a73bf6..df367c7 100644 --- a/README.md +++ b/README.md @@ -33,22 +33,22 @@ Follow these steps to install Shake&Tune on your printer: # The maximum time in seconds to let Shake&Tune process the CSV files and generate the graphs. # motor_freq: - # /!\ This option is only available in DangerKlipper /!\ + # /!\ This option has limitations in stock Klipper and is best used with DangerKlipper /!\ # Frequencies of X and Y motor resonances to filter them using - # composite shapers. This require the `[input_shaper]` config + # composite shapers. This requires the `[input_shaper]` config # section to be defined in your printer.cfg file to work. # motor_freq_x: # motor_freq_y: - # /!\ This option is only available in DangerKlipper /!\ + # /!\ This option has limitations in stock Klipper and is best used with DangerKlipper /!\ # If motor_freq is not set, these two parameters can be used # to configure different filters for X and Y motors. The same # values are supported as for motor_freq parameter. # motor_damping_ratio: 0.05 - # /!\ This option is only available in DangerKlipper /!\ - # Damping ratios of X and Y motor resonances. + # /!\ This option has limitations in stock Klipper and is best used with DangerKlipper /!\ + # Damping ratios for X and Y motor resonances. # motor_damping_ratio_x: # motor_damping_ratio_y: - # /!\ This option is only available in DangerKlipper /!\ + # /!\ This option has limitations in stock Klipper and is best used with DangerKlipper /!\ # If motor_damping_ratio is not set, these two parameters can be used # to configure different filters for X and Y motors. The same values # are supported as for motor_damping_ratio parameter. diff --git a/shaketune/motor_res_filter.py b/shaketune/motor_res_filter.py index 5bf6240..a1d4b81 100644 --- a/shaketune/motor_res_filter.py +++ b/shaketune/motor_res_filter.py @@ -26,7 +26,7 @@ def __init__(self, printer, freq_x: float, freq_y: float, damping_x: float, damp self._original_shapers = {} - # Convolve two Klipper shapers into a new composite shaper + # Convolve two Klipper shapers into a new custom composite input shaping filter @staticmethod def convolve_shapers(L, R): As = [a * b for a in L[0] for b in R[0]] @@ -36,6 +36,11 @@ def convolve_shapers(L, R): def apply_filters(self) -> None: input_shaper = self._printer.lookup_object('input_shaper', None) + if input_shaper is None: + raise ValueError( + 'Unable to apply Shake&Tune motor resonance filters: no [input_shaper] config section found!' + ) + shapers = input_shaper.get_shapers() for shaper in shapers: axis = shaper.axis @@ -71,7 +76,7 @@ def apply_filters(self) -> None: ConsoleOutput.print( ( f'Error: the {axis} axis is not a ZV type shaper. Shake&Tune motor resonance filters ' - 'will be ignored for this axis... Thi is due to the size of the pulse train being too ' + 'will be ignored for this axis... This is due to the size of the pulse train being too ' 'small and not allowing the convolved shapers to be applied... unless this PR is ' 'merged: https://github.com/Klipper3d/klipper/pull/6460' ) @@ -109,6 +114,11 @@ def apply_filters(self) -> None: def remove_filters(self) -> None: input_shaper = self._printer.lookup_object('input_shaper', None) + if input_shaper is None: + raise ValueError( + 'Unable to deactivate Shake&Tune motor resonance filters: no [input_shaper] config section found!' + ) + shapers = input_shaper.get_shapers() for shaper in shapers: axis = shaper.axis diff --git a/shaketune/shaketune.py b/shaketune/shaketune.py index 6965a66..d1999f8 100644 --- a/shaketune/shaketune.py +++ b/shaketune/shaketune.py @@ -58,33 +58,19 @@ class ShakeTune: def __init__(self, config) -> None: self._config = config self._printer = config.get_printer() + self.printer.register_event_handler('klippy:connect', self._on_klippy_connect) - self._initialize_danger_klipper() - self._initialize_console_output() - self._validate_resonance_tester() - self._initialize_config(config) - self._register_commands() - self._initialize_motor_resonance_filter() - - # Check if Shake&Tune is running in DangerKlipper - def _initialize_danger_klipper(self) -> None: + # Check if Shake&Tune is running in DangerKlipper global IN_DANGER - if importlib.util.find_spec('extras.danger_options') is not None: - IN_DANGER = True + IN_DANGER = importlib.util.find_spec('extras.danger_options') is not None - # Register the console print output callback to the corresponding Klipper function - def _initialize_console_output(self) -> None: + # Register the console print output callback to the corresponding Klipper function gcode = self._printer.lookup_object('gcode') ConsoleOutput.register_output_callback(gcode.respond_info) - # Check if the resonance_tester object is available in the printer - # configuration as it is required for Shake&Tune to work properly - def _validate_resonance_tester(self) -> None: - res_tester = self._printer.lookup_object('resonance_tester', None) - if res_tester is None: - raise self._config.error( - 'No [resonance_tester] config section found in printer.cfg! Please add one to use Shake&Tune.' - ) + self._initialize_config(config) + self._register_commands() + self._initialize_motor_resonance_filter() # Initialize the ShakeTune object and its configuration def _initialize_config(self, config) -> None: @@ -155,30 +141,23 @@ def _register_commands(self) -> None: self._printer.load_object(self._config, gcode_macro_name.lower()) # Register the motor resonance filters if they are defined in the config - # DangerKlipper is required for now or a degraded system forcing the ZV filter for - # both input shaping and motor resonance filter will be used instead. But this will + # DangerKlipper is required for the full feature but a degraded system forcing the ZV filter for + # both input shaping and motor resonance filter will be used instead in stock Klipper. But this might # be improved in the future if https://github.com/Klipper3d/klipper/pull/6460 get merged - # TODO: To mitigate this issue, add a automated patch to klippy/chelper/kin_shaper.c + # TODO: To mitigate this issue, add an automated patch to klippy/chelper/kin_shaper.c # (using a .diff file) to enable the motor filters in stock Klipper as well. # But this will make the Klipper repo dirty to moonraker update manager, so I'm not # sure how to handle this. Maybe with also a command to revert the patch? Or a # manual command to apply the patch with a required user action? def _initialize_motor_resonance_filter(self) -> None: if self._motor_freq_x is not None and self._motor_freq_y is not None: - input_shaper = self._printer.lookup_object('input_shaper', None) - if input_shaper is None: - raise self._config.error( - ( - 'Error: motor resonance filters cannot be enabled because the standard ' - '[input_shaper] Klipper config section is not configured!' - ) - ) - + self._printer.register_event_handler('klippy:ready', self._on_klippy_ready) gcode = self._printer.lookup_object('gcode') gcode.register_command( - 'MOTOR_RESONANCE_FILTER', self.cmd_MOTOR_RESONANCE_FILTER, desc='Enable/disable motor resonance filters' + 'MOTOR_RESONANCE_FILTER', + self.cmd_MOTOR_RESONANCE_FILTER, + desc='Enable/disable the motor resonance filters', ) - self.motor_resonance_filter = MotorResonanceFilter( self._printer, self._motor_freq_x, @@ -188,11 +167,37 @@ def _initialize_motor_resonance_filter(self) -> None: IN_DANGER, ) - self._printer.register_event_handler('klippy:ready', self.handle_ready) + def _on_klippy_connect(self) -> None: + # Check if the resonance_tester object is available in the printer + # configuration as it is required for Shake&Tune to work properly + res_tester = self._printer.lookup_object('resonance_tester', None) + if res_tester is None: + raise self._config.error( + 'No [resonance_tester] config section found in printer.cfg! Please add one to use Shake&Tune!' + ) + + # In case the user has configured a motor resonance filter, we need to make sure + # that the input shaper is configured as well in order to use them. This is because + # the input shaper object is the one used to actually applies the additional filters + if self._motor_freq_x is not None and self._motor_freq_y is not None: + input_shaper = self._printer.lookup_object('input_shaper', None) + if input_shaper is None: + raise self._config.error( + ( + 'No [input_shaper] config section found in printer.cfg! Please add one to use Shake&Tune ' + 'motor resonance filters!' + ) + ) - def handle_ready(self) -> None: + def _on_klippy_ready(self) -> None: self.motor_resonance_filter.apply_filters() + # ------------------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------------------ + # Following are all the Shake&Tune commands that are registered to the Klipper console + # ------------------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------------------ + def cmd_EXCITATE_AXIS_AT_FREQ(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') static_freq_graph_creator = StaticGraphCreator(self._st_config)