Skip to content

Tuning

Input shaper, accel chooser, prime-line macro, and nozzle scrub — the configs that fall out of post-build tuning sessions and get iterated on over time.

InputShaper.cfg

Output of SHAPER_CALIBRATE for X and Y. Frequencies referenced from printer.cfg’s [input_shaper] block.

# Klipper input shaper
[mcu rpi]
serial: /tmp/klipper_host_mcu

[adxl345]
cs_pin: rpi:None

[resonance_tester]
accel_chip: adxl345
probe_points:
    150,150,20  # center of bed

Accel.cfg

Accel test harness — TEST_SPEED runs and accel chooser macros.

# Home, get position, throw around toolhead, home again.
# If MCU stepper positions (first line in GET_POSITION) are greater than a full step different (your number of microsteps), then skipping occured.
# We only measure to a full step to accomodate for endstop variance.
# Example: TEST_SPEED SPEED=300 ACCEL=5000 ITERATIONS=10

[gcode_macro TEST_SPEED]
gcode:
	# Speed
	{% set speed  = params.SPEED|default(printer.configfile.settings.printer.max_velocity)|int %}
	# Iterations
	{% set iterations = params.ITERATIONS|default(5)|int %}
	# Acceleration
	{% set accel  = params.ACCEL|default(printer.configfile.settings.printer.max_accel)|int %}
	# Bounding inset for large pattern (helps prevent slamming the toolhead into the sides after small skips, and helps to account for machines with imperfectly set dimensions)
	{% set bound = params.BOUND|default(20)|int %}
	# Size for small pattern box
	{% set smallpatternsize = SMALLPATTERNSIZE|default(20)|int %}
	
	# Large pattern
		# Max positions, inset by BOUND
		{% set x_min = printer.toolhead.axis_minimum.x + bound %}
		{% set x_max = printer.toolhead.axis_maximum.x - bound %}
		{% set y_min = printer.toolhead.axis_minimum.y + bound %}
		{% set y_max = printer.toolhead.axis_maximum.y - bound %}
	
	# Small pattern at center
		# Find X/Y center point
		{% set x_center = (printer.toolhead.axis_minimum.x|float + printer.toolhead.axis_maximum.x|float ) / 2 %}
		{% set y_center = (printer.toolhead.axis_minimum.y|float + printer.toolhead.axis_maximum.y|float ) / 2 %}
		
		# Set small pattern box around center point
		{% set x_center_min = x_center - (smallpatternsize/2) %}
		{% set x_center_max = x_center + (smallpatternsize/2) %}
		{% set y_center_min = y_center - (smallpatternsize/2) %}
		{% set y_center_max = y_center + (smallpatternsize/2) %}

	# Save current gcode state (absolute/relative, etc)
	SAVE_GCODE_STATE NAME=TEST_SPEED
	
	# Output parameters to g-code terminal
	{ action_respond_info("TEST_SPEED: starting %d iterations at speed %d, accel %d" % (iterations, speed, accel)) }

	# Absolute positioning
	G90
	
	# Set new limits
	SET_VELOCITY_LIMIT VELOCITY={speed} ACCEL={accel} ACCEL_TO_DECEL={accel / 2}

	# Home and get position for comparison later:
		G28
		# QGL if not already QGLd (only if QGL section exists in config)
		{% if printer.configfile.settings.quad_gantry_level %}
			{% if printer.quad_gantry_level.applied == False %}
				QUAD_GANTRY_LEVEL
				G28 Z
			{% endif %}
		{% endif %}	
		G0 X{printer.toolhead.axis_maximum.x} Y{printer.toolhead.axis_maximum.y} F{30*60}
		G4 P1000 
		GET_POSITION

	# Go to starting position
	G0 X{x_min} Y{y_min} Z{bound + 10} F{speed*60}

	{% for i in range(iterations) %}
		# Large pattern
			# Diagonals
			G0 X{x_min} Y{y_min} F{speed*60}
			G0 X{x_max} Y{y_max} F{speed*60}
			G0 X{x_min} Y{y_min} F{speed*60}
			G0 X{x_max} Y{y_min} F{speed*60}
			G0 X{x_min} Y{y_max} F{speed*60}
			G0 X{x_max} Y{y_min} F{speed*60}
			
			# Box
			G0 X{x_min} Y{y_min} F{speed*60}
			G0 X{x_min} Y{y_max} F{speed*60}
			G0 X{x_max} Y{y_max} F{speed*60}
			G0 X{x_max} Y{y_min} F{speed*60}
		
		# Small pattern
			# Small diagonals 
			G0 X{x_center_min} Y{y_center_min} F{speed*60}
			G0 X{x_center_max} Y{y_center_max} F{speed*60}
			G0 X{x_center_min} Y{y_center_min} F{speed*60}
			G0 X{x_center_max} Y{y_center_min} F{speed*60}
			G0 X{x_center_min} Y{y_center_max} F{speed*60}
			G0 X{x_center_max} Y{y_center_min} F{speed*60}
			
			# Small box
			G0 X{x_center_min} Y{y_center_min} F{speed*60}
			G0 X{x_center_min} Y{y_center_max} F{speed*60}
			G0 X{x_center_max} Y{y_center_max} F{speed*60}
			G0 X{x_center_max} Y{y_center_min} F{speed*60}
	{% endfor %}

	# Restore max speed/accel/accel_to_decel to their configured values
	SET_VELOCITY_LIMIT VELOCITY={printer.configfile.settings.printer.max_velocity} ACCEL={printer.configfile.settings.printer.max_accel} ACCEL_TO_DECEL={printer.configfile.settings.printer.max_accel_to_decel} 

	# Re-home and get position again for comparison:
		G28
		# Go to XY home positions (in case your homing override leaves it elsewhere)
		G0 X{printer.toolhead.axis_maximum.x} Y{printer.toolhead.axis_maximum.y} F{30*60}
		G4 P1000 
		GET_POSITION

	# Restore previous gcode state (absolute/relative, etc)
	RESTORE_GCODE_STATE NAME=TEST_SPEED

