small code cleaning and fixes
This commit is contained in:
12
README.md
12
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.
|
# The maximum time in seconds to let Shake&Tune process the CSV files and generate the graphs.
|
||||||
|
|
||||||
# motor_freq:
|
# 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
|
# 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.
|
# section to be defined in your printer.cfg file to work.
|
||||||
# motor_freq_x:
|
# motor_freq_x:
|
||||||
# motor_freq_y:
|
# 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
|
# If motor_freq is not set, these two parameters can be used
|
||||||
# to configure different filters for X and Y motors. The same
|
# to configure different filters for X and Y motors. The same
|
||||||
# values are supported as for motor_freq parameter.
|
# values are supported as for motor_freq parameter.
|
||||||
# motor_damping_ratio: 0.05
|
# motor_damping_ratio: 0.05
|
||||||
# /!\ This option is only available in DangerKlipper /!\
|
# /!\ This option has limitations in stock Klipper and is best used with DangerKlipper /!\
|
||||||
# Damping ratios of X and Y motor resonances.
|
# Damping ratios for X and Y motor resonances.
|
||||||
# motor_damping_ratio_x:
|
# motor_damping_ratio_x:
|
||||||
# motor_damping_ratio_y:
|
# 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
|
# 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
|
# to configure different filters for X and Y motors. The same values
|
||||||
# are supported as for motor_damping_ratio parameter.
|
# are supported as for motor_damping_ratio parameter.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class MotorResonanceFilter:
|
|||||||
|
|
||||||
self._original_shapers = {}
|
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
|
@staticmethod
|
||||||
def convolve_shapers(L, R):
|
def convolve_shapers(L, R):
|
||||||
As = [a * b for a in L[0] for b in R[0]]
|
As = [a * b for a in L[0] for b in R[0]]
|
||||||
@@ -36,6 +36,11 @@ class MotorResonanceFilter:
|
|||||||
|
|
||||||
def apply_filters(self) -> None:
|
def apply_filters(self) -> None:
|
||||||
input_shaper = self._printer.lookup_object('input_shaper', 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()
|
shapers = input_shaper.get_shapers()
|
||||||
for shaper in shapers:
|
for shaper in shapers:
|
||||||
axis = shaper.axis
|
axis = shaper.axis
|
||||||
@@ -71,7 +76,7 @@ class MotorResonanceFilter:
|
|||||||
ConsoleOutput.print(
|
ConsoleOutput.print(
|
||||||
(
|
(
|
||||||
f'Error: the {axis} axis is not a ZV type shaper. Shake&Tune motor resonance filters '
|
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 '
|
'small and not allowing the convolved shapers to be applied... unless this PR is '
|
||||||
'merged: https://github.com/Klipper3d/klipper/pull/6460'
|
'merged: https://github.com/Klipper3d/klipper/pull/6460'
|
||||||
)
|
)
|
||||||
@@ -109,6 +114,11 @@ class MotorResonanceFilter:
|
|||||||
|
|
||||||
def remove_filters(self) -> None:
|
def remove_filters(self) -> None:
|
||||||
input_shaper = self._printer.lookup_object('input_shaper', 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()
|
shapers = input_shaper.get_shapers()
|
||||||
for shaper in shapers:
|
for shaper in shapers:
|
||||||
axis = shaper.axis
|
axis = shaper.axis
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from .motor_res_filter import MotorResonanceFilter
|
|||||||
from .shaketune_config import ShakeTuneConfig
|
from .shaketune_config import ShakeTuneConfig
|
||||||
from .shaketune_process import ShakeTuneProcess
|
from .shaketune_process import ShakeTuneProcess
|
||||||
|
|
||||||
IN_DANGER = False
|
|
||||||
DEFAULT_MOTOR_DAMPING_RATIO = 0.05
|
DEFAULT_MOTOR_DAMPING_RATIO = 0.05
|
||||||
ST_COMMANDS = {
|
ST_COMMANDS = {
|
||||||
'EXCITATE_AXIS_AT_FREQ': (
|
'EXCITATE_AXIS_AT_FREQ': (
|
||||||
@@ -58,33 +57,18 @@ class ShakeTune:
|
|||||||
def __init__(self, config) -> None:
|
def __init__(self, config) -> None:
|
||||||
self._config = config
|
self._config = config
|
||||||
self._printer = config.get_printer()
|
self._printer = config.get_printer()
|
||||||
|
self._printer.register_event_handler('klippy:connect', self._on_klippy_connect)
|
||||||
|
|
||||||
self._initialize_danger_klipper()
|
# Check if Shake&Tune is running in DangerKlipper
|
||||||
self._initialize_console_output()
|
self.IN_DANGER = importlib.util.find_spec('extras.danger_options') is not None
|
||||||
self._validate_resonance_tester()
|
|
||||||
self._initialize_config(config)
|
|
||||||
self._register_commands()
|
|
||||||
self._initialize_motor_resonance_filter()
|
|
||||||
|
|
||||||
# Check if Shake&Tune is running in DangerKlipper
|
# Register the console print output callback to the corresponding Klipper function
|
||||||
def _initialize_danger_klipper(self) -> None:
|
|
||||||
global IN_DANGER
|
|
||||||
if importlib.util.find_spec('extras.danger_options') is not None:
|
|
||||||
IN_DANGER = True
|
|
||||||
|
|
||||||
# Register the console print output callback to the corresponding Klipper function
|
|
||||||
def _initialize_console_output(self) -> None:
|
|
||||||
gcode = self._printer.lookup_object('gcode')
|
gcode = self._printer.lookup_object('gcode')
|
||||||
ConsoleOutput.register_output_callback(gcode.respond_info)
|
ConsoleOutput.register_output_callback(gcode.respond_info)
|
||||||
|
|
||||||
# Check if the resonance_tester object is available in the printer
|
self._initialize_config(config)
|
||||||
# configuration as it is required for Shake&Tune to work properly
|
self._register_commands()
|
||||||
def _validate_resonance_tester(self) -> None:
|
self._initialize_motor_resonance_filter()
|
||||||
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.'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Initialize the ShakeTune object and its configuration
|
# Initialize the ShakeTune object and its configuration
|
||||||
def _initialize_config(self, config) -> None:
|
def _initialize_config(self, config) -> None:
|
||||||
@@ -155,44 +139,63 @@ class ShakeTune:
|
|||||||
self._printer.load_object(self._config, gcode_macro_name.lower())
|
self._printer.load_object(self._config, gcode_macro_name.lower())
|
||||||
|
|
||||||
# Register the motor resonance filters if they are defined in the config
|
# 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
|
# 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. But this will
|
# 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
|
# 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.
|
# (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
|
# 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
|
# 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?
|
# manual command to apply the patch with a required user action?
|
||||||
def _initialize_motor_resonance_filter(self) -> None:
|
def _initialize_motor_resonance_filter(self) -> None:
|
||||||
if self._motor_freq_x is not None and self._motor_freq_y is not 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)
|
self._printer.register_event_handler('klippy:ready', self._on_klippy_ready)
|
||||||
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!'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
gcode = self._printer.lookup_object('gcode')
|
gcode = self._printer.lookup_object('gcode')
|
||||||
gcode.register_command(
|
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.motor_resonance_filter = MotorResonanceFilter(
|
||||||
self._printer,
|
self._printer,
|
||||||
self._motor_freq_x,
|
self._motor_freq_x,
|
||||||
self._motor_freq_y,
|
self._motor_freq_y,
|
||||||
self._motor_damping_x,
|
self._motor_damping_x,
|
||||||
self._motor_damping_y,
|
self._motor_damping_y,
|
||||||
IN_DANGER,
|
self.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!'
|
||||||
|
)
|
||||||
|
|
||||||
def handle_ready(self) -> None:
|
# 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 _on_klippy_ready(self) -> None:
|
||||||
self.motor_resonance_filter.apply_filters()
|
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:
|
def cmd_EXCITATE_AXIS_AT_FREQ(self, gcmd) -> None:
|
||||||
ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}')
|
ConsoleOutput.print(f'Shake&Tune version: {ShakeTuneConfig.get_git_version()}')
|
||||||
static_freq_graph_creator = StaticGraphCreator(self._st_config)
|
static_freq_graph_creator = StaticGraphCreator(self._st_config)
|
||||||
|
|||||||
Reference in New Issue
Block a user