From 55895c150785779b16b59bff3b95f0acef2085c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Boisselier?= Date: Thu, 16 May 2024 23:33:49 +0200 Subject: [PATCH] fixed most of the bugs now as a Klipper plugin --- shaketune/helpers/common_func.py | 8 +++ shaketune/measurement/__init__.py | 17 ------ shaketune/measurement/axes_input_shaper.py | 10 ++-- shaketune/measurement/axes_map.py | 9 ++- shaketune/measurement/belts_comparison.py | 10 ++-- shaketune/measurement/macros.cfg | 8 +++ shaketune/measurement/motorsconfigparser.py | 60 +++++++++---------- shaketune/measurement/static_freq.py | 8 ++- shaketune/measurement/vibrations_profile.py | 46 +++++++------- shaketune/post_processing/analyze_axesmap.py | 3 +- shaketune/post_processing/graph_creator.py | 4 +- shaketune/post_processing/graph_vibrations.py | 14 ++--- shaketune/shaketune.py | 25 ++++---- 13 files changed, 116 insertions(+), 106 deletions(-) create mode 100644 shaketune/measurement/macros.cfg diff --git a/shaketune/helpers/common_func.py b/shaketune/helpers/common_func.py index 6546347..b908da2 100644 --- a/shaketune/helpers/common_func.py +++ b/shaketune/helpers/common_func.py @@ -14,6 +14,14 @@ from scipy.signal import spectrogram from .console_output import ConsoleOutput +# Constant used to define the standard axis direction and names +AXIS_CONFIG = [ + {'axis': 'x', 'direction': (1, 0, 0), 'label': 'axis_X'}, + {'axis': 'y', 'direction': (0, 1, 0), 'label': 'axis_Y'}, + {'axis': 'a', 'direction': (1, -1, 0), 'label': 'belt_A'}, + {'axis': 'b', 'direction': (1, 1, 0), 'label': 'belt_B'}, +] + def parse_log(logname): try: diff --git a/shaketune/measurement/__init__.py b/shaketune/measurement/__init__.py index 8cffad7..72d968b 100644 --- a/shaketune/measurement/__init__.py +++ b/shaketune/measurement/__init__.py @@ -5,20 +5,3 @@ from .axes_map import axes_map_calibration as axes_map_calibration from .belts_comparison import compare_belts_responses as compare_belts_responses from .static_freq import excitate_axis_at_freq as excitate_axis_at_freq from .vibrations_profile import create_vibrations_profile as create_vibrations_profile - -AXIS_CONFIG = [ - {'axis': 'x', 'direction': (1, 0, 0), 'label': 'axis_X'}, - {'axis': 'y', 'direction': (0, 1, 0), 'label': 'axis_Y'}, - {'axis': 'a', 'direction': (1, -1, 0), 'label': 'belt_A'}, - {'axis': 'b', 'direction': (1, 1, 0), 'label': 'belt_B'}, -] - -# graph_creators = { -# 'axesmap': (AxesMapFinder, lambda gc: gc.configure(options.accel_used, options.chip_name)), -# 'belts': (BeltsGraphCreator, None), -# 'shaper': (ShaperGraphCreator, lambda gc: gc.configure(options.scv, options.max_smoothing)), -# 'vibrations': ( -# VibrationsGraphCreator, -# lambda gc: gc.configure(options.kinematics, options.accel_used, options.chip_name, options.metadata), -# ), -# } diff --git a/shaketune/measurement/axes_input_shaper.py b/shaketune/measurement/axes_input_shaper.py index d25209d..48b4d64 100644 --- a/shaketune/measurement/axes_input_shaper.py +++ b/shaketune/measurement/axes_input_shaper.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 +from ..helpers.common_func import AXIS_CONFIG from ..helpers.console_output import ConsoleOutput from ..shaketune_thread import ShakeTuneThread -from . import AXIS_CONFIG from .accelerometer import Accelerometer from .resonance_test import vibrate_axis -def axes_shaper_calibration(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> None: +def axes_shaper_calibration(gcmd, config, st_thread: ShakeTuneThread) -> None: min_freq = gcmd.get_float('FREQ_START', default=5, minval=1) max_freq = gcmd.get_float('FREQ_END', default=133.33, minval=1) hz_per_sec = gcmd.get_float('HZ_PER_SEC', default=1, minval=1) @@ -21,9 +21,11 @@ def axes_shaper_calibration(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> feedrate_travel = gcmd.get_float('TRAVEL_SPEED', default=120.0, minval=20.0) z_height = gcmd.get_float('Z_HEIGHT', default=None, minval=1) - systime = printer.get_reactor().monotonic() + printer = config.get_printer() + gcode = printer.lookup_object('gcode') toolhead = printer.lookup_object('toolhead') res_tester = printer.lookup_object('resonance_tester') + systime = printer.get_reactor().monotonic() if scv is None: toolhead_info = toolhead.get_status(systime) @@ -92,7 +94,7 @@ def axes_shaper_calibration(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> accelerometer.stop_measurement(config['label'], append_time=True) # And finally generate the graph for each measured axis - ConsoleOutput.print(f'{config['axis'].upper()} axis frequency profile generation...') + ConsoleOutput.print(f'{config["axis"].upper()} axis frequency profile generation...') ConsoleOutput.print('This may take some time (1-3min)') st_thread.run() diff --git a/shaketune/measurement/axes_map.py b/shaketune/measurement/axes_map.py index bbf0dc5..c386976 100644 --- a/shaketune/measurement/axes_map.py +++ b/shaketune/measurement/axes_map.py @@ -6,13 +6,18 @@ from ..shaketune_thread import ShakeTuneThread from .accelerometer import Accelerometer -def axes_map_calibration(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> None: +def axes_map_calibration(gcmd, config, st_thread: ShakeTuneThread) -> None: z_height = gcmd.get_float('Z_HEIGHT', default=20.0) speed = gcmd.get_float('SPEED', default=80.0, minval=20.0) accel = gcmd.get_int('ACCEL', default=1500, minval=100) feedrate_travel = gcmd.get_float('TRAVEL_SPEED', default=120.0, minval=20.0) accel_chip = gcmd.get('ACCEL_CHIP', default=None) + printer = config.get_printer() + gcode = printer.lookup_object('gcode') + toolhead = printer.lookup_object('toolhead') + systime = printer.get_reactor().monotonic() + if accel_chip is None: accel_chip = Accelerometer.find_axis_accelerometer(printer, 'xy') if accel_chip is None: @@ -21,8 +26,6 @@ def axes_map_calibration(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> No ) accelerometer = Accelerometer(printer.lookup_object(accel_chip)) - systime = printer.get_reactor().monotonic() - toolhead = printer.lookup_object('toolhead') toolhead_info = toolhead.get_status(systime) old_accel = toolhead_info['max_accel'] old_mcr = toolhead_info['minimum_cruise_ratio'] diff --git a/shaketune/measurement/belts_comparison.py b/shaketune/measurement/belts_comparison.py index 3e3a546..e0d312d 100644 --- a/shaketune/measurement/belts_comparison.py +++ b/shaketune/measurement/belts_comparison.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 +from ..helpers.common_func import AXIS_CONFIG from ..helpers.console_output import ConsoleOutput from ..shaketune_thread import ShakeTuneThread -from . import AXIS_CONFIG from .accelerometer import Accelerometer from .resonance_test import vibrate_axis -def compare_belts_responses(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> None: +def compare_belts_responses(gcmd, config, st_thread: ShakeTuneThread) -> None: min_freq = gcmd.get_float('FREQ_START', default=5.0, minval=1) max_freq = gcmd.get_float('FREQ_END', default=133.33, minval=1) hz_per_sec = gcmd.get_float('HZ_PER_SEC', default=1.0, minval=1) @@ -16,9 +16,11 @@ def compare_belts_responses(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> feedrate_travel = gcmd.get_float('TRAVEL_SPEED', default=120.0, minval=20.0) z_height = gcmd.get_float('Z_HEIGHT', default=None, minval=1) - systime = printer.get_reactor().monotonic() + printer = config.get_printer() + gcode = printer.lookup_object('gcode') toolhead = printer.lookup_object('toolhead') res_tester = printer.lookup_object('resonance_tester') + systime = printer.get_reactor().monotonic() accel_chip = Accelerometer.find_axis_accelerometer(printer, 'xy') if accel_chip is None: @@ -68,7 +70,7 @@ def compare_belts_responses(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> input_shaper = None # Filter axis configurations to get the A and B axis only - filtered_config = [a for a in AXIS_CONFIG if a['axis'] in ('x', 'y')] + filtered_config = [a for a in AXIS_CONFIG if a['axis'] in ('a', 'b')] for config in filtered_config: accelerometer.start_measurement() vibrate_axis(toolhead, gcode, config['direction'], min_freq, max_freq, hz_per_sec, accel_per_hz) diff --git a/shaketune/measurement/macros.cfg b/shaketune/measurement/macros.cfg new file mode 100644 index 0000000..c34a9d9 --- /dev/null +++ b/shaketune/measurement/macros.cfg @@ -0,0 +1,8 @@ + +# [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/measurement/motorsconfigparser.py b/shaketune/measurement/motorsconfigparser.py index 3dab656..4da86ba 100644 --- a/shaketune/measurement/motorsconfigparser.py +++ b/shaketune/measurement/motorsconfigparser.py @@ -4,8 +4,7 @@ # from the Klipper configuration and the TMC registers # Written by Frix_x#0161 # -import re -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional TRINAMIC_DRIVERS = ['tmc2130', 'tmc2208', 'tmc2209', 'tmc2240', 'tmc2660', 'tmc5160'] MOTORS = ['stepper_x', 'stepper_y', 'stepper_x1', 'stepper_y1', 'stepper_z', 'stepper_z1', 'stepper_z2', 'stepper_z3'] @@ -17,25 +16,20 @@ class Motor: self.name: str = name self._registers: Dict[str, Dict[str, Any]] = {} self._config: Dict[str, Any] = {} - self._driver: Tuple[str, Any] = ('', None) - - def set_driver(self, driver_name: str, tmc_object: Any) -> None: - self._driver = (driver_name, tmc_object) - - def get_driver(self) -> Tuple[str, Any]: - return self._driver def set_register(self, register: str, value_dict: dict) -> None: + # First we filter out entries with a value of 0 to avoid having too much uneeded data + value_dict = {k: v for k, v in value_dict.items() if v != 0} + # Special parsing for CHOPCONF to extract meaningful values if register == 'CHOPCONF': - # Add intpol=0 if missing from the register dump - if 'intpol=' not in value_dict: + # Add intpol=0 if missing from the register dump to force printing it as it's important + if 'intpol' not in value_dict: value_dict['intpol'] = '0' - # Simplify the microstep resolution format + # Remove the microsteps entry as the format here is not easy to read and + # it's already read in the correct format directly from the Klipper config if 'mres' in value_dict: - mres_match = re.search(r'(\d+)usteps', value_dict['mres']) - if mres_match: - value_dict['mres'] = mres_match.group(1) + del value_dict['mres'] # Special parsing for CHOPCONF to avoid pwm_ before each values if register == 'PWMCONF': @@ -46,7 +40,7 @@ class Motor: new_value_dict[key] = val value_dict = new_value_dict - # Then fill the registers while merging all the thresholds into the same THRS virtual register + # Then gets merged all the thresholds into the same THRS virtual register if register in ['TPWMTHRS', 'TCOOLTHRS']: existing_thrs = self._registers.get('THRS', {}) merged_values = {**existing_thrs, **value_dict} @@ -110,35 +104,42 @@ class Motor: class MotorsConfigParser: - def __init__(self, printer, motors: List[str] = MOTORS, drivers: List[str] = TRINAMIC_DRIVERS): + def __init__(self, config, motors: List[str] = MOTORS, drivers: List[str] = TRINAMIC_DRIVERS): + self._printer = config.get_printer() + self._motors: List[Motor] = [] - self._printer = printer for motor_name in motors: for driver in drivers: - tmc_object = printer.lookup_object(f'{driver} {motor_name}', None) + tmc_object = self._printer.lookup_object(f'{driver} {motor_name}', None) if tmc_object is None: continue motor = self._create_motor(motor_name, driver, tmc_object) self._motors.append(motor) + pconfig = self._printer.lookup_object('configfile') + self.kinematics = pconfig.status_raw_config['printer']['kinematics'] + # Create a Motor object with the given name, driver and TMC object # and fill it with the relevant configuration and registers def _create_motor(self, motor_name: str, driver: str, tmc_object: Any) -> Motor: motor = Motor(motor_name) - motor.set_driver(driver.upper(), tmc_object) + motor.set_config('tmc', driver) self._parse_klipper_config(motor, tmc_object) self._parse_tmc_registers(motor, tmc_object) return motor - def _parse_klipper_config(self, motor: Motor, tmc: Any) -> None: + def _parse_klipper_config(self, motor: Motor, tmc_object: Any) -> None: # The TMCCommandHelper isn't a direct member of the TMC object... but we can still get it this way - tmc_cmdhelper = tmc.get_status.__self__ + tmc_cmdhelper = tmc_object.get_status.__self__ motor_currents = tmc_cmdhelper.current_helper.get_current() motor.set_config('run_current', motor_currents[0]) motor.set_config('hold_current', motor_currents[1]) + pconfig = self._printer.lookup_object('configfile') + motor.set_config('microsteps', int(pconfig.status_raw_config[motor.name]['microsteps'])) + autotune_object = self._printer.lookup_object(f'autotune_tmc {motor.name}', None) if autotune_object is not None: motor.set_config('autotune_enabled', True) @@ -147,24 +148,21 @@ class MotorsConfigParser: else: motor.set_config('autotune_enabled', False) - def _parse_tmc_registers(self, motor: Motor, tmc: Any) -> None: + def _parse_tmc_registers(self, motor: Motor, tmc_object: Any) -> None: # The TMCCommandHelper isn't a direct member of the TMC object... but we can still get it this way - tmc_cmdhelper = tmc.get_status.__self__ + tmc_cmdhelper = tmc_object.get_status.__self__ for register in RELEVANT_TMC_REGISTERS: - # value = tmc_cmdhelper.read_register(register) - # motor.set_register(register, value) - val = tmc_cmdhelper.fields.registers.get(register) if (val is not None) and (register not in tmc_cmdhelper.read_registers): # write-only register - fields_string = self._extract_register_values(register, val) + fields_string = self._extract_register_values(tmc_cmdhelper, register, val) elif register in tmc_cmdhelper.read_registers: # readable register val = tmc_cmdhelper.mcu_tmc.get_register(register) if tmc_cmdhelper.read_translate is not None: register, val = tmc_cmdhelper.read_translate(register, val) - fields_string = self._extract_register_values(register, val) + fields_string = self._extract_register_values(tmc_cmdhelper, register, val) motor.set_register(register, fields_string) @@ -173,7 +171,7 @@ class MotorsConfigParser: reg_fields = tmc_cmdhelper.fields.all_fields.get(register, {}) reg_fields = sorted([(mask, name) for name, mask in reg_fields.items()]) fields = {} - for mask, field_name in reg_fields: + for _, field_name in reg_fields: field_value = tmc_cmdhelper.fields.get_field(field_name, val, register) fields[field_name] = field_value return fields @@ -181,7 +179,7 @@ class MotorsConfigParser: # Find and return the motor by its name def get_motor(self, motor_name: str) -> Optional[Motor]: for motor in self._motors: - if motor._name == motor_name: + if motor.name == motor_name: return motor return None diff --git a/shaketune/measurement/static_freq.py b/shaketune/measurement/static_freq.py index 7bc41b1..1dbf188 100644 --- a/shaketune/measurement/static_freq.py +++ b/shaketune/measurement/static_freq.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 +from ..helpers.common_func import AXIS_CONFIG from ..helpers.console_output import ConsoleOutput -from . import AXIS_CONFIG from .resonance_test import vibrate_axis -def excitate_axis_at_freq(gcmd, gcode, printer) -> None: +def excitate_axis_at_freq(gcmd, config) -> None: freq = gcmd.get_int('FREQUENCY', default=25, minval=1) duration = gcmd.get_int('DURATION', default=10, minval=1) accel_per_hz = gcmd.get_float('ACCEL_PER_HZ', default=None) @@ -19,9 +19,11 @@ def excitate_axis_at_freq(gcmd, gcode, printer) -> None: ConsoleOutput.print(f'Excitating {axis.upper()} axis at {freq}Hz for {duration} seconds') - systime = printer.get_reactor().monotonic() + printer = config.get_printer() + gcode = printer.lookup_object('gcode') toolhead = printer.lookup_object('toolhead') res_tester = printer.lookup_object('resonance_tester') + systime = printer.get_reactor().monotonic() if accel_per_hz is None: accel_per_hz = res_tester.test.accel_per_hz diff --git a/shaketune/measurement/vibrations_profile.py b/shaketune/measurement/vibrations_profile.py index f580d9f..31e748d 100644 --- a/shaketune/measurement/vibrations_profile.py +++ b/shaketune/measurement/vibrations_profile.py @@ -11,7 +11,7 @@ from .motorsconfigparser import MotorsConfigParser MIN_SPEED = 2 # mm/s -def create_vibrations_profile(gcmd, gcode, printer, st_thread: ShakeTuneThread) -> None: +def create_vibrations_profile(gcmd, config, st_thread: ShakeTuneThread) -> None: size = gcmd.get_float('SIZE', default=100.0, minval=50.0) z_height = gcmd.get_float('Z_HEIGHT', default=20.0) max_speed = gcmd.get_float('MAX_SPEED', default=200.0, minval=10.0) @@ -23,29 +23,30 @@ def create_vibrations_profile(gcmd, gcode, printer, st_thread: ShakeTuneThread) if (size / (max_speed / 60)) < 0.25: gcmd.error('The size of the movement is too small for the given speed! Increase SIZE or decrease MAX_SPEED!') - # Check that input shaper is already configured + printer = config.get_printer() + gcode = printer.lookup_object('gcode') + toolhead = printer.lookup_object('toolhead') input_shaper = printer.lookup_object('input_shaper', None) + systime = printer.get_reactor().monotonic() + + # Check that input shaper is already configured if input_shaper is None: gcmd.error('Input shaper is not configured! Please run the shaper calibration macro first.') - # TODO: Add the kinematics check to define the main_angles - # but this needs to retrieve it from the printer configuration - # {% if kinematics == "cartesian" %} - # # Cartesian motors are on X and Y axis directly - # RESPOND MSG="Cartesian kinematics mode" - # {% set main_angles = [0, 90] %} - # {% elif kinematics == "corexy" %} - # # CoreXY motors are on A and B axis (45 and 135 degrees) - # RESPOND MSG="CoreXY kinematics mode" - # {% set main_angles = [45, 135] %} - # {% else %} - # { action_raise_error("Only Cartesian and CoreXY kinematics are supported at the moment for the vibrations measurement tool!") } - # {% endif %} - kinematics = 'cartesian' - main_angles = [0, 90] + motors_config_parser = MotorsConfigParser(config, motors=['stepper_x', 'stepper_y']) + + if motors_config_parser.kinematics == 'cartesian' or motors_config_parser.kinematics == 'corexz': + # Cartesian motors are on X and Y axis directly, same for CoreXZ + main_angles = [0, 90] + elif motors_config_parser.kinematics == 'corexy': + # CoreXY motors are on A and B axis (45 and 135 degrees) + main_angles = [45, 135] + else: + gcmd.error( + 'Only Cartesian and CoreXY kinematics are supported at the moment for the vibrations measurement tool!' + ) + ConsoleOutput.print(f'{motors_config_parser.kinematics.upper()} kinematics mode') - systime = printer.get_reactor().monotonic() - toolhead = printer.lookup_object('toolhead') toolhead_info = toolhead.get_status(systime) old_accel = toolhead_info['max_accel'] old_mcr = toolhead_info['minimum_cruise_ratio'] @@ -66,6 +67,7 @@ def create_vibrations_profile(gcmd, gcode, printer, st_thread: ShakeTuneThread) nb_speed_samples = int((max_speed - MIN_SPEED) / speed_increment + 1) for curr_angle in main_angles: + ConsoleOutput.print(f'-> Measuring angle: {curr_angle} degrees...') radian_angle = math.radians(curr_angle) # Find the best accelerometer chip for the current angle if not specified @@ -86,6 +88,7 @@ def create_vibrations_profile(gcmd, gcode, printer, st_thread: ShakeTuneThread) # Sweep the speed range to record the vibrations at different speeds for curr_speed_sample in range(nb_speed_samples): curr_speed = MIN_SPEED + curr_speed_sample * speed_increment + ConsoleOutput.print(f'Current speed: {curr_speed} mm/s') # Reduce the segments length for the lower speed range (0-100mm/s). The minimum length is 1/3 of the SIZE and is gradually increased # to the nominal SIZE at 100mm/s. No further size changes are made above this speed. The goal is to ensure that the print head moves @@ -126,12 +129,9 @@ def create_vibrations_profile(gcmd, gcode, printer, st_thread: ShakeTuneThread) ) toolhead.wait_moves() - # Get the motors and TMC configurations from Klipper - motors_config_parser = MotorsConfigParser(printer, motors=['stepper_x', 'stepper_y']) - # Run post-processing ConsoleOutput.print('Machine vibrations profile generation...') ConsoleOutput.print('This may take some time (5-8min)') creator = st_thread.get_graph_creator() - creator.configure(kinematics, accel, motors_config_parser) + creator.configure(motors_config_parser.kinematics, accel, motors_config_parser) st_thread.run() diff --git a/shaketune/post_processing/analyze_axesmap.py b/shaketune/post_processing/analyze_axesmap.py index 1a818d9..4c094a3 100644 --- a/shaketune/post_processing/analyze_axesmap.py +++ b/shaketune/post_processing/analyze_axesmap.py @@ -109,7 +109,8 @@ def axesmap_calibration(lognames, accel=None): axes_map = ','.join([f'{spike[0][0]}{spike[1]}' for spike in spikes_sorted]) # alignment_error, sensitivity_error = compute_errors(filtered_data, spikes_sorted, accel, NUM_POINTS) - results = f'Detected axes_map:\n {axes_map}\n' + results = f'Be aware that this macro is experimental and has been known to sometimes produce incorrect results. Use it with caution and always check the results!\n' + results += f'Detected axes_map:\n {axes_map}\n' # TODO: work on this function that is currently not giving good results... # results += "Accelerometer angle deviation:\n" diff --git a/shaketune/post_processing/graph_creator.py b/shaketune/post_processing/graph_creator.py index d8af166..9316bcb 100644 --- a/shaketune/post_processing/graph_creator.py +++ b/shaketune/post_processing/graph_creator.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import abc +import re import shutil import tarfile from datetime import datetime @@ -189,6 +190,7 @@ class VibrationsGraphCreator(GraphCreator): with tarfile.open(tar_path, 'w:gz') as tar: for csv_file in lognames: tar.add(csv_file, arcname=csv_file.name, recursive=False) + csv_file.unlink() def create_graph(self) -> None: if not self._accel or not self._kinematics: @@ -197,7 +199,7 @@ class VibrationsGraphCreator(GraphCreator): lognames = self._move_and_prepare_files( glob_pattern='shaketune-vib_*.csv', min_files_required=None, - custom_name_func=lambda f: f.name, + custom_name_func=lambda f: re.search(r'shaketune-vib_(.*?)_\d{8}_\d{6}', f.name).group(1), ) fig = vibrations_profile( lognames=[str(path) for path in lognames], diff --git a/shaketune/post_processing/graph_vibrations.py b/shaketune/post_processing/graph_vibrations.py index 05bcf7e..48c32a9 100644 --- a/shaketune/post_processing/graph_vibrations.py +++ b/shaketune/post_processing/graph_vibrations.py @@ -564,23 +564,23 @@ def plot_motor_config_txt(fig, motors, differences): motor_details = [(motors[0], 'X motor'), (motors[1], 'Y motor')] distance = 0.12 - if motors[0].get_property('autotune_enabled'): - distance = 0.24 + if motors[0].get_config('autotune_enabled'): + distance = 0.27 config_blocks = [ - f"| {lbl}: {mot.get_property('motor').upper()} on {mot.get_property('tmc').upper()} @ {mot.get_property('voltage')}V {mot.get_property('run_current')}A" + f"| {lbl}: {mot.get_config('motor').upper()} on {mot.get_config('tmc').upper()} @ {mot.get_config('voltage'):0.1f}V {mot.get_config('run_current'):0.2f}A - {mot.get_config('microsteps')}usteps" for mot, lbl in motor_details ] config_blocks.append('| TMC Autotune enabled') else: config_blocks = [ - f"| {lbl}: {mot.get_property('tmc').upper()} @ {mot.get_property('run_current')}A" + f"| {lbl}: {mot.get_config('tmc').upper()} @ {mot.get_config('run_current'):0.2f}A - {mot.get_config('microsteps')}usteps" for mot, lbl in motor_details ] config_blocks.append('| TMC Autotune not detected') for idx, block in enumerate(config_blocks): fig.text( - 0.40, 0.990 - 0.015 * idx, block, ha='left', va='top', fontsize=10, color=KLIPPAIN_COLORS['dark_purple'] + 0.41, 0.990 - 0.015 * idx, block, ha='left', va='top', fontsize=10, color=KLIPPAIN_COLORS['dark_purple'] ) tmc_registers = motors[0].get_registers() @@ -589,7 +589,7 @@ def plot_motor_config_txt(fig, motors, differences): settings_str = ' '.join(f'{k}={v}' for k, v in settings.items()) tmc_block = f'| {register.upper()}: {settings_str}' fig.text( - 0.40 + distance, + 0.41 + distance, 0.990 - 0.015 * idx, tmc_block, ha='left', @@ -601,7 +601,7 @@ def plot_motor_config_txt(fig, motors, differences): if differences is not None: differences_text = f'| Y motor diff: {differences}' fig.text( - 0.40 + distance, + 0.41 + distance, 0.990 - 0.015 * (idx + 1), differences_text, ha='left', diff --git a/shaketune/shaketune.py b/shaketune/shaketune.py index 6999bd2..f7d058b 100644 --- a/shaketune/shaketune.py +++ b/shaketune/shaketune.py @@ -18,8 +18,9 @@ from .shaketune_thread import ShakeTuneThread class ShakeTune: def __init__(self, config) -> None: + self._pconfig = config self._printer = config.get_printer() - self._gcode = self._printer.lookup_object('gcode') + gcode = self._printer.lookup_object('gcode') res_tester = self._printer.lookup_object('resonance_tester') if res_tester is None: @@ -34,29 +35,29 @@ class ShakeTune: 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(self._gcode.respond_info) + ConsoleOutput.register_output_callback(gcode.respond_info) - self._gcode.register_command( + gcode.register_command( 'EXCITATE_AXIS_AT_FREQ', self.cmd_EXCITATE_AXIS_AT_FREQ, desc=self.cmd_EXCITATE_AXIS_AT_FREQ_help, ) - self._gcode.register_command( + gcode.register_command( 'AXES_MAP_CALIBRATION', self.cmd_AXES_MAP_CALIBRATION, desc=self.cmd_AXES_MAP_CALIBRATION_help, ) - self._gcode.register_command( + gcode.register_command( 'COMPARE_BELTS_RESPONSES', self.cmd_COMPARE_BELTS_RESPONSES, desc=self.cmd_COMPARE_BELTS_RESPONSES_help, ) - self._gcode.register_command( + gcode.register_command( 'AXES_SHAPER_CALIBRATION', self.cmd_AXES_SHAPER_CALIBRATION, desc=self.cmd_AXES_SHAPER_CALIBRATION_help, ) - self._gcode.register_command( + gcode.register_command( 'CREATE_VIBRATIONS_PROFILE', self.cmd_CREATE_VIBRATIONS_PROFILE, desc=self.cmd_CREATE_VIBRATIONS_PROFILE_help, @@ -68,7 +69,7 @@ class ShakeTune: 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._gcode, self._printer) + 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' @@ -76,7 +77,7 @@ class ShakeTune: 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._gcode, self._printer, st_thread) + 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' @@ -84,7 +85,7 @@ class ShakeTune: 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._gcode, self._printer, st_thread) + 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' @@ -94,7 +95,7 @@ class ShakeTune: 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._gcode, self._printer, st_thread) + 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' @@ -102,4 +103,4 @@ class ShakeTune: ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}') vibration_profile_creator = VibrationsGraphCreator(self._config) st_thread = ShakeTuneThread(self._config, vibration_profile_creator, self._printer.get_reactor(), self.timeout) - create_vibrations_profile(gcmd, self._gcode, self._printer, st_thread) + create_vibrations_profile(gcmd, self._pconfig, st_thread)