PrimeLineMacro.cfg

PRINT_START prime line — purges the previous filament and lays a primed bead at the build-plate edge before the first layer.

#
# Parametric nozzle gunk cleaning PRIME LINE macro with an built in handle for easy removal.
#
# Prints an extruder priming line in the front middle of the bed. Starts with a filament purge to build up pressure
# and clean the gunk off the nozzle, followed by a line forward and half the line backwards. Then prints a handle on top
# of the printed lines so they could be easily removed by hand, retracts the filament and moves closer towards the bed center.
#
# XPAD, YPAD can be used to specify a "no printing zone" around the edges of the bed that the line will never be printed into,
# in case printing close to edges is obstructed by things like binder clips holding the plate onto the bed.
#
# Most of the above actions are configurable if the defaults are not sufficient. You don't have to provide any of them, only if you want
# something changed from the defaults:
#
#  PRIME_LINE XPAD=0 YPAD=0 LENGTH=150 PRINT_SPEED=30 TRAVEL_SPEED=200 PURGE=8 RETRACT=1 EXTRUSION_MULTIPLIER=1.25 PRINT_HANDLE=1 HANDLE_FAN=35
#
# Careful: prints close to bed. Make sure your z-offset is correctly set and your bed mesh loaded, otherwise
# you can damage your print surface.
#
[gcode_macro PRIME_LINE]
description: Print an easy to remove parametric extruder priming line with a built-in handle.
gcode:
    # settings
    {% set line = {
      'x_padding'      : params.XPAD|default(0)|float,  # left/right padding around the bed the line can't print into
      'y_padding'      : params.YPAD|default(0)|float,  # top/bottom padding around the bed the line can't print into
      'initial_purge'  : params.PURGE|default(8)|int,   # mm of filament to purge before printing. set to 0 to disable
      'retract_after'  : params.RETRACT|default(1)|int, # mm of filament to recract after printing. set to 0 to disable
      'length'         : params.LENGTH|default(150)|int,
      'print_speed'    : params.PRINT_SPEED|default(30)|int,
      'travel_speed'   : params.TRAVEL_SPEED|default(200)|int,
      'extr_multi'     : params.EXTRUSION_MULTIPLIER|default(1.25)|float,  # apply to prime lines
      'overlap_percent': 80, # how much prime lines overlap each other
    } %}
    {% set handle = {
      'do_print'    : params.PRINT_HANDLE|default(1)|int,  # set to 0 to disable printing the handle
      'fan_percent' : params.HANDLE_FAN|default(40)|int,   # without fan the handle is too small and melty to print upright
      'width'       : 5.0,
      'height'      : 5.0,
      'move_away'   : 60   # how much to move the toolhead away from the printed handle once done. set 0 to disable
    } %}

    # sanity check and computed variables
    {% set max_x, max_y, nozzle_diameter = printer.toolhead.axis_maximum.x|float, printer.toolhead.axis_maximum.y|float, printer.configfile.config['extruder'].nozzle_diameter|float %}
    {% set _ = line.update({'width': nozzle_diameter * 1.25, 'height': nozzle_diameter / 2, 'length': [line.length, max_x - 2 * line.x_padding - 2]|min}) %}
    {% set _ = line.update({'e_per_mm': line.extr_multi * (line.width * line.height) / (3.1415 * (1.75/2)**2), 'x_start': max_x / 2 - line.length / 2, 'y_start': line.y_padding})  %}

    SAVE_GCODE_STATE NAME=STATE_PRIME_LINE

    M117 Prime Line
    G90 # absolute positioning
    G0 X{line.x_start} Y{line.y_start + (handle.width / 2)|int + 1} Z{line.height} F{line.travel_speed * 60} # move to starting position
    G91 # relative positioning
    G1 E{line.initial_purge} F{5 * 60} # extrude at ~12mm3/sec
    G0 F{line.print_speed * 60} # set print speed
    G1 X{line.length} E{line.length * line.e_per_mm} # print forward line
    G0 Y{line.width * line.overlap_percent / 100} # overlap forward line
    G1 X-{line.length / 2} E{(line.length / 2) * line.e_per_mm}  # print backward line for half the length

    # print a handle for easy removal
    {% if handle.do_print != 0 and handle.width != 0 and handle.height != 0 %}
      G0 X{handle.width} Y{handle.width / 2} # move into position for printing handle
      {% set saved_fan_speed = (printer['fan'].speed * 256)|int %}
      M106 S{((handle.fan_percent / 100) * 256)|int} # set part fan to desired speed
      {% for _ in range((line.height * 1000)|int, (handle.height * 1000)|int, (line.height * 1000)|int) %} # loop however many cycles it takes to print required handle height
        G1 Y{loop.cycle(-1.0, 1.0) * handle.width} E{handle.width * line.e_per_mm} # handle layer
        G0 X-{line.width * 0.2} Z{line.height} # move up and shift the layer to make the handle sloping
      {% endfor %}
      M106 S{saved_fan_speed} # restore previous part fan speed
    {% endif %}
    
    G1 E-{line.retract_after} F{50 * 60} # retract ar 50mm/sec after printing
    G0 X{handle.move_away} F{line.travel_speed * 60}
    M117

    RESTORE_GCODE_STATE NAME=STATE_PRIME_LINE

