Skip to content

Instantly share code, notes, and snippets.

@kmobs
Last active May 4, 2025 17:47
Show Gist options
  • Save kmobs/f6def5db272ca5c1b81727482f53bed8 to your computer and use it in GitHub Desktop.
Save kmobs/f6def5db272ca5c1b81727482f53bed8 to your computer and use it in GitHub Desktop.

Revisions

  1. kmobs revised this gist Apr 17, 2022. 1 changed file with 80 additions and 80 deletions.
    160 changes: 80 additions & 80 deletions frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -11,91 +11,91 @@ The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`
    Place the following in `klippy/extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.


    import logging, math, os, time
    import logging, math, os, time

    class TestAxis:
    def __init__(self, axis=None, vib_dir=None):
    if axis is None:
    self._name = "axis=%.3f,%.3f" % (vib_dir[0], vib_dir[1])
    else:
    self._name = axis
    if vib_dir is None:
    self._vib_dir = (1., 0.) if axis == 'x' else (0., 1.)
    else:
    s = math.sqrt(sum([d*d for d in vib_dir]))
    self._vib_dir = [d / s for d in vib_dir]
    def matches(self, chip_axis):
    if self._vib_dir[0] and 'x' in chip_axis:
    return True
    if self._vib_dir[1] and 'y' in chip_axis:
    return True
    return False
    def get_name(self):
    return self._name
    def get_point(self, l):
    return (self._vib_dir[0] * l, self._vib_dir[1] * l)
    class TestAxis:
    def __init__(self, axis=None, vib_dir=None):
    if axis is None:
    self._name = "axis=%.3f,%.3f" % (vib_dir[0], vib_dir[1])
    else:
    self._name = axis
    if vib_dir is None:
    self._vib_dir = (1., 0.) if axis == 'x' else (0., 1.)
    else:
    s = math.sqrt(sum([d*d for d in vib_dir]))
    self._vib_dir = [d / s for d in vib_dir]
    def matches(self, chip_axis):
    if self._vib_dir[0] and 'x' in chip_axis:
    return True
    if self._vib_dir[1] and 'y' in chip_axis:
    return True
    return False
    def get_name(self):
    return self._name
    def get_point(self, l):
    return (self._vib_dir[0] * l, self._vib_dir[1] * l)

    def _parse_axis(gcmd, raw_axis):
    if raw_axis is None:
    return None
    raw_axis = raw_axis.lower()
    if raw_axis in ['x', 'y']:
    return TestAxis(axis=raw_axis)
    dirs = raw_axis.split(',')
    if len(dirs) != 2:
    raise gcmd.error("Invalid format of axis '%s'" % (raw_axis,))
    try:
    dir_x = float(dirs[0].strip())
    dir_y = float(dirs[1].strip())
    except:
    raise gcmd.error(
    "Unable to parse axis direction '%s'" % (raw_axis,))
    return TestAxis(vib_dir=(dir_x, dir_y))
    def _parse_axis(gcmd, raw_axis):
    if raw_axis is None:
    return None
    raw_axis = raw_axis.lower()
    if raw_axis in ['x', 'y']:
    return TestAxis(axis=raw_axis)
    dirs = raw_axis.split(',')
    if len(dirs) != 2:
    raise gcmd.error("Invalid format of axis '%s'" % (raw_axis,))
    try:
    dir_x = float(dirs[0].strip())
    dir_y = float(dirs[1].strip())
    except:
    raise gcmd.error(
    "Unable to parse axis direction '%s'" % (raw_axis,))
    return TestAxis(vib_dir=(dir_x, dir_y))


    class ResonanceHolder:
    def __init__(self, config):
    self.printer = config.get_printer()
    self.gcode = self.printer.lookup_object('gcode')
    self.accel_per_hz = config.getfloat('accel_per_hz', 75., above=0.)
    self.gcode.register_command("HOLD_RESONANCE", self.cmd_HOLD_RESONANCE, desc=self.cmd_HOLD_RESONANCE_help)
    class ResonanceHolder:
    def __init__(self, config):
    self.printer = config.get_printer()
    self.gcode = self.printer.lookup_object('gcode')
    self.accel_per_hz = config.getfloat('accel_per_hz', 75., above=0.)
    self.gcode.register_command("HOLD_RESONANCE", self.cmd_HOLD_RESONANCE, desc=self.cmd_HOLD_RESONANCE_help)

    def hold(self, gcmd, axis, seconds, freq):
    '''holds a resonance for N seconds
    resonance code taken from klipper's test_resonances command'''
    end = time.time() + seconds
    toolhead = self.printer.lookup_object('toolhead')
    X, Y, Z, E = toolhead.get_position()
    sign = 1.
    input_shaper = self.printer.lookup_object('input_shaper', None)
    if input_shaper is not None and not gcmd.get_int('INPUT_SHAPING', 0):
    input_shaper.disable_shaping()
    gcmd.respond_info("Disabled [input_shaper] for resonance holding")
    else:
    input_shaper = None
    gcmd.respond_info("starting freq %i for %i seconds" % (freq, seconds))
    while time.time() < end:
    t_seg = .25 / freq
    accel = self.accel_per_hz * freq
    max_v = accel * t_seg
    toolhead.cmd_M204(self.gcode.create_gcode_command(
    "M204", "M204", {"S": accel}))
    L = .5 * accel * t_seg**2
    dX, dY = axis.get_point(L)
    nX = X + sign * dX
    nY = Y + sign * dY
    toolhead.move([nX, nY, Z, E], max_v)
    toolhead.move([X, Y, Z, E], max_v)
    sign = -sign
    gcmd.respond_info("DONE")
    def hold(self, gcmd, axis, seconds, freq):
    '''holds a resonance for N seconds
    resonance code taken from klipper's test_resonances command'''
    end = time.time() + seconds
    toolhead = self.printer.lookup_object('toolhead')
    X, Y, Z, E = toolhead.get_position()
    sign = 1.
    input_shaper = self.printer.lookup_object('input_shaper', None)
    if input_shaper is not None and not gcmd.get_int('INPUT_SHAPING', 0):
    input_shaper.disable_shaping()
    gcmd.respond_info("Disabled [input_shaper] for resonance holding")
    else:
    input_shaper = None
    gcmd.respond_info("starting freq %i for %i seconds" % (freq, seconds))
    while time.time() < end:
    t_seg = .25 / freq
    accel = self.accel_per_hz * freq
    max_v = accel * t_seg
    toolhead.cmd_M204(self.gcode.create_gcode_command(
    "M204", "M204", {"S": accel}))
    L = .5 * accel * t_seg**2
    dX, dY = axis.get_point(L)
    nX = X + sign * dX
    nY = Y + sign * dY
    toolhead.move([nX, nY, Z, E], max_v)
    toolhead.move([X, Y, Z, E], max_v)
    sign = -sign
    gcmd.respond_info("DONE")


    cmd_HOLD_RESONANCE_help = ("Holds resonance for n seconds")
    def cmd_HOLD_RESONANCE(self, gcmd):
    axis = _parse_axis(gcmd, gcmd.get("AXIS").lower())
    freq = gcmd.get("FREQ", parser=int)
    seconds = gcmd.get("SECONDS", parser=int)
    self.hold(gcmd, axis, seconds, freq)
    cmd_HOLD_RESONANCE_help = ("Holds resonance for n seconds")
    def cmd_HOLD_RESONANCE(self, gcmd):
    axis = _parse_axis(gcmd, gcmd.get("AXIS").lower())
    freq = gcmd.get("FREQ", parser=int)
    seconds = gcmd.get("SECONDS", parser=int)
    self.hold(gcmd, axis, seconds, freq)

    def load_config(config):
    return ResonanceHolder(config)
    def load_config(config):
    return ResonanceHolder(config)
  2. kmobs revised this gist Apr 17, 2022. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`
    Place the following in `klippy/extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.


    ```import logging, math, os, time
    import logging, math, os, time

    class TestAxis:
    def __init__(self, axis=None, vib_dir=None):
    @@ -99,4 +99,3 @@ class ResonanceHolder:

    def load_config(config):
    return ResonanceHolder(config)
    ```
  3. kmobs revised this gist Apr 17, 2022. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,8 @@ You have to have `[resonance_holder]` in your printer.cfg.
    The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`

    Place the following in `klippy/extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.


    ```import logging, math, os, time
    class TestAxis:
    @@ -96,4 +98,5 @@ class ResonanceHolder:
    self.hold(gcmd, axis, seconds, freq)
    def load_config(config):
    return ResonanceHolder(config)
    return ResonanceHolder(config)
    ```
  4. kmobs revised this gist Apr 17, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -96,4 +96,4 @@ class ResonanceHolder:
    self.hold(gcmd, axis, seconds, freq)
    def load_config(config):
    return ResonanceHolder(config)```
    return ResonanceHolder(config)
  5. kmobs revised this gist Apr 17, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@ You have to have `[resonance_holder]` in your printer.cfg.

    The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`

    Place the following in `extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.
    Place the following in `klippy/extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.
    ```import logging, math, os, time
    class TestAxis:
  6. kmobs revised this gist Apr 17, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    ## Frequency Testing
    This will allow you to test a specific frequency that you hear when you do your resonance testing in Klipper and potentially track down where extra peaks are coming from. If something is rattling at a specific frequency, you can specify that frequency and feel around the printer until you track it down.

    Code was written by Zifnab.
    Code was adopted by zifnab from somewhere in Klipper.

    ## Usage
    You have to have `[resonance_holder]` in your printer.cfg.
  7. kmobs revised this gist Apr 17, 2022. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@ Code was written by Zifnab.

    ## Usage
    You have to have `[resonance_holder]` in your printer.cfg.

    The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`

    Place the following in `extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.
  8. kmobs created this gist Apr 17, 2022.
    98 changes: 98 additions & 0 deletions frequencytester.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    ## Frequency Testing
    This will allow you to test a specific frequency that you hear when you do your resonance testing in Klipper and potentially track down where extra peaks are coming from. If something is rattling at a specific frequency, you can specify that frequency and feel around the printer until you track it down.

    Code was written by Zifnab.

    ## Usage
    You have to have `[resonance_holder]` in your printer.cfg.
    The command is `HOLD_RESONANCE AXIS=<axis> FREQ=int SECONDS=<seconds>`

    Place the following in `extras/resonance_holder.py` and restart klipper (not firmware restart) to gain the module.
    ```import logging, math, os, time
    class TestAxis:
    def __init__(self, axis=None, vib_dir=None):
    if axis is None:
    self._name = "axis=%.3f,%.3f" % (vib_dir[0], vib_dir[1])
    else:
    self._name = axis
    if vib_dir is None:
    self._vib_dir = (1., 0.) if axis == 'x' else (0., 1.)
    else:
    s = math.sqrt(sum([d*d for d in vib_dir]))
    self._vib_dir = [d / s for d in vib_dir]
    def matches(self, chip_axis):
    if self._vib_dir[0] and 'x' in chip_axis:
    return True
    if self._vib_dir[1] and 'y' in chip_axis:
    return True
    return False
    def get_name(self):
    return self._name
    def get_point(self, l):
    return (self._vib_dir[0] * l, self._vib_dir[1] * l)
    def _parse_axis(gcmd, raw_axis):
    if raw_axis is None:
    return None
    raw_axis = raw_axis.lower()
    if raw_axis in ['x', 'y']:
    return TestAxis(axis=raw_axis)
    dirs = raw_axis.split(',')
    if len(dirs) != 2:
    raise gcmd.error("Invalid format of axis '%s'" % (raw_axis,))
    try:
    dir_x = float(dirs[0].strip())
    dir_y = float(dirs[1].strip())
    except:
    raise gcmd.error(
    "Unable to parse axis direction '%s'" % (raw_axis,))
    return TestAxis(vib_dir=(dir_x, dir_y))
    class ResonanceHolder:
    def __init__(self, config):
    self.printer = config.get_printer()
    self.gcode = self.printer.lookup_object('gcode')
    self.accel_per_hz = config.getfloat('accel_per_hz', 75., above=0.)
    self.gcode.register_command("HOLD_RESONANCE", self.cmd_HOLD_RESONANCE, desc=self.cmd_HOLD_RESONANCE_help)
    def hold(self, gcmd, axis, seconds, freq):
    '''holds a resonance for N seconds
    resonance code taken from klipper's test_resonances command'''
    end = time.time() + seconds
    toolhead = self.printer.lookup_object('toolhead')
    X, Y, Z, E = toolhead.get_position()
    sign = 1.
    input_shaper = self.printer.lookup_object('input_shaper', None)
    if input_shaper is not None and not gcmd.get_int('INPUT_SHAPING', 0):
    input_shaper.disable_shaping()
    gcmd.respond_info("Disabled [input_shaper] for resonance holding")
    else:
    input_shaper = None
    gcmd.respond_info("starting freq %i for %i seconds" % (freq, seconds))
    while time.time() < end:
    t_seg = .25 / freq
    accel = self.accel_per_hz * freq
    max_v = accel * t_seg
    toolhead.cmd_M204(self.gcode.create_gcode_command(
    "M204", "M204", {"S": accel}))
    L = .5 * accel * t_seg**2
    dX, dY = axis.get_point(L)
    nX = X + sign * dX
    nY = Y + sign * dY
    toolhead.move([nX, nY, Z, E], max_v)
    toolhead.move([X, Y, Z, E], max_v)
    sign = -sign
    gcmd.respond_info("DONE")
    cmd_HOLD_RESONANCE_help = ("Holds resonance for n seconds")
    def cmd_HOLD_RESONANCE(self, gcmd):
    axis = _parse_axis(gcmd, gcmd.get("AXIS").lower())
    freq = gcmd.get("FREQ", parser=int)
    seconds = gcmd.get("SECONDS", parser=int)
    self.hold(gcmd, axis, seconds, freq)
    def load_config(config):
    return ResonanceHolder(config)```