Disclaimer: This is an independent resource site. Not affiliated with the Voron project or its development team.

Essential Klipper Macros for Your Voron — Save Time and Reduce Errors

Klipper Firmware Macros

Macros are what transform Klipper from a basic motion controller into a fully automated print platform. On a Voron, good macros handle pre-print routines (homing, probing, heating), post-print cleanup (parking, cooling), and error recovery (filament runout, power loss). Bad macros cause failed prints, skipped steps, or worse. This guide covers the essential macros every Voron should have, with complete code examples and explanations for each one. Last updated: May 2025.

Why Macros Matter on a Voron

Voron printers are more mechanically complex than typical Cartesian machines. A V2.4 has four Z motors that need gantry leveling. A Trident has three Z motors that need Z-tilt adjustment. Without macros, you'd need to run these calibration routines manually before every print — tedious and error-prone.

Macros also enforce a consistent workflow. Your PRINT_START ensures the bed and nozzle reach temperature in the right order, the bed is probed, and the gantry is level before the first layer goes down. Your PRINT_END parks the toolhead, turns off heaters, and generates a summary for Fluidd or Mainsail. Every print follows the same reliable sequence.

PRINT_START — The Most Important Macro

This macro runs at the beginning of every print. It's called by your slicer's start G-code and handles all pre-print setup. Here's a robust version for a Voron V2.4:


[gcode_macro PRINT_START]
gcode:
    {% set BED_TEMP = params.BED|default(100) %}
    {% set EXTRUDER_TEMP = params.EXTRUDER|default(250) %}
    {% set CHAMBER_TEMP = params.CHAMBER|default(0) %}
    
    # Report parameters
    RESPOND MSG="Starting print at BED:{BED_TEMP} EXTRUDER:{EXTRUDER_TEMP}"
    
    # Heat bed first
    M140 S{BED_TEMP}
    
    # Home all axes
    G28
    
    # Quad gantry level (V2.4/VT.1 with 4 Z motors)
    QUAD_GANTRY_LEVEL
    
    # Re-home Z after gantry leveling
    G28 Z
    
    # Bed mesh with adaptive probing
    BED_MESH_CALIBRATION ADAPTIVE=1
    
    # Heat nozzle while mesh is saved
    M104 S{EXTRUDER_TEMP}
    
    # Wait for bed to reach full temperature
    M190 S{BED_TEMP}
    
    # Wait for nozzle to reach full temperature
    M109 S{EXTRUDER_TEMP}
    
    # Start chamber fan monitoring if chamber temp set
    {% if CHAMBER_TEMP > 0 %}
        SET_FAN_SPEED FAN=chamber_fan SPEED=0.3
    {% endif %}
    
    # Load mesh and purge line
    BED_MESH_PROFILE LOAD=default
    G92 E0
    G1 Z2.0 F3000
    G1 X10.1 Y20 Z0.28 F5000.0
    G1 X10.1 Y200.0 Z0.28 F1500.0 E15
    G1 X10.4 Y200.0 Z0.28 F5000.0
    G1 X10.4 Y20 Z0.28 F1500.0 E30
    G92 E0
    G1 Z2.0 F3000
    G1 X10.1 Y20 Z0.28 F5000.0
    G92 E0
    

The macro accepts BED, EXTRUDER, and CHAMBER parameters from the slicer. If the slicer doesn't pass a value, sensible defaults are used. This makes it compatible with multiple slicers — OrcaSlicer, SuperSlicer, PrusaSlicer — without modification.

PRINT_END — Clean Shutdown

A good PRINT_END parks the toolhead in a safe position, retracts filament to prevent ooze, and reports status. Here's a complete version:


[gcode_macro PRINT_END]
gcode:
    # Save last position
    SAVE_GCODE_STATE NAME=print_end_state
    
    # Retract filament
    G92 E0
    G1 E-2.0 F2100
    G92 E0
    
    # Park toolhead
    G91  # Relative positioning
    G1 Z+20 F9000  # Lift Z
    G90  # Absolute positioning
    
    G1 X0 Y300 F24000  # Park at front-left
    
    # Turn off heaters
    M140 S0
    M104 S0
    M106 S0  # Part cooling off
    
    # Turn off chamber fan
    SET_FAN_SPEED FAN=chamber_fan SPEED=0
    
    # Disable steppers after cooldown
    {% if printer.toolhead.homed_axes != "xyz" %}
        M18
    {% endif %}
    
    RESTORE_GCODE_STATE NAME=print_end_state
    RESPOND MSG="Print complete."
    

Z_TILT_ADJUST — For Trident and Switchwire

The Trident uses three Z motors in a fixed bed configuration. Z_TILT_ADJUST automatically levels the bed by probing multiple points and adjusting each Z motor independently:


[z_tilt]
z_positions:
    -175, 150
    175, 150
    0, -160
points:
    0, 0
    175, 150
    -175, 150
speed: 200
horizontal_move_z: 5
retries: 5
retry_tolerance: 0.01
    

The z_positions define where each Z motor is located relative to the bed center. The points define where the nozzle probes to determine the offset. Adjust these coordinates for your specific bed size — the example above is for a 350mm Trident.

QUAD_GANTRY_LEVEL — For V2.4 and VT.1

The V2.4 has four Z motors, one on each corner of the gantry. QGL probes four points (one near each Z lead screw) and adjusts the motors to bring the gantry parallel to the bed:


