diff --git a/README.md b/README.md index e4156ac..a153c96 100644 --- a/README.md +++ b/README.md @@ -29,18 +29,26 @@ Follow these steps to install the Shake&Tune module in your printer: 1. Then, append the following to your `printer.cfg` file and restart Klipper (if prefered, you can include only the needed macros: using `*.cfg` is a convenient way to include them all at once): ``` [shaketune] - # result_folder: ~/printer_data/config/K-ShakeTune_results + # result_folder: ~/printer_data/config/ShakeTune_results + # The folder where the results will be stored. It will be created if it doesn't exist. # number_of_results_to_keep: 3 + # The number of results to keep in the result_folder. The oldest results will + # be automatically deleted after each runs. # keep_raw_csv: False + # If True, the raw CSV files will be kept in the result_folder alongside the + # PNG graphs. If False, they will be deleted and only the graphs will be kept. + # show_macros_in_webui: True + # Mainsail and Fluidd doesn't create buttons for "system" macros that are not in the + # printer.cfg file. If you want to see the macros in the webui, set this to True. ``` ## Usage Ensure your machine is homed, then invoke one of the following macros as needed: + - `EXCITATE_AXIS_AT_FREQ` to maintain a specific excitation frequency, useful to inspect and find out what is resonating. - `AXES_MAP_CALIBRATION` to automatically find Klipper's `axes_map` parameter for your accelerometer orientation (be careful, this is experimental for now and known to give bad results). - `COMPARE_BELTS_RESPONSES` for a differential belt resonance graph, useful for checking relative belt tensions and belt path behaviors on a CoreXY printer. - `AXES_SHAPER_CALIBRATION` for standard input shaper graphs, used to mitigate ringing/ghosting by tuning Klipper's input shaper filters. - `CREATE_VIBRATIONS_PROFILE` for vibrations graphs as a function of toolhead direction and speed, used to find problematic ranges where the printer could be exposed to more VFAs and optimize your slicer speed profiles and TMC driver parameters. - - `EXCITATE_AXIS_AT_FREQ` to maintain a specific excitation frequency, useful to inspect and find out what is resonating. For further insights on the usage of these macros and the generated graphs, refer to the [K-Shake&Tune module documentation](./docs/README.md). diff --git a/shaketune/dummy_macros.cfg b/shaketune/dummy_macros.cfg new file mode 100644 index 0000000..40607de --- /dev/null +++ b/shaketune/dummy_macros.cfg @@ -0,0 +1,67 @@ +# This file contains dummy gcode macros to inject them at Klipper startup +# by the Shake&Tune plugin in order to make them available in the UI. +# Indeed, system macros in Klipper are not available as buttons in Mainsail/Fluidd +# and this is a workaround to have a good and friendly UX when using Shake&Tune. + + +[gcode_macro EXCITATE_AXIS_AT_FREQ] +description: dummy +gcode: + {% set dummy = params.FREQUENCY|default(25) %} + {% set dummy = params.DURATION|default(10) %} + {% set dummy = params.ACCEL_PER_HZ %} + {% set dummy = params.AXIS|default('x') %} + {% set dummy = params.TRAVEL_SPEED|default(120) %} + {% set dummy = params.Z_HEIGHT %} + _EXCITATE_AXIS_AT_FREQ {rawparams} + + +[gcode_macro AXES_MAP_CALIBRATION] +description: dummy +gcode: + {% set dummy = params.Z_HEIGHT|default(20) %} + {% set dummy = params.SPEED|default(80) %} + {% set dummy = params.ACCEL|default(1500) %} + {% set dummy = params.TRAVEL_SPEED|default(120) %} + {% set dummy = params.ACCEL_CHIP %} + _AXES_MAP_CALIBRATION {rawparams} + + +[gcode_macro COMPARE_BELTS_RESPONSES] +description: dummy +gcode: + {% set dummy = params.FREQ_START|default(5) %} + {% set dummy = params.FREQ_END|default(133.33) %} + {% set dummy = params.HZ_PER_SEC|default(1) %} + {% set dummy = params.ACCEL_PER_HZ %} + {% set dummy = params.TRAVEL_SPEED|default(120) %} + {% set dummy = params.Z_HEIGHT %} + _COMPARE_BELTS_RESPONSES {rawparams} + + +[gcode_macro AXES_SHAPER_CALIBRATION] +description: dummy +gcode: + {% set dummy = params.FREQ_START|default(5) %} + {% set dummy = params.FREQ_END|default(133.33) %} + {% set dummy = params.HZ_PER_SEC|default(1) %} + {% set dummy = params.ACCEL_PER_HZ %} + {% set dummy = params.AXIS|default('all') %} + {% set dummy = params.SCV %} + {% set dummy = params.MAX_SMOOTHING %} + {% set dummy = params.TRAVEL_SPEED|default(120) %} + {% set dummy = params.Z_HEIGHT %} + _AXES_SHAPER_CALIBRATION {rawparams} + + +[gcode_macro CREATE_VIBRATIONS_PROFILE] +description: dummy +gcode: + {% set dummy = params.SIZE|default(100) %} + {% set dummy = params.Z_HEIGHT|default(20) %} + {% set dummy = params.MAX_SPEED|default(200) %} + {% set dummy = params.SPEED_INCREMENT|default(2) %} + {% set dummy = params.ACCEL|default(3000) %} + {% set dummy = params.TRAVEL_SPEED|default(120) %} + {% set dummy = params.ACCEL_CHIP %} + _CREATE_VIBRATIONS_PROFILE {rawparams} diff --git a/shaketune/measurement/macros.cfg b/shaketune/measurement/macros.cfg deleted file mode 100644 index c34a9d9..0000000 --- a/shaketune/measurement/macros.cfg +++ /dev/null @@ -1,8 +0,0 @@ - -# [gcode_macro AXES_MAP_CALIBRATION] -# gcode: -# {% set z_height = params.Z_HEIGHT|default(20)|int %} # z height to put the toolhead before starting the movements -# {% set speed = params.SPEED|default(80)|float * 60 %} # feedrate for the movements -# {% set accel = params.ACCEL|default(1500)|int %} # accel value used to move on the pattern -# {% set feedrate_travel = params.TRAVEL_SPEED|default(120)|int * 60 %} # travel feedrate between moves -# {% set accel_chip = params.ACCEL_CHIP|default("adxl345") %} # ADXL chip name in the config diff --git a/shaketune/shaketune.py b/shaketune/shaketune.py index f7d058b..ec7ea50 100644 --- a/shaketune/shaketune.py +++ b/shaketune/shaketune.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 +import os from pathlib import Path from .helpers.console_output import ConsoleOutput @@ -24,81 +25,77 @@ class ShakeTune: res_tester = self._printer.lookup_object('resonance_tester') if res_tester is None: - config.error('No [resonance_tester] config section found in printer.cfg! Please add one to use Shake&Tune') + config.error('No [resonance_tester] config section found in printer.cfg! Please add one to use Shake&Tune.') self.timeout = config.getfloat('timeout', 2.0, above=0.0) - - result_folder = config.get('result_folder', default='~/printer_data/config/K-ShakeTune_results') + result_folder = config.get('result_folder', default='~/printer_data/config/ShakeTune_results') result_folder_path = Path(result_folder).expanduser() if result_folder else None keep_n_results = config.getint('number_of_results_to_keep', default=3, minval=0) keep_csv = config.getboolean('keep_raw_csv', default=False) + show_macros = config.getboolean('show_macros_in_webui', default=True) dpi = config.getint('dpi', default=150, minval=100, maxval=500) self._config = ShakeTuneConfig(result_folder_path, keep_n_results, keep_csv, dpi) ConsoleOutput.register_output_callback(gcode.respond_info) - gcode.register_command( - 'EXCITATE_AXIS_AT_FREQ', - self.cmd_EXCITATE_AXIS_AT_FREQ, - desc=self.cmd_EXCITATE_AXIS_AT_FREQ_help, - ) - gcode.register_command( - 'AXES_MAP_CALIBRATION', - self.cmd_AXES_MAP_CALIBRATION, - desc=self.cmd_AXES_MAP_CALIBRATION_help, - ) - gcode.register_command( - 'COMPARE_BELTS_RESPONSES', - self.cmd_COMPARE_BELTS_RESPONSES, - desc=self.cmd_COMPARE_BELTS_RESPONSES_help, - ) - gcode.register_command( - 'AXES_SHAPER_CALIBRATION', - self.cmd_AXES_SHAPER_CALIBRATION, - desc=self.cmd_AXES_SHAPER_CALIBRATION_help, - ) - gcode.register_command( - 'CREATE_VIBRATIONS_PROFILE', - self.cmd_CREATE_VIBRATIONS_PROFILE, - desc=self.cmd_CREATE_VIBRATIONS_PROFILE_help, - ) + commands = [ + ('EXCITATE_AXIS_AT_FREQ', self.cmd_EXCITATE_AXIS_AT_FREQ, 'Maintain a specified excitation frequency for a period of time to diagnose and locate a source of vibration'), + ('AXES_MAP_CALIBRATION', self.cmd_AXES_MAP_CALIBRATION, 'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer'), + ('COMPARE_BELTS_RESPONSES', self.cmd_COMPARE_BELTS_RESPONSES, 'Perform a custom half-axis test to analyze and compare the frequency profiles of individual belts on CoreXY printers'), + ('AXES_SHAPER_CALIBRATION', self.cmd_AXES_SHAPER_CALIBRATION, 'Perform standard axis input shaper tests on one or both XY axes to select the best input shaper filter'), + ('CREATE_VIBRATIONS_PROFILE', self.cmd_CREATE_VIBRATIONS_PROFILE, 'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer') + ] + command_descriptions = {name: desc for name, _, desc in commands} + + for name, command, description in commands: + gcode.register_command( + f'_{name}' if show_macros else name, + command, + desc=description + ) + + # Load the dummy macros with their description in order to show them in the web interfaces + if show_macros: + pconfig = self._printer.lookup_object('configfile') + dirname = os.path.dirname(os.path.realpath(__file__)) + filename = os.path.join(dirname, 'dummy_macros.cfg') + try: + dummy_macros = pconfig.read_config(filename) + except Exception as err: + raise config.error("Cannot load Shake&Tune dummy macro '%s'" % (filename,)) from err + for macro in dummy_macros.get_prefix_sections(''): + section = macro.get_name() + command = section.split(' ', 1)[1] + if command in command_descriptions: + description = command_descriptions[command] + else: + description = 'Shake&Tune macro' + macro.fileconfig._sections[section]['description'] = description + self._printer.load_object(dummy_macros, section) - cmd_EXCITATE_AXIS_AT_FREQ_help = ( - 'Maintain a specified excitation frequency for a period of time to diagnose and locate a source of vibration' - ) def cmd_EXCITATE_AXIS_AT_FREQ(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') excitate_axis_at_freq(gcmd, self._pconfig) - cmd_AXES_MAP_CALIBRATION_help = 'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer' - def cmd_AXES_MAP_CALIBRATION(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') axes_map_finder = AxesMapFinder(self._config) st_thread = ShakeTuneThread(self._config, axes_map_finder, self._printer.get_reactor(), self.timeout) axes_map_calibration(gcmd, self._pconfig, st_thread) - cmd_COMPARE_BELTS_RESPONSES_help = 'Perform a custom half-axis test to analyze and compare the frequency profiles of individual belts on CoreXY printers' - def cmd_COMPARE_BELTS_RESPONSES(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') belt_graph_creator = BeltsGraphCreator(self._config) st_thread = ShakeTuneThread(self._config, belt_graph_creator, self._printer.get_reactor(), self.timeout) compare_belts_responses(gcmd, self._pconfig, st_thread) - cmd_AXES_SHAPER_CALIBRATION_help = ( - 'Perform standard axis input shaper tests on one or both XY axes to select the best input shaper filter' - ) - def cmd_AXES_SHAPER_CALIBRATION(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') shaper_graph_creator = ShaperGraphCreator(self._config) st_thread = ShakeTuneThread(self._config, shaper_graph_creator, self._printer.get_reactor(), self.timeout) axes_shaper_calibration(gcmd, self._pconfig, st_thread) - cmd_CREATE_VIBRATIONS_PROFILE_help = 'Perform a set of movements to measure the orientation of the accelerometer and help you set the best axes_map configuration for your printer' - def cmd_CREATE_VIBRATIONS_PROFILE(self, gcmd) -> None: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') vibration_profile_creator = VibrationsGraphCreator(self._config)