nozzle_scrub.cfg

CLEAN_NOZZLE macro — wipes the hot nozzle on the brass brush before each print and after each filament change.

#######################################################################################################################################

# Sample macro config to be used in conjunction with the Decontaminator Purge Bucket & Nozzle Scrubber mod. Created by Hernsl 
# (hernsl#8860 on Discord) and edited by Edwardyeeks (edwardyeeks#6042 on Discord). Several ideas that made it as features by
# Deutherius (deutherius#3295 on Discord).

# The goal of this macro is to provide a nozzle scrubbing and purging routine that is easily copied/referenced into your  printer.cfg.
# Users can simply change parameters and enable/disable options in the first half. Descriptions are plentiful, making this macro
# look huge but informative and are laid out in sequence to be read first describing the line below; PLEASE READ CAREFULLY.

# This sample config assumes the following: The user has implemented the default decontaminator purge bucket & nozzle scrubber mod
# for the VORON 1/2. It can be tweaked to customised purge bucket geometries and brushes.

# Features in this macro: option of putting the bucket at the rear or front of the bed. Purge routine that can be enabled/disabled.
# By default, bucket is located at rear left of bed and purge routine is enabled. The purge and scrubbing routine is randomized
# in either left or right bucket to ensure as even as possible distribution of filament gunk.

# Default parameters are set for safe speeds and movements. Where necessary, tweak the parameters for the nozzle scrub procedure 
# to fit your printer.

# To avoid adding length of lines to your main printer.cfg config file, one can upload a config file separately into klipper and
# include it into the main printer config. Upload nozzle_scrub.cfg to the same directory as printer.cfg. Usually, it is in /home/pi/.
# Users of Fluidd, Mainsail and other klipper front ends would find it under /home/pi/klipper_config/.