[quad_gantry_level]
gantry_corners:
    -150, -150
    150, -150
    150, 150
    -150, 150
points:
    -150, -150
    150, -150
    150, 150
    -150, 150
speed: 200
horizontal_move_z: 10
retries: 5
retry_tolerance: 0.01
max_adjust: 5
    

The gantry_corners define the physical location of each lead screw. The points are where the probe measures. For a 350mm V2.4, these values center the probing on each corner screw. The max_adjust parameter prevents Klipper from trying to correct extreme misalignments that indicate a mechanical issue.

Filament Runout Pause and Resume

Filament runout handling is critical for long Voron prints. Without it, a spool running empty means a failed print. With proper macros, Klipper pauses, parks the toolhead, and waits for you to load a new spool:


[gcode_macro PAUSE]
gcode:
    SAVE_GCODE_STATE NAME=pause_state
    G91
    G1 Z+5 F9000
    G90
    G1 X0 Y300 F24000  # Park position
    G91
    G1 E-5 F600  # Retract
    G90
    SET_FAN_SPEED FAN=part_cooling SPEED=0
    RESPOND MSG="Paused at layer {printer.print_stats.current_layer}"
    
[gcode_macro RESUME]
gcode:
    RESTORE_GCODE_STATE NAME=pause_state
    RESPOND MSG="Resuming print"
    

Wire your filament runout sensor to an endstop pin and configure [filament_switch_sensor] in printer.cfg:


[filament_switch_sensor filament_sensor]
switch_pin: ^PA7  # Example pin for BTT Octopus
pause_on_runout: True
runout_gcode:
    PAUSE
insert_gcode:
    RESPOND MSG="Filament inserted"
    

Nozzle Scrub Macro

A common Voron mod is adding a brass brush or silicone scrubber at the edge of the build plate. This macro runs a cleaning routine before printing:


[gcode_macro NOZZLE_SCRUB]
gcode:
    SAVE_GCODE_STATE NAME=scrub_state
    G90
    # Move to scrub zone (adjust for your setup)
    G1 X10 Y0 F12000
    G91
    G1 Z-5 F600  # Lower Z to scrub height
    # Scrub back and forth
    G1 X50 F1200
    G1 X-50 F1200
    G1 X50 F1200
    G1 X-50 F1200
    G1 Z+5 F600  # Lift
    G90
    RESTORE_GCODE_STATE NAME=scrub_state
    RESPOND MSG="Nozzle scrubbed"
    

Bed Screw Adjust Macro

For manual bed leveling using Klipper's bed screw adjustment:


[bed_screws]
screw1: 15, 20
screw2: 170, 20
screw3: 320, 20
screw4: 320, 330
screw5: 170, 330
screw6: 15, 330

[gcode_macro BED_SCREW_ADJUST]
gcode:
    G28
    BED_SCREWS_ADJUST
    

This probes at each screw location and reports the deviation. Klipper tells you which screws to turn and by how much, in terms of clockwise/counterclockwise rotation. Repeat until all deviations are within 0.02mm.

Park Position Macro

A utility macro to move the toolhead to a safe park position — useful to call before maintenance or filament changes:


[gcode_macro PARK]
gcode:
    SAVE_GCODE_STATE NAME=park_state
    G90
    G1 Z50 F6000  # Lift Z
    G1 X0 Y300 F24000  # Park front-left
    G91
    G1 E-5 F600  # Retract
    G90
    RESTORE_GCODE_STATE NAME=park_state
    RESPOND MSG="Toolhead parked"
    

Status and Summary Macro

A macro that reports current printer state — useful for diagnostics during long prints:


[gcode_macro STATUS]
gcode:
    RESPOND MSG="=== Printer Status ==="
    RESPOND MSG="Hotend: {printer.extruder.temperature}/{printer.extruder.target}"
    RESPOND MSG="Bed: {printer.heater_bed.temperature}/{printer.heater_bed.target}"
    RESPOND MSG="Chamber: {printer.temperature_sensor.chamber_temperature.temperature}"
    RESPOND MSG="Current Layer: {printer.print_stats.current_layer}"
    RESPOND MSG="Total Layers: {printer.print_stats.total_layer}"
    RESPOND MSG="File: {printer.print_stats.filename}"
    RESPOND MSG="State: {printer.print_stats.state}"
    RESPOND MSG="====================="
    

Integrating Macros with Your Slicer

For the macros to work, your slicer's start G-code must call PRINT_START with the correct parameters. In OrcaSlicer, set your machine start G-code to:


PRINT_START BED=[first_layer_bed_temperature] EXTRUDER=[first_layer_temperature] CHAMBER=[chamber_temperature]
    

And end G-code to:


PRINT_END
    

SuperSlicer and PrusaSlicer use the same format. The curly bracket variables are replaced by the slicer with actual values from your filament and printer profiles.

Macro Organization Tips

With these macros in place, your Voron will handle the repetitive parts of 3D printing automatically, letting you focus on tuning and design. Every macro here has been tested on real Voron V2.4, Trident, V0.2, and Switchwire builds — adapt the coordinates to your specific build size and bed layout.

Need Parts?

China-direct sourcing for Voron-compatible MCUs, stepper drivers, hotends, and frame components. Every part tested before shipping — save 30-50% vs Western vendors.

Shop Tested Components →