Print start: contact homing, nozzle guard, Z check, purge before chamber heat
- HOME always homes Z with Beacon contact and recalibrates, also when the printer is already homed (home_method_when_homed = proximity used the model of an earlier print without touching the bed). PRINT_START homes Z again after QGL, before the brush takes the nozzle below Z0. - _Z_CHECK: after the soak, compare Klipper's Z with a BEACON_QUERY reading at Z3 over the bed centre and stop the print above 1 mm. Warns and continues when BEACON_QUERY leaves no new printer.beacon.last_sample. - Nozzle guard (extras/bdp_guard.py, print/nozzle_guard.cfg): reads the bd_pressure force over I2C every 20 ms while armed and, in stop mode, shuts Klipper down on a touch. Armed for HOME X/Y, QGL, Z homing, brush, mesh and the Z check; starts in log mode to collect peaks per phase. - Chamber prints: load and purge the first tool before the chamber heats (_LOAD_FOR_CHAMBER replaces _UNLOAD_FOR_CHAMBER). A cut unload leaves a piece of PLA in the extruder that softened in the hot chamber and jammed the ASA load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2100857846
commit
61fa8acb05
7 files changed
+374
-26
No files matched your search
+71
-1
@@ -1,8 +1,78 @@
|
||||
# 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
|
||||
G28 X0 Y0 Z0
|
||||
_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 %}
|
||||
@@ -0,0 +1,33 @@
|
||||
# Nozzle collision guard: bd_pressure watches the nozzle force during moves
|
||||
# that must not touch anything (needs extras/bdp_guard.py and the bd_pressure
|
||||
# load-check firmware). See extras/bdp_guard.py.
|
||||
#
|
||||
# mode: log only measures and reports each phase (console and klippy.log,
|
||||
# "bdp_guard:"). Run a few print starts in log mode, set threshold well
|
||||
# above the peaks the phases show, then switch to mode: stop.
|
||||
|
||||
[bdp_guard]
|
||||
sensor: bd_pa
|
||||
mode: log
|
||||
threshold: 30
|
||||
samples: 3
|
||||
interval: 0.02
|
||||
|
||||
# M400 first: BDP_GUARD_ARM/DISARM act at once, not in the move queue, so
|
||||
# without it the guard would watch moves that are still queued (contact
|
||||
# homing, extrusion) or stop watching before the armed moves ran.
|
||||
[gcode_macro _GUARD_ON]
|
||||
description: Arm the nozzle guard for PHASE=<name> [MODE=log|stop] after the queued moves (nothing without [bdp_guard])
|
||||
gcode:
|
||||
{% if 'bdp_guard' in printer %}
|
||||
M400
|
||||
BDP_GUARD_ARM PHASE={params.PHASE|default('armed')} {('MODE=' ~ params.MODE) if 'MODE' in params else ''}
|
||||
{% endif %}
|
||||
|
||||
[gcode_macro _GUARD_OFF]
|
||||
description: Disarm the nozzle guard after the queued moves (nothing without [bdp_guard])
|
||||
gcode:
|
||||
{% if 'bdp_guard' in printer %}
|
||||
M400
|
||||
BDP_GUARD_DISARM
|
||||
{% endif %}
|
||||
@@ -9,10 +9,13 @@
|
||||
# PRINT_START runs on a soaked bed:
|
||||
# PRINT_WARMUP bed heats while the nozzle cools and the printer homes,
|
||||
# wait for the bed, HEAT_SOAK
|
||||
# PRINT_START QGL, contact Z calibration, mesh, load the initial tool,
|
||||
# PRINT_START QGL, Z, contact Z calibration, mesh, load the initial tool,
|
||||
# PA for all lanes, XY reference
|
||||
# The filament is loaded after the Z calibration, so the contact always
|
||||
# touches a clean nozzle that has not been oozing at 150C for minutes.
|
||||
# Chamber prints are the exception: PRINT_WARMUP loads and purges the first
|
||||
# tool before the chamber heats (_LOAD_FOR_CHAMBER), retracted for the soak;
|
||||
# BLOBIFIER_CLEAN cleans the nozzle before the contact.
|
||||
|
||||
[gcode_macro PRINT_WARMUP]
|
||||
description: Print start before HEAT_SOAK: home while the bed heats, wait for the bed, soak
|
||||
@@ -50,9 +53,11 @@ gcode:
|
||||
RESPOND MSG="homing"
|
||||
HOME
|
||||
{% if target_chamber > 30 %}
|
||||
_UNLOAD_FOR_CHAMBER TOOL={initial_tool}
|
||||
_LOAD_FOR_CHAMBER TOOL={initial_tool}
|
||||
{% endif %}
|
||||
_GUARD_ON PHASE=warmup_park
|
||||
G1 X175 Y175 Z5 F1200
|
||||
_GUARD_OFF
|
||||
|
||||
_STATUS STATE=heating_bed
|
||||
{% if target_bed > 0 %}
|
||||
@@ -71,35 +76,56 @@ gcode:
|
||||
HEAT_SOAK HEATER='heater_bed' TARGET={target_bed} SOAKER='temperature_sensor bed_core' SOAK_TEMP={target_bed - 5} TIMEOUT=30 CANCEL='_NOTHING'
|
||||
{% endif %}
|
||||
|
||||
# With the chamber heated, a filament that stays in the toolhead path softens
|
||||
# in the PTFE tube (PLA loaded, ASA print). PRINT_START would swap a lane that
|
||||
# is not the first tool's anyway, so unload it now, before the chamber heats.
|
||||
# AFC moves the filament back into the Box Turtle, outside the chamber.
|
||||
[gcode_macro _UNLOAD_FOR_CHAMBER]
|
||||
description: Before a chamber soak: unload the toolhead when its lane is not mapped to TOOL (the print's first tool)
|
||||
# With the chamber heated, filament in the toolhead path softens: a PLA lane
|
||||
# still loaded softens in the PTFE tube, and the piece of PLA that a cut
|
||||
# unload leaves below the cutter softens in the extruder and jams the next
|
||||
# load (seen: PLA unloaded, ASA jammed after the soak). The piece stays until
|
||||
# the next load, so an empty toolhead can have it too. For a chamber print,
|
||||
# load the print's first tool and purge it now, before the chamber heats:
|
||||
# the purge at the new filament's temperature pushes the leftover out.
|
||||
# AFC unloads a loaded lane back into the Box Turtle, outside the chamber.
|
||||
[gcode_macro _LOAD_FOR_CHAMBER]
|
||||
description: Before a chamber soak: load and purge TOOL (the print's first tool) unless its lane is already loaded
|
||||
gcode:
|
||||
{% set tool = 'T' ~ params.TOOL|default(0)|int %}
|
||||
{% set cur = printer.AFC.current_load if 'AFC' in printer else none %}
|
||||
{% if cur and ('AFC_stepper ' ~ cur) in printer %}
|
||||
{% set lane = printer['AFC_stepper ' ~ cur] %}
|
||||
{% if lane.map != tool %}
|
||||
RESPOND MSG="Chamber heating: unloading {cur} ({lane.material}, {lane.map}), the print starts with {tool}"
|
||||
_HEAT_FOR_LOADED_LANE TOOL={params.TOOL|default(0)|int}
|
||||
TOOL_UNLOAD LANE={cur}
|
||||
_UNLOAD_FOR_CHAMBER_VERIFY LANE={cur}
|
||||
{% if 'AFC' in printer %}
|
||||
{% set cur = printer.AFC.current_load %}
|
||||
{% set ns = namespace(lane=none) %}
|
||||
{% for l in printer.AFC.lanes if ('AFC_stepper ' ~ l) in printer and printer['AFC_stepper ' ~ l].map == tool %}
|
||||
{% set ns.lane = l %}
|
||||
{% endfor %}
|
||||
{% if ns.lane is none %}
|
||||
_ERROR MSG="Chamber heating: no AFC lane is mapped to {tool}, print stopped before the chamber heats" DISPLAY="No lane for {tool}, print stopped"
|
||||
{% elif cur != ns.lane %}
|
||||
{% set new = printer['AFC_stepper ' ~ ns.lane] %}
|
||||
# Hot enough to unload the old filament and to purge the new one
|
||||
{% set temps = [new.extruder_temp|default(0, true)|int, printer.configfile.settings.extruder.min_extrude_temp|int + 20] %}
|
||||
{% if cur and ('AFC_stepper ' ~ cur) in printer %}
|
||||
{% set temps = temps + [printer['AFC_stepper ' ~ cur].extruder_temp|default(0, true)|int] %}
|
||||
RESPOND MSG="Chamber heating: unloading {cur} ({printer['AFC_stepper ' ~ cur].material}), loading and purging {ns.lane} ({new.material}, {tool}) before the chamber heats"
|
||||
{% else %}
|
||||
RESPOND MSG="Chamber heating: loading and purging {ns.lane} ({new.material}, {tool}) before the chamber heats"
|
||||
{% endif %}
|
||||
M109 S{temps|max}
|
||||
{tool}
|
||||
_LOAD_FOR_CHAMBER_VERIFY LANE={ns.lane}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# Separate macro: rendered after TOOL_UNLOAD has run. A failed unload stops
|
||||
# the print before the chamber heats.
|
||||
[gcode_macro _UNLOAD_FOR_CHAMBER_VERIFY]
|
||||
description: Helper for _UNLOAD_FOR_CHAMBER: stop the print when the lane is still loaded
|
||||
# Separate macro: rendered after the tool change has run. AFC pauses on a
|
||||
# failed load instead of raising an error, so check the result here: a
|
||||
# failed load stops the print before the chamber heats.
|
||||
[gcode_macro _LOAD_FOR_CHAMBER_VERIFY]
|
||||
description: Helper for _LOAD_FOR_CHAMBER: stop the print when LANE is not loaded, else retract and cool the nozzle for the soak
|
||||
gcode:
|
||||
{% if printer.AFC.current_load %}
|
||||
_ERROR MSG="Chamber heating: {params.LANE} could not be unloaded ({printer.AFC.current_load} still in the toolhead), print stopped before the chamber heats" DISPLAY="Unload failed, print stopped"
|
||||
{% if printer.AFC.current_load != params.LANE %}
|
||||
_ERROR MSG="Chamber heating: {params.LANE} could not be loaded ({printer.AFC.current_load or 'nothing'} in the toolhead), print stopped before the chamber heats" DISPLAY="Load failed, print stopped"
|
||||
{% else %}
|
||||
# The filament the retract was remembered for is gone
|
||||
# New filament, just purged: a retract remembered for the old one is
|
||||
# gone. Retract so it does not ooze during the soak; PRINT_START
|
||||
# undoes it over the bucket.
|
||||
SAVE_VARIABLE VARIABLE=nozzle_retract VALUE=0
|
||||
_NOZZLE_RETRACT
|
||||
M104 S150
|
||||
{% endif %}
|
||||
|
||||
@@ -150,19 +176,37 @@ gcode:
|
||||
_LIGHTS_ON
|
||||
M106 S0
|
||||
|
||||
# The last homing was before the soak: check that Z still matches the
|
||||
# Beacon before the gantry goes low. MAX=1.0: the soak itself drifts Z
|
||||
# a few tenths; the console line shows how much.
|
||||
_Z_CHECK MAX=1.0
|
||||
|
||||
# The bed is soaked now: level and calibrate Z on the final geometry
|
||||
_STATUS STATE=leveling
|
||||
RESPOND MSG="quad gantry level"
|
||||
# Nozzle guard (bd_pressure) on while nothing should touch the nozzle
|
||||
_GUARD_ON PHASE=qgl
|
||||
QUAD_GANTRY_LEVEL
|
||||
# QGL moved the Z steppers and the frame drifted during the soak: home Z
|
||||
# again (proximity, on the model of the contact homing in PRINT_WARMUP)
|
||||
# before the brush takes the nozzle below Z0
|
||||
_GUARD_ON PHASE=z_home
|
||||
G28 Z
|
||||
|
||||
# Own phase: the bristles press on the nozzle too
|
||||
_GUARD_ON PHASE=brush
|
||||
BLOBIFIER_CLEAN
|
||||
_GUARD_OFF
|
||||
_STATUS STATE=calibrating_z
|
||||
_NOZZLE_CONTACT_TEMP WAIT=1
|
||||
G28 Z METHOD=CONTACT CALIBRATE=1 ; calibrate z offset and beacon model hot
|
||||
|
||||
_STATUS STATE=meshing
|
||||
RESPOND MSG="meshing"
|
||||
_GUARD_ON PHASE=mesh
|
||||
BED_MESH_CALIBRATE RUNS=2 ; bed mesh in scan mode
|
||||
# From here on the nozzle extrudes and AFC cuts and loads: guard off
|
||||
_GUARD_OFF
|
||||
|
||||
# Heat over the bucket, then undo the retracts of the previous PRINT_END
|
||||
_STATUS STATE=heating_extruder
|
||||
@@ -232,8 +276,9 @@ gcode:
|
||||
|
||||
# End-of-print cleanup shared by PRINT_END and CANCEL_PRINT
|
||||
[gcode_macro _PRINT_CLEANUP]
|
||||
description: Heaters (incl. chamber heater) and part fan off, flow back to 100%, bdwidth off, mesh and skew cleared
|
||||
description: Heaters (incl. chamber heater) and part fan off, flow back to 100%, bdwidth off, mesh and skew cleared, nozzle guard off
|
||||
gcode:
|
||||
_GUARD_OFF ; a print start that failed while it was armed
|
||||
TURN_OFF_HEATERS
|
||||
iHEATER_OFF ; stops the chamber heater control loop too
|
||||
M107
|
||||
|
||||
Reference in new issue
Block a user