# Once uploaded, add the following to your printer.cfg in the Macros section: [include /home/pi/nozzle_scrub.cfg] 
# Those running Fluidd, Mainsail and other front ends will need to use the following location instead:
# [include /home/pi/klipper_config/nozzle_scrub.cfg]

#######################################################################################################################################

# Name of the macro is clean_nozzle.

[gcode_macro clean_nozzle]

# If you are putting your purge bucket at the rear left of the bed as per default installation, enable True on your location_bucket_rear 
# variable. If you want to put your purge bucket elsewhere (perhaps the front), then set it to False. See diagrams and description 
# further below on how to set your XY position.
variable_location_bucket_rear:      True

# If you want the purging routine in your bucket enabled, set to True (and vice versa).
variable_enable_purge:              True

# These parameters define your filament purging. The retract variable is used to retract right after purging to prevent unnecessary
# oozing. Some filament are particularly oozy and may continue to ooze out of the nozzle for a second or two after retracting. The
# ooze dwell variable makes allowance for this. Update as necessary. If you decided to not enable purge, you can ignore this section.
variable_purge_len:            20	         ; Amount of filament, in mm, to purge.
variable_purge_spd:           150	         ; Speed, in mm/min, of the purge.
variable_purge_temp_min:      240	         ; Minimum nozzle temperature to permit a purge. Otherwise, purge will not occur.
variable_purge_ret:             2            ; Retract length, in mm, after purging to prevent slight oozing. Adjust as necessary.
variable_ooze_dwell:            2            ; Dwell/wait time, in seconds, after purging and retracting.

# Adjust this so that your nozzle scrubs within the brush. Currently defaulted to be a lot higher for safety. Be careful not to go too low!
variable_brush_top:             3.0

# These parameters define your scrubbing, travel speeds, safe z clearance and how many times you want to wipe. Update as necessary. Wipe 
# direction is randomized based off whether the left or right bucket is randomly selected in the purge & scrubbing routine.
variable_clearance_z:           5	         ; When traveling, but not cleaning, the clearance along the z-axis between nozzle and brush.
variable_wipe_qty:              3	         ; Number of complete (A complete wipe: left, right, left OR right, left, right) wipes.
variable_prep_spd_xy:        3000	         ; Travel (not cleaning) speed along x and y-axis in mm/min.
variable_prep_spd_z:         1500	         ; Travel (not cleaning) speed along z axis in mm/min.
variable_wipe_spd_xy:        5000	         ; Nozzle wipe speed in mm/min.


# These parameters define the size of the brush. Update as necessary. A visual reference is provided below. Note that orientation of 
# parameters remain the same whether bucket is at rear or front.
# 
#                  ←   brush_width   →                            
#                   _________________                                                          ↑
#                  |                 |  ↑                     If you chose location_bucket_rear = True, Y position is acquired
#  brush_start (x) |                 | brush_depth            from your stepper_y position_max. Adjust your brush physically in
#                  |_________________|  ↓                               Y so that the nozzle scrubs within the brush.       
#                          (y)                                                                 ↓
#                      brush_front
# __________________________________________________________
#                     PRINTER FRONT
# 
# 
## For V1.8, you may need to measure where your brush is on the x axis and input manually into any of the variable_brush_start uncommented.
## For V2.4 250mm build, uncomment this below: 
#variable_brush_start:     25	    

## For V2.4 300mm build, uncomment this below:
variable_brush_start:     60

## For V2.4 350mm build, uncomment this below:
#variable_brush_start:     75

# This value is defaulted from brush location in CAD (rear left). Change if your brush width is different.
variable_brush_width:          35

## These are only used if location_bucket_rear is False. You specify a custom location in y axis for your brush - see diagram above. ##
variable_brush_front:       0          
variable_brush_depth:       0          


# These parameters define the size of your purge bucket. Update as necessary. If you decided to not enable purge, you can ignore 
# this section. A visual reference is provided below. Note that orientation of parameters remain the same whether bucket is at rear 
# or front.
# 
#                                     bucket_gap
#                                      ← ---- →
#                     __________________________________________
#                    |                 |      |                 |      
#                    |                 |      |                 |
#  bucket_start (x)  |                 |______|                 |
#                    |                 |      |                 |
#                    |                 |      |                 |
#                    |_________________|. . . |_________________|
#                     ← ------------- →        ← ------------- →
#                     bucket_left_width        bucket_right_width
#  _______________________________________________________________________________________
#                                    PRINTER FRONT
# 
## For V2.4 250mm build, uncomment below 
#variable_bucket_left_width:    42

