# HOME: home all axes and move to the bed centre # # Z always with Beacon contact (the nozzle touches the bed), also when the # printer is already homed. Without METHOD=CONTACT, [beacon] # home_method_when_homed = proximity homes a homed printer on the # eddy-current model of an earlier print (other bed temperature, maybe # another plate) without touching the bed and without recalibrating. # Contact refuses a nozzle above 180C (contact_max_hotend_temperature). [gcode_macro HOME] gcode: G90 G4 P2000 _GUARD_ON PHASE=home_xy G28 X Y # Contact homing presses the nozzle on the bed: guard off _GUARD_OFF G28 Z METHOD=CONTACT CALIBRATE=1 _GUARD_ON PHASE=home_lift G1 X175 Y175 Z10 F1200 _GUARD_OFF # _Z_CHECK: compare where Klipper thinks the nozzle is with what the Beacon # measures (proximity), at X/Y (default the bed centre) and Z (default 3 mm, # inside the model range 0.2-5 mm). Catches a Z that changed since the last # homing (lost Z steps, gantry moved, much thermal drift) before the nozzle # goes low; a difference above MAX stops the print. A wrong Beacon model # fools both readings the same way, so this does not replace contact homing. # # BEACON_QUERY stores its reading in printer.beacon.last_sample. When it # gives no new reading there, the check only warns, so a Beacon version # without that field does not stop every print. [gcode_macro _Z_CHECK] description: Compare Klipper's Z with the Beacon reading at X Y Z (default 175 175 3), stop the print when they differ by more than MAX (default 0.5 mm) gcode: {% set x = params.X|default(175)|float %} {% set y = params.Y|default(175)|float %} {% set z = params.Z|default(3)|float %} {% set max = params.MAX|default(0.5)|float %} {% if 'xyz' not in printer.toolhead.homed_axes %} _ERROR MSG="_Z_CHECK: printer not homed" DISPLAY="Z check: not homed" {% elif 'beacon' not in printer %} _WARN MSG="_Z_CHECK: no [beacon], check skipped" {% else %} {% set last = printer.beacon.last_sample %} {% set prev = last.time if last and last.time is defined else -1 %} SAVE_GCODE_STATE NAME=_z_check G90 _GUARD_ON PHASE=z_check {% if printer.toolhead.position.z < z %} G1 Z{z} F600 {% endif %} G1 X{x} Y{y} F12000 G1 Z{z} F600 _GUARD_OFF G4 P300 BEACON_QUERY _Z_CHECK_EVAL MAX={max} PREV={prev} RESTORE_GCODE_STATE NAME=_z_check {% endif %} # Separate macro: rendered after BEACON_QUERY has run. toolhead.position is # the real nozzle height (gcode offset and mesh included). [gcode_macro _Z_CHECK_EVAL] description: Helper for _Z_CHECK: compare the BEACON_QUERY reading with the toolhead Z gcode: {% set s = printer.beacon.last_sample %} {% set z = printer.toolhead.position.z %} {% set max = params.MAX|default(0.5)|float %} {% if not s or s.time is not defined or s.dist is not defined or s.time == params.PREV|default(-1)|float %} _WARN MSG="_Z_CHECK: BEACON_QUERY left no new reading in printer.beacon.last_sample, Z check skipped" DISPLAY="Z check skipped" {% elif s.dist is none %} _ERROR MSG="_Z_CHECK: Klipper Z={'%.2f' % z} but the Beacon reads nothing (more than 5 mm away or no model), print stopped" DISPLAY="Z check failed, print stopped" {% elif (s.dist - z)|abs > max %} _ERROR MSG="_Z_CHECK: Klipper Z={'%.3f' % z}, Beacon measures {'%.3f' % s.dist} mm (difference {'%.3f' % (s.dist - z)}, limit {max}), print stopped" DISPLAY="Z check failed, print stopped" {% else %} RESPOND MSG="Z check: Klipper Z={'%.3f' % z}, Beacon {'%.3f' % s.dist} mm, difference {'%.3f' % (s.dist - z)} (limit {max})" {% endif %}