Print start: soak before QGL and Z, load after Z, PA per lane temperature

PRINT_WARMUP: bed heats during the warmup, the nozzle only waits while it
is above 170C (Beacon contact limit 180C), one HOME to get over the bed,
then M190 and HEAT_SOAK. No more filament load and 220->150C cycle there.

PRINT_START (on the soaked bed): one QGL, one contact Z calibration, mesh,
heat over the bucket, load the initial tool, PA for all lanes, load the
initial tool again if a calibration changed lanes, G28 X Y reference.
Loading after the contact keeps ooze off the nozzle for the calibration.

PA: calibrate each lane at its own filament temperature (was the
temperature from before CHANGE_TOOL), and apply the loaded lane's PA
after PA_CALIBRATE_ALL_LANES (the last cached lane's PA won before).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-17 19:46:05 +02:00
1 parent e5be65834e
commit 6cc43f951d
2 files changed
+92 -132

No files matched your search

+20 -4
View File
@@ -422,11 +422,14 @@ gcode:
{% else %}
CHANGE_TOOL LANE={lane}
# Nozzle temp: use the extruder's current target, which AFC
# already sets from Spoolman when the lane was loaded. Fall
# back to the configured default if nothing is set yet.
# Nozzle temp: the lane's own filament temperature (AFC, from
# Spoolman). Not printer.extruder.target: the template is rendered
# before CHANGE_TOOL runs, so that is still the previous lane's
# (or the print's) temperature. PA_CALIBRATE heats to it (M109).
{% set lane_obj = printer["AFC_stepper " ~ lane] if ("AFC_stepper " ~ lane) in printer else {} %}
{% set lane_temp = lane_obj.extruder_temp|default(0, true)|float %}
{% set target = printer.extruder.target|default(0)|float %}
{% set nozzle_temp = target if target > 0 else cfg.fallback_nozzle_temp|float %}
{% set nozzle_temp = lane_temp if lane_temp > 0 else (target if target > 0 else cfg.fallback_nozzle_temp|float) %}
{action_respond_info("Calibrating PA for %s (spool %d) at %.0fC..." % (lane, spool_id, nozzle_temp))}
M117 Calibrating PA: {lane}
@@ -619,6 +622,19 @@ gcode:
UPDATE_DELAYED_GCODE ID=_PA_POLL_LANE_CHANGE DURATION=2
# PA_CALIBRATE_ALL_LANES sets the PA of every lane in turn (the last one
# wins), and the lane-change poll only reacts to a change of the loaded lane.
# Run this after it so the PA matches the lane that is actually loaded.
[gcode_macro _PA_APPLY_LOADED_LANE]
description: Apply the cached PA of the lane loaded in the toolhead
gcode:
{% set lane = printer.AFC.current_load|default(none) if "AFC" in printer else none %}
{% if lane %}
_PA_APPLY_FOR_LANE LANE={lane}
{% else %}
RESPOND MSG="_PA_APPLY_LOADED_LANE: no lane loaded, PA unchanged"
{% endif %}
[gcode_macro _PA_APPLY_FOR_LANE]
description: Internal -- applies cached PA for a lane without calibrating
# LANE=<lane_name>
+72 -128
View File
@@ -1,59 +1,39 @@
# Print start and end: PRINT_WARMUP, PRINT_START, PRINT_END
# Idle time (in seconds) to wait before running the above G-Code
# commands. The default is 600 seconds.
#####################################################################
# Macros
#####################################################################
# [gcode_macro PRINT_START]
# gcode:
# PRINT_WARMUP BED={params.BED} EXTRUDER={params.EXTRUDER} CHAMBER={params.CHAMBER|default("0")} TOOL={params.TOOL|default("0")}
# PRINT_START_2 EXTRUDER={params.EXTRUDER}
# OrcaSlicer calls PRINT_WARMUP and then PRINT_START. HEAT_SOAK at the end of
# PRINT_WARMUP pauses the print file and resumes it when the soak is done, so
# 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,
# 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.
[gcode_macro PRINT_WARMUP]
description: Perform initial homing and heating tasks
description: Print start before HEAT_SOAK: home while the bed heats, wait for the bed, soak
gcode:
{% set target_bed = params.BED|int %}
{% set target_extruder = params.EXTRUDER|int %}
{% set target_chamber = params.CHAMBER|default("0")|int %}
# {% set x_wait = printer.toolhead.axis_maximum.x|float / 2 %}
# {% set y_wait = printer.toolhead.axis_maximum.y|float / 2 %}
{% set initial_tool = params.TOOL|default("0")|int %}
{% set chamber_temp = printer["temperature_sensor chamber"].temperature|float %}
RESET_FAILURE
CLEAR_PAUSE
CLEAR_PAUSE
# Clear what an earlier print or error left on the display
M117
_LIGHTS_ON
#SET_PIN PIN=caselight VALUE=1.00
UPDATE_DELAYED_GCODE ID=_delayed_motors_off DURATION=0
BED_MESH_CLEAR
SET_GCODE_OFFSET Z=0
CLEAR_PAUSE
SKEW_PROFILE LOAD=Califlower
{% set current_temp = printer.extruder.temperature %}
{% if current_temp > 150 %}
RESPOND MSG="nozzle to hot, lowering to 150"
M104 S150 ; set nozzle temp to 150
M109 S150 ; wait until nozzle reaches 150 ; wait until nozzle reaches 0
{% endif %}
_STATUS STATE=homing
RESPOND MSG="homing"
HOME
RESPOND MSG="homing finished"
# G0 Z2 ; position beacon at 2mm for heat soak
M106 S0
# Bed first, so it heats during the rest of the warmup
{% if target_bed < 60 %}
RESPOND MSG="Using PID for <60°C bed"
SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={target_bed} PID_KP=33.606 PID_KI=0.694 PID_KD=407.058
@@ -61,53 +41,44 @@ gcode:
RESPOND MSG="Using PID for ≥60°C bed"
SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={target_bed} pid_Kp=46.843 pid_Ki=2.002 pid_Kd=274.034
{% endif %}
G1 X175 Y175 Z2 F1200
# Only to get the toolhead over the bed for the soak; the Z that counts
# is the contact calibration in PRINT_START on the soaked bed
_STATUS STATE=homing
_NOZZLE_CONTACT_TEMP
RESPOND MSG="homing"
HOME
G1 X175 Y175 Z5 F1200
_STATUS STATE=heating_bed
RESPOND MSG="heating"
{% if target_bed > 0 %}
M140 S{target_bed} ; start bed heater
M104 S150 ; set nozzle temp to 150
M109 S150 ; wait until nozzle reaches 150 ; wait until nozzle reaches 0
M190 S{target_bed} ; wait on bed temperature
RESPOND MSG="heating"
M190 S{target_bed}
{% endif %}
_STATUS STATE=homing
HOME
_STATUS STATE=leveling
QUAD_GANTRY_LEVEL
BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available
G1 X175 Y175 Z5 F1200
_STATUS STATE=heating_extruder
_HEAT_FOR_LOADED_LANE TOOL={initial_tool} ; unload needs the loaded filament's temperature
T{initial_tool} #PURGE_LENGTH=100 #Load Initial Tool
M104 S{target_extruder} ; set extruder to print temp
M109 S{target_extruder} ; wait for extruder temp
_NOZZLE_RETRACT LENGTH=2 ; no oozing while waiting; PRINT_START pushes it back
M104 S150 ; set nozzle temp to 150
M109 S150 ; wait until nozzle reaches 150 ; wait until nozzle reaches 0
BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available
G1 X175 Y175 Z5 F1200
_STATUS STATE=heating_bed
{% if target_chamber > 30 %}
RESPOND MSG="waiting for chamber temperature"
M141 S{target_chamber}
# M191 S{target_chamber} ; Waits until the chamber temperature reaches 60°C
# TEMPERATURE_WAIT SENSOR="temperature_sensor chamber" MINIMUM={target_chamber}
RESPOND MSG="waiting for chamber temperature"
M141 S{target_chamber}
M106 S255
# HEAT_SOAK HEATER='heater_bed' TARGET={BED_TEMP} SOAKER='temperature_sensor iHeater_S' SOAK_TEMP={target_chamber} TIMEOUT=60 CANCEL='_NOTHING'
# Unreachable SOAK_TEMP + CANCEL='_NOTHING': soaks until the TIMEOUT, then continues the print
HEAT_SOAK HEATER='heater_bed' TARGET={target_bed} SOAKER='temperature_sensor chamber' SOAK_TEMP={target_chamber} TIMEOUT=60 CANCEL='_NOTHING'
# (CANCEL='_NOTHING') and having unreachable SOAK_TEMP makes it run till the TIMEOUT and continue without canceling the print.
{% else %}
RESPOND MSG="waiting for bed core temperature"
RESPOND MSG="waiting for bed core temperature"
HEAT_SOAK HEATER='heater_bed' TARGET={target_bed} SOAKER='temperature_sensor bed_core' SOAK_TEMP={target_bed - 5} TIMEOUT=30 CANCEL='_NOTHING'
# (CANCEL='_NOTHING') and having unreachable SOAK_TEMP makes it run till the TIMEOUT and continue without canceling the print.
{% endif %}
# Beacon contact refuses a nozzle above contact_max_hotend_temperature (180C)
[gcode_macro _NOZZLE_CONTACT_TEMP]
description: Nozzle to 150C for Beacon contact; wait only while it is above MAXIMUM (default 170C), WAIT=1 also waits until it is at least 145C
gcode:
{% set max = params.MAXIMUM|default(170)|float %}
{% set heat = params.WAIT|default(0)|int == 1 %}
M104 S150
{% if heat %}
TEMPERATURE_WAIT SENSOR=extruder MINIMUM=145 MAXIMUM={max}
{% elif printer.extruder.temperature > max %}
RESPOND MSG="Nozzle at {printer.extruder.temperature|round|int}C, waiting until it is below {max|int}C"
TEMPERATURE_WAIT SENSOR=extruder MAXIMUM={max}
{% endif %}
# AFC heats for a tool change from the print file's per-tool temperatures.
@@ -134,85 +105,58 @@ gcode:
RESUME_BASE
[gcode_macro PRINT_START]
description: Print start after HEAT_SOAK: QGL, Z calibration, mesh, load the initial tool, PA
gcode:
RESPOND MSG="print start macro continued"
_LIGHTS_ON
{% set target_extruder = params.EXTRUDER|int %}
{% set initial_tool = params.TOOL|default("0")|int %}
RESPOND MSG="print start macro continued"
_LIGHTS_ON
M106 S0
M104 S150 ; set nozzle temp to 150
M109 S150 ; wait until nozzle reaches 150 ; wait until nozzle reaches 0
HOME
BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available
_STATUS STATE=calibrating_z
G28 Z METHOD=CONTACT CALIBRATE=1 ; calibrate z offset and beacon model hot
# The bed is soaked now: level and calibrate Z on the final geometry
_STATUS STATE=leveling
RESPOND MSG="quad ganrty level"
RESPOND MSG="quad gantry level"
QUAD_GANTRY_LEVEL
BLOBIFIER_CLEAN
_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"
BED_MESH_CALIBRATE RUNS=2 ; bed mesh in scan mode
BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available
M104 S150 ; set nozzle temp to 150
M109 S150 ; wait until nozzle reaches 150 ; wait until nozzle reaches 0
_STATUS STATE=calibrating_z
G28 Z METHOD=CONTACT CALIBRATE=1 ; calibrate z offset and beacon model hot
# Heat over the bucket, then undo the retracts of the previous PRINT_END
_STATUS STATE=heating_extruder
M104 S{target_extruder} ; set extruder to print temp
M109 S{target_extruder} ; wait for extruder temp
BLOBIFIER_PARK ; over the bucket, then undo the retracts
_NOZZLE_UNRETRACT ; of PRINT_WARMUP and the previous PRINT_END
# ; needs fine tuning, long meltzones require more
# SET_GCODE_OFFSET Z_ADJUST={OFFSET} ; apply optional material squish via slicer
#SET_GCODE_OFFSET Z=-0.06 ; squish
# SET_GCODE_OFFSET Z=0.02 ; squish # worked before but a bit to high now
# SET_GCODE_OFFSET Z=-0.05 ; squish
SET_GCODE_OFFSET Z=-0.00 ; squish
RESPOND MSG="starting"
;PRIME_NOZZLE ; call another macro to purge or prime nozzle
# WIPE_NOZZLE ; call another macro to wipe nozzle if available
# Line_Purge
# AFC_POOP PURGE_LENGTH=100
# AFC_KICK
BLOBIFIER_CLEAN
BLOBIFIER_PARK
M109 S{target_extruder}
_NOZZLE_UNRETRACT
# Load the initial tool (unloading another lane needs that lane's temperature)
_HEAT_FOR_LOADED_LANE TOOL={initial_tool}
T{initial_tool}
PA_CALIBRATE_ALL_LANES LANES="lane1,lane2,lane3,lane4,lane5"
# A calibration can leave another lane loaded, and every cached lane
# sets its PA: load the initial tool again and apply its PA
T{initial_tool}
_PA_APPLY_LOADED_LANE
M104 S{target_extruder} ; set extruder to print temp
M109 S{target_extruder} ; wait for extruder temp
M109 S{target_extruder}
SET_GCODE_OFFSET Z=-0.00 ; squish
BLOBIFIER_CLEAN
; start printing
G90 ; absolute positioning
G1 Z20 F30000 ; move nozzle away from bed
G1 X175 Y175 F30000 ; move nozzle away from bed
G28 XYZ
#G11 ; unretract
# XY reference for AFC_XY_SAFETY_CHECK (homes X and Y; Z stays from the
# contact calibration)
_AFC_STORE_HOME_REFERENCE
# bdwidth is not used while printing: its motion reading stays at 0 and its
# per-reading width compensation made the flow jump between 77 and 119%.
# To use it again: SET_BDWIDTH NAME=fila_width_0 COMMAND=ENABLE_WIDTH
RESPOND MSG="starting"
_STATUS STATE=printing