## For V2.4 300mm build, uncomment below
variable_bucket_left_width:    67

## For V2.4 350mm build, uncomment below
#variable_bucket_left_width:    92   

# These values are defaulted from bucket geometry in CAD (rear left location). Change only if you're using a custom bucket.
variable_bucket_right_width:   40            
variable_bucket_gap:           22	

# For V1.8, you may need to measure where your bucket start is and input into bucket_start. Otherwise, a value of 0 is for a default
# installation of purge bucket at rear left.
variable_bucket_start: 0


###############################################################################################################################################
###############################################################################################################################################

### From here on, unless you know what you're doing, it's recommended not to change anything. Feel free to peruse the code and reach out to me
### (edwardyeeks#6042) on Discord if you spot any problems!

###############################################################################################################################################
###############################################################################################################################################

# Placeholder. The variable will later be set to contain, at random, a number representing the left or right bucket.
variable_bucket_pos:            1	        

gcode:
   # First, check if the axes are homed.
   {% if "xyz" in printer.toolhead.homed_axes %}

      ## Save the gcode state in this macro instance.
      SAVE_GCODE_STATE NAME=clean_nozzle

      STATUS_CLEANING ; LED

      ## Set to absolute positioning.
      G90

      ## Grab max position of Y-axis from config to use in setting a fixed y position for location_bucket_rear = True.
      {% set Ry = printer.configfile.config["stepper_y"]["position_max"]|float %}

      ## Check if user enabled purge option or not.
      {% if enable_purge %}

         ### Randomly select left or right bin for purge. 0 = left, 1 = right
         SET_GCODE_VARIABLE MACRO=clean_nozzle VARIABLE=bucket_pos VALUE={(range(2) | random)}

         ### Raise Z for travel.
         G1 Z{brush_top + clearance_z} F{prep_spd_z}

         ### Check if user chose to use rear location.
         {% if location_bucket_rear %}
            G1 Y{Ry} F{prep_spd_xy}
         {% else %}
            G1 Y{brush_front + (brush_depth / 2)} F{prep_spd_xy}
         {% endif %}

         ### Position for purge. Randomly selects middle of left or right bucket. It references from the middle of the left bucket.
         G1 X{bucket_start + (bucket_left_width / (2 - bucket_pos)) + (bucket_pos * bucket_gap) + (bucket_pos * (bucket_right_width / 2))}

         ### Perform purge if the temp is up to min temp. If not, it will skip and continue executing rest of macro. Small retract after
         ### purging to minimize any persistent oozing at 5x purge_spd. G4 dwell is in milliseconds, hence * 1000 in formula.
         {% if printer.extruder.temperature >= purge_temp_min %}
            M83      ; relative mode
            G1 E{purge_len} F{purge_spd}
            G1 E-{purge_ret} F{purge_spd * 5}
            G4 P{ooze_dwell * 1000}
            G92 E0   ; reset extruder
         {% endif %}

      {% endif %}
   
      ## Position for wipe. Either left or right of brush based off bucket_pos to avoid unnecessary travel.
      G1 Z{brush_top + clearance_z} F{prep_spd_z}
      G1 X{brush_start + (brush_width * bucket_pos)} F{prep_spd_xy}

      ## Check if user chose to use rear location.
      {% if location_bucket_rear %}
         G1 Y{Ry}
      {% else %}
         G1 Y{brush_front + (brush_depth / 2)}
      {% endif %}

      ## Move nozzle down into brush.
      G1 Z{brush_top} F{prep_spd_z}
   
      ## Perform wipe. Wipe direction based off bucket_pos for cool random scrubby routine.
      {% for wipes in range(1, (wipe_qty + 1)) %}
         G1 X{brush_start + (brush_width * (1 - bucket_pos))} F{wipe_spd_xy}
         G1 X{brush_start + (brush_width * bucket_pos)} F{wipe_spd_xy}
      {% endfor %}
   
      ## Clear from area.
      M117 Cleaned!
      G1 Z{brush_top + clearance_z} F{prep_spd_z}
      G1 X150 F{prep_spd_xy} 

      ## Restore the gcode state to how it was before the macro.
      RESTORE_GCODE_STATE NAME=clean_nozzle

   {% else %}

      ## raise error will stop any macros that clean_nozzle is referenced in from proceeding for safety.
      { action_raise_error("Please home your axes!") }
      M117 Please home first!

   {% endif %}