From ac5917cd5d946dd2b133271f0f86148f7aa07b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Boisselier?= Date: Sun, 29 Dec 2024 23:21:28 +0100 Subject: [PATCH] modified graph metadata header to include sweeping/pulse params --- shaketune/cli.py | 22 ++++++++- shaketune/commands/axes_shaper_calibration.py | 9 ++-- shaketune/commands/compare_belts_responses.py | 9 ++-- .../graph_creators/belts_graph_creator.py | 18 ++++--- shaketune/graph_creators/plotter.py | 49 ++++++++++--------- .../graph_creators/shaper_graph_creator.py | 15 +++--- shaketune/helpers/resonance_test.py | 25 +++++++--- 7 files changed, 93 insertions(+), 54 deletions(-) diff --git a/shaketune/cli.py b/shaketune/cli.py index f133ffa..4b3d363 100644 --- a/shaketune/cli.py +++ b/shaketune/cli.py @@ -28,12 +28,16 @@ def configure_graph_creator(graph_type, args, dummy_config): elif graph_type == 'static frequency': config_kwargs |= {'accel_per_hz': args.accel_per_hz, 'freq': args.frequency, 'duration': args.duration} elif graph_type == 'belts comparison': - config_kwargs |= {'kinematics': args.kinematics, 'accel_per_hz': args.accel_per_hz, 'max_scale': args.max_scale} + config_kwargs |= { + 'kinematics': args.kinematics, + 'test_params': (args.mode, None, None, args.accel_per_hz, None, args.sweeping_accel, args.sweeping_period), + 'max_scale': args.max_scale, + } elif graph_type == 'input shaper': config_kwargs |= { 'scv': args.scv, 'max_smoothing': args.max_smoothing, - 'accel_per_hz': args.accel_per_hz, + 'test_params': (args.mode, None, None, args.accel_per_hz, None, args.sweeping_accel, args.sweeping_period), 'max_scale': args.max_scale, } elif graph_type == 'vibrations profile': @@ -74,7 +78,14 @@ def main(): add_common_arguments(belts_parser) belts_parser.add_argument('-k', '--klipper_dir', default='~/klipper', help='Main klipper directory') belts_parser.add_argument('--kinematics', help='Machine kinematics configuration') + belts_parser.add_argument('--mode', type=str, help='Mode of the test used during the measurement') belts_parser.add_argument('--accel_per_hz', type=float, help='Accel per Hz used during the measurement') + belts_parser.add_argument( + '--sweeping_accel', type=float, help='Accel used during the sweeping test (if sweeping was used)' + ) + belts_parser.add_argument( + '--sweeping_period', type=float, help='Sweeping period used during the sweeping test (if sweeping was used)' + ) belts_parser.add_argument( '--max_scale', type=lambda x: int(float(x)), help='Maximum energy value to scale the belts graph' ) @@ -85,7 +96,14 @@ def main(): shaper_parser.add_argument('-k', '--klipper_dir', default='~/klipper', help='Main klipper directory') shaper_parser.add_argument('--scv', type=float, default=5.0, help='Square corner velocity') shaper_parser.add_argument('--max_smoothing', type=float, help='Maximum shaper smoothing to allow') + shaper_parser.add_argument('--mode', type=str, help='Mode of the test used during the measurement') shaper_parser.add_argument('--accel_per_hz', type=float, help='Accel per Hz used during the measurement') + shaper_parser.add_argument( + '--sweeping_accel', type=float, help='Accel used during the sweeping test (if sweeping was used)' + ) + shaper_parser.add_argument( + '--sweeping_period', type=float, help='Sweeping period used during the sweeping test (if sweeping was used)' + ) shaper_parser.add_argument( '--max_scale', type=lambda x: int(float(x)), help='Maximum energy value to scale the input shaper graph' ) diff --git a/shaketune/commands/axes_shaper_calibration.py b/shaketune/commands/axes_shaper_calibration.py index 9c28ca1..b6f408a 100644 --- a/shaketune/commands/axes_shaper_calibration.py +++ b/shaketune/commands/axes_shaper_calibration.py @@ -73,10 +73,6 @@ def axes_shaper_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None: toolhead.manual_move(point, feedrate_travel) toolhead.dwell(0.5) - # Configure the graph creator - creator = st_process.get_graph_creator() - creator.configure(scv, max_sm, accel_per_hz, max_scale) - # set the needed acceleration values for the test toolhead_info = toolhead.get_status(systime) old_accel = toolhead_info['max_accel'] @@ -110,7 +106,9 @@ def axes_shaper_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None: # Then do the actual measurements ConsoleOutput.print(f'Measuring {config["label"]}...') accelerometer.start_recording(measurements_manager, name=config['label'], append_time=True) - vibrate_axis(toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester) + test_params = vibrate_axis( + toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester + ) accelerometer.stop_recording() accelerometer.wait_for_samples() toolhead.dwell(0.5) @@ -120,6 +118,7 @@ def axes_shaper_calibration(gcmd, config, st_process: ShakeTuneProcess) -> None: ConsoleOutput.print(f'{config["axis"].upper()} axis frequency profile generation...') ConsoleOutput.print('This may take some time (1-3min)') measurements_manager.wait_for_data_transfers(printer.get_reactor()) + st_process.get_graph_creator().configure(scv, max_sm, test_params, max_scale) st_process.run(measurements_manager) st_process.wait_for_completion() toolhead.dwell(1) diff --git a/shaketune/commands/compare_belts_responses.py b/shaketune/commands/compare_belts_responses.py index 318f492..94a1397 100644 --- a/shaketune/commands/compare_belts_responses.py +++ b/shaketune/commands/compare_belts_responses.py @@ -45,11 +45,7 @@ def compare_belts_responses(gcmd, config, st_process: ShakeTuneProcess) -> None: max_accel = max_freq * accel_per_hz - # Configure the graph creator motors_config_parser = MotorsConfigParser(config, motors=None) - creator = st_process.get_graph_creator() - creator.configure(motors_config_parser.kinematics, accel_per_hz, max_scale) - if motors_config_parser.kinematics in {'corexy', 'limited_corexy'}: filtered_config = [a for a in AXIS_CONFIG if a['axis'] in ('a', 'b')] accel_chip = Accelerometer.find_axis_accelerometer(printer, 'xy') @@ -113,7 +109,9 @@ def compare_belts_responses(gcmd, config, st_process: ShakeTuneProcess) -> None: for config in filtered_config: ConsoleOutput.print(f'Measuring {config["label"]}...') accelerometer.start_recording(measurements_manager, name=config['label'], append_time=True) - vibrate_axis(toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester) + test_params = vibrate_axis( + toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester + ) accelerometer.stop_recording() accelerometer.wait_for_samples() toolhead.dwell(0.5) @@ -133,5 +131,6 @@ def compare_belts_responses(gcmd, config, st_process: ShakeTuneProcess) -> None: ConsoleOutput.print('Belts comparative frequency profile generation...') ConsoleOutput.print('This may take some time (1-3min)') measurements_manager.wait_for_data_transfers(printer.get_reactor()) + st_process.get_graph_creator().configure(motors_config_parser.kinematics, test_params, max_scale) st_process.run(measurements_manager) st_process.wait_for_completion() diff --git a/shaketune/graph_creators/belts_graph_creator.py b/shaketune/graph_creators/belts_graph_creator.py index 68d1e3d..4e57c9c 100644 --- a/shaketune/graph_creators/belts_graph_creator.py +++ b/shaketune/graph_creators/belts_graph_creator.py @@ -16,6 +16,7 @@ from ..helpers.accelerometer import Measurement, MeasurementsManager from ..helpers.common_func import detect_peaks from ..helpers.console_output import ConsoleOutput +from ..helpers.resonance_test import testParams from ..shaketune_config import ShakeTuneConfig from . import get_shaper_calibrate_module from .graph_creator import GraphCreator @@ -26,13 +27,16 @@ class BeltsGraphCreator(GraphCreator): def __init__(self, config: ShakeTuneConfig): super().__init__(config) self._kinematics: Optional[str] = None - self._accel_per_hz: Optional[float] = None + self._test_params: Optional[testParams] = None def configure( - self, kinematics: Optional[str] = None, accel_per_hz: Optional[float] = None, max_scale: Optional[int] = None + self, + kinematics: Optional[str] = None, + test_params: Optional[testParams] = None, + max_scale: Optional[int] = None, ) -> None: self._kinematics = kinematics - self._accel_per_hz = accel_per_hz + self._test_params = test_params self._max_scale = max_scale def create_graph(self, measurements_manager: MeasurementsManager) -> None: @@ -40,7 +44,7 @@ def create_graph(self, measurements_manager: MeasurementsManager) -> None: measurements=measurements_manager.get_measurements(), kinematics=self._kinematics, max_freq=self._config.max_freq, - accel_per_hz=self._accel_per_hz, + test_params=self._test_params, max_scale=self._max_scale, st_version=self._version, ) @@ -73,14 +77,14 @@ def __init__( measurements: List[Measurement], kinematics: Optional[str], max_freq: float, - accel_per_hz: Optional[float], + test_params: Optional[testParams], max_scale: Optional[int], st_version: str, ): self.measurements = measurements self.kinematics = kinematics self.max_freq = max_freq - self.accel_per_hz = accel_per_hz + self.test_params = test_params self.max_scale = max_scale self.st_version = st_version @@ -134,7 +138,7 @@ def compute(self): 'signal1_belt': signal1_belt, 'signal2_belt': signal2_belt, 'kinematics': self.kinematics, - 'accel_per_hz': self.accel_per_hz, + 'test_params': self.test_params, 'st_version': self.st_version, 'measurements': self.measurements, 'max_freq': self.max_freq, diff --git a/shaketune/graph_creators/plotter.py b/shaketune/graph_creators/plotter.py index 694bab6..87b1f39 100644 --- a/shaketune/graph_creators/plotter.py +++ b/shaketune/graph_creators/plotter.py @@ -325,7 +325,7 @@ def plot_belts_graph(self, data): signal1_belt = data['signal1_belt'] signal2_belt = data['signal2_belt'] kinematics = data['kinematics'] - accel_per_hz = data['accel_per_hz'] + mode, _, _, accel_per_hz, _, sweeping_accel, sweeping_period = data['test_params'] st_version = data['st_version'] measurements = data['measurements'] max_freq = data['max_freq'] @@ -356,6 +356,12 @@ def plot_belts_graph(self, data): title_line2 += ' -- ' + kinematics.upper() + ' kinematics' except Exception: title_line2 = measurements[0]['name'] + ' / ' + measurements[1]['name'] + + title_line3 = f'| Mode: {mode}' + title_line3 += f' -- ApH: {accel_per_hz}' if accel_per_hz is not None else '' + if mode == 'SWEEPING': + title_line3 += f' [sweeping period: {sweeping_accel} s - accel: {sweeping_accel} mm/s²]' + title_lines = [ { 'x': 0.060, @@ -366,32 +372,28 @@ def plot_belts_graph(self, data): 'weight': 'bold', }, {'x': 0.060, 'y': 0.939, 'va': 'top', 'text': title_line2}, + { + 'x': 0.481, + 'y': 0.985, + 'va': 'top', + 'fontsize': 10, + 'text': title_line3, + }, ] if kinematics in {'limited_corexy', 'corexy', 'limited_corexz', 'corexz'}: title_lines.extend( [ - {'x': 0.55, 'y': 0.985, 'va': 'top', 'text': f'| Estimated similarity: {similarity_factor:.1f}%'}, - {'x': 0.55, 'y': 0.950, 'va': 'top', 'text': f'| {mhi} (experimental)'}, { - 'x': 0.551, - 'y': 0.915, + 'x': 0.480, + 'y': 0.953, 'va': 'top', - 'text': f'| Accel per Hz used: {accel_per_hz} mm/s²/Hz', - 'fontsize': 10, + 'fontsize': 13, + 'text': f'| Estimated similarity: {similarity_factor:.1f}%', }, + {'x': 0.480, 'y': 0.920, 'va': 'top', 'fontsize': 13, 'text': f'| {mhi} (experimental)'}, ] ) - else: - title_lines.append( - { - 'x': 0.551, - 'y': 0.915, - 'va': 'top', - 'text': f'| Accel per Hz used: {accel_per_hz} mm/s²/Hz', - 'fontsize': 10, - } - ) self.add_title(fig, title_lines) self.add_logo(fig) @@ -642,7 +644,7 @@ def plot_input_shaper_graph(self, data): bins = data['bins'] pdata = data['pdata'] # shapers_tradeoff_data = data['shapers_tradeoff_data'] - accel_per_hz = data['accel_per_hz'] + mode, _, _, accel_per_hz, _, sweeping_accel, sweeping_period = data['test_params'] max_smoothing = data['max_smoothing'] scv = data['scv'] st_version = data['st_version'] @@ -683,7 +685,10 @@ def plot_input_shaper_graph(self, data): title_line2 = measurements[0]['name'] title_line3 = '' title_line4 = '' - title_line5 = f'| Accel per Hz used: {accel_per_hz} mm/s²/Hz' if accel_per_hz is not None else '' + title_line5 = f'| Mode: {mode}' + title_line5 += f' -- ApH: {accel_per_hz}' if accel_per_hz is not None else '' + if mode == 'SWEEPING': + title_line5 += f' [sweeping period: {sweeping_accel} s - accel: {sweeping_accel} mm/s²]' title_lines = [ { 'x': 0.065, @@ -694,9 +699,9 @@ def plot_input_shaper_graph(self, data): 'weight': 'bold', }, {'x': 0.065, 'y': 0.957, 'va': 'top', 'text': title_line2}, - {'x': 0.500, 'y': 0.990, 'va': 'top', 'fontsize': 14, 'text': title_line3}, - {'x': 0.500, 'y': 0.968, 'va': 'top', 'fontsize': 14, 'text': title_line4}, - {'x': 0.501, 'y': 0.945, 'va': 'top', 'fontsize': 10, 'text': title_line5}, + {'x': 0.481, 'y': 0.990, 'va': 'top', 'fontsize': 11, 'text': title_line5}, + {'x': 0.480, 'y': 0.970, 'va': 'top', 'fontsize': 14, 'text': title_line3}, + {'x': 0.480, 'y': 0.949, 'va': 'top', 'fontsize': 14, 'text': title_line4}, ] self.add_title(fig, title_lines) self.add_logo(fig, position=[0.001, 0.924, 0.075, 0.075]) diff --git a/shaketune/graph_creators/shaper_graph_creator.py b/shaketune/graph_creators/shaper_graph_creator.py index ede8f69..a6cee94 100644 --- a/shaketune/graph_creators/shaper_graph_creator.py +++ b/shaketune/graph_creators/shaper_graph_creator.py @@ -22,6 +22,7 @@ detect_peaks, ) from ..helpers.console_output import ConsoleOutput +from ..helpers.resonance_test import testParams from ..shaketune_config import ShakeTuneConfig from . import get_shaper_calibrate_module from .graph_creator import GraphCreator @@ -42,18 +43,18 @@ def __init__(self, config: ShakeTuneConfig): super().__init__(config) self._max_smoothing: Optional[float] = None self._scv: Optional[float] = None - self._accel_per_hz: Optional[float] = None + self._test_params: Optional[testParams] = None def configure( self, scv: float, max_smoothing: Optional[float] = None, - accel_per_hz: Optional[float] = None, + test_params: Optional[testParams] = None, max_scale: Optional[int] = None, ) -> None: self._scv = scv self._max_smoothing = max_smoothing - self._accel_per_hz = accel_per_hz + self._test_params = test_params self._max_scale = max_scale def create_graph(self, measurements_manager: MeasurementsManager) -> None: @@ -61,7 +62,7 @@ def create_graph(self, measurements_manager: MeasurementsManager) -> None: measurements=measurements_manager.get_measurements(), max_smoothing=self._max_smoothing, scv=self._scv, - accel_per_hz=self._accel_per_hz, + test_params=self._test_params, max_freq=self._config.max_freq, max_scale=self._max_scale, st_version=self._version, @@ -88,7 +89,7 @@ class ShaperGraphComputation: def __init__( self, measurements: List[Measurement], - accel_per_hz: Optional[float], + test_params: Optional[testParams], scv: float, max_smoothing: Optional[float], max_freq: float, @@ -96,7 +97,7 @@ def __init__( st_version: str, ): self.measurements = measurements - self.accel_per_hz = accel_per_hz + self.test_params = test_params self.scv = scv self.max_smoothing = max_smoothing self.max_freq = max_freq @@ -227,7 +228,7 @@ def compute(self): 'bins': bins, 'pdata': pdata, 'shapers_tradeoff_data': shapers_tradeoff_data, - 'accel_per_hz': self.accel_per_hz, + 'test_params': self.test_params, 'max_smoothing': self.max_smoothing, 'scv': self.scv, 'st_version': self.st_version, diff --git a/shaketune/helpers/resonance_test.py b/shaketune/helpers/resonance_test.py index 09f8558..bcc00e0 100644 --- a/shaketune/helpers/resonance_test.py +++ b/shaketune/helpers/resonance_test.py @@ -19,9 +19,14 @@ import math +from collections import namedtuple from ..helpers.console_output import ConsoleOutput +testParams = namedtuple( + 'testParams', ['mode', 'min_freq', 'max_freq', 'accel_per_hz', 'hz_per_sec', 'sweeping_accel', 'sweeping_period'] +) + # This class is used to generate the base vibration test sequences # Note: it's almost untouched from the original Klipper code from Dmitry Butyugin @@ -180,7 +185,9 @@ def get_parameters(self): self.res_tester.generator.sweeping_accel, ) - def vibrate_axis(self, axis_direction, min_freq=None, max_freq=None, hz_per_sec=None, accel_per_hz=None): + def vibrate_axis( + self, axis_direction, min_freq=None, max_freq=None, hz_per_sec=None, accel_per_hz=None + ) -> testParams: base_min_freq, base_max_freq, base_aph, base_hps, base_s_period, base_s_accel = self.get_parameters() final_min_f = min_freq if min_freq is not None else base_min_freq @@ -193,19 +200,23 @@ def vibrate_axis(self, axis_direction, min_freq=None, max_freq=None, hz_per_sec= if s_period == 0 or self.is_old_klipper: ConsoleOutput.print('Using pulse-only test') gen = BaseVibrationGenerator(final_min_f, final_max_f, final_aph, final_hps) + test_params = testParams('PULSE-ONLY', final_min_f, final_max_f, final_aph, final_hps, None, None) else: ConsoleOutput.print('Using pulse test with additional sweeping') gen = SweepingVibrationGenerator(final_min_f, final_max_f, final_aph, final_hps, s_accel, s_period) + test_params = testParams('SWEEPING', final_min_f, final_max_f, final_aph, final_hps, s_accel, s_period) test_seq = gen.gen_test() self._run_test_sequence(axis_direction, test_seq) self.toolhead.wait_moves() + return test_params - def vibrate_axis_at_static_freq(self, axis_direction, freq, duration, accel_per_hz): + def vibrate_axis_at_static_freq(self, axis_direction, freq, duration, accel_per_hz) -> testParams: gen = StaticFrequencyVibrationGenerator(freq, accel_per_hz, duration) test_seq = gen.gen_test() self._run_test_sequence(axis_direction, test_seq) self.toolhead.wait_moves() + return testParams('static', freq, freq, accel_per_hz, None, None, None) def _run_test_sequence(self, axis_direction, test_seq): toolhead = self.toolhead @@ -309,11 +320,13 @@ def _project_distance(distance, normalized_direction): ) -def vibrate_axis(toolhead, gcode, axis_direction, min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester): +def vibrate_axis( + toolhead, gcode, axis_direction, min_freq, max_freq, hz_per_sec, accel_per_hz, res_tester +) -> testParams: manager = ResonanceTestManager(toolhead, gcode, res_tester) - manager.vibrate_axis(axis_direction, min_freq, max_freq, hz_per_sec, accel_per_hz) + return manager.vibrate_axis(axis_direction, min_freq, max_freq, hz_per_sec, accel_per_hz) -def vibrate_axis_at_static_freq(toolhead, gcode, axis_direction, freq, duration, accel_per_hz): +def vibrate_axis_at_static_freq(toolhead, gcode, axis_direction, freq, duration, accel_per_hz) -> testParams: manager = ResonanceTestManager(toolhead, gcode, None) - manager.vibrate_axis_at_static_freq(axis_direction, freq, duration, accel_per_hz) + return manager.vibrate_axis_at_static_freq(axis_direction, freq, duration, accel_per_hz)