# Print start and end: PRINT_WARMUP, PRINT_START, PRINT_END ##################################################################### # Macros ##################################################################### # 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: Print start before HEAT_SOAK: home while the bed heats, wait for the bed, soak gcode: {% set target_bed = params.BED|int %} {% set target_chamber = params.CHAMBER|default("0")|int %} RESET_FAILURE CLEAR_PAUSE # Clear what an earlier print or error left on the display M117 _LIGHTS_ON UPDATE_DELAYED_GCODE ID=_delayed_motors_off DURATION=0 BED_MESH_CLEAR SET_GCODE_OFFSET Z=0 SKEW_PROFILE LOAD=Califlower 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 {% else %} 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 %} # 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 {% if target_bed > 0 %} RESPOND MSG="heating" M190 S{target_bed} {% endif %} {% if target_chamber > 30 %} RESPOND MSG="waiting for chamber temperature" M141 S{target_chamber} M106 S255 # 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' {% else %} 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' {% 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. # When the loaded lane's tool number is not in that list (for example lane5 = # T4 loaded, single-colour print with only T0), AFC does not heat at all and # the unload fails below min_extrude_temp. Heat for the loaded filament first. [gcode_macro _HEAT_FOR_LOADED_LANE] description: Heat to the loaded lane's filament temperature before changing to another tool gcode: {% set tool = 'T' ~ params.TOOL|default(0)|int %} {% set cur = printer.AFC.current_load %} {% if cur and ('AFC_stepper ' ~ cur) in printer %} {% set lane = printer['AFC_stepper ' ~ cur] %} {% if lane.map != tool %} {% set min_temp = printer.configfile.settings.extruder.min_extrude_temp|int + 20 %} {% set temp = [lane.extruder_temp|default(0, true)|int, min_temp]|max %} RESPOND MSG="Heating to {temp}C to unload {cur} ({lane.material}) before {tool}" M109 S{temp} {% endif %} {% endif %} [gcode_macro _NOTHING] gcode: RESUME_BASE [gcode_macro PRINT_START] description: Print start after HEAT_SOAK: QGL, Z calibration, mesh, load the initial tool, PA gcode: {% set target_extruder = params.EXTRUDER|int %} {% set initial_tool = params.TOOL|default("0")|int %} RESPOND MSG="print start macro continued" _LIGHTS_ON M106 S0 # The bed is soaked now: level and calibrate Z on the final geometry _STATUS STATE=leveling 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 # Heat over the bucket, then undo the retracts of the previous PRINT_END _STATUS STATE=heating_extruder 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 M109 S{target_extruder} SET_GCODE_OFFSET Z=-0.00 ; squish BLOBIFIER_CLEAN # 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 [gcode_macro PRINT_END] # Use PRINT_END for the slicer ending script - please customise for your slicer of choice gcode: # safe anti-stringing move coords {% set th = printer.toolhead %} {% set x_safe = th.position.x + 20 * (1 if th.axis_maximum.x - th.position.x > 20 else -1) %} {% set y_safe = th.position.y + 20 * (1 if th.axis_maximum.y - th.position.y > 20 else -1) %} {% set z_safe = [th.position.z + 2, th.axis_maximum.z]|min %} SAVE_GCODE_STATE NAME=STATE_PRINT_END _LIGHTS_ON M400 ; wait for buffer to clear G92 E0 ; zero the extruder _NOZZLE_RETRACT ; so the nozzle does not leak while cooling down TURN_OFF_HEATERS iHEATER_OFF ; Turns off the chamber heater G90 ; absolute positioning G0 X{x_safe} Y{y_safe} Z{z_safe} F20000 ; move nozzle to remove stringing G0 X{th.axis_maximum.x//2} Y{th.axis_maximum.y - 5} F3600 ; park nozzle at rear M107 ; turn off fan #SET_PIN PIN=caselight VALUE=0.03 _STATUS STATE=part_ready UPDATE_DELAYED_GCODE ID=_delayed_motors_off DURATION=3600 RESTORE_GCODE_STATE NAME=STATE_PRINT_END # After the restore: RESTORE_GCODE_STATE also restores the flow (M221) _PRINT_CLEANUP # 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 gcode: TURN_OFF_HEATERS iHEATER_OFF ; stops the chamber heater control loop too M107 {% if 'bdwidth fila_width_0' in printer %} SET_BDWIDTH NAME=fila_width_0 COMMAND=DISABLE ; also sets M221 S100 {% endif %} M221 S100 BED_MESH_CLEAR SET_SKEW CLEAR=1 {% if 'gcode_macro _PURGE_CHECK_CFG' in printer %} SET_GCODE_VARIABLE MACRO=_PURGE_CHECK_CFG VARIABLE=ignore_missing_sensor VALUE=False {% endif %} # Retract/unretract that is remembered across prints and restarts. # Klipper's G10 only retracts once until a G11, and nothing sends G11 here, # so G10 in PRINT_WARMUP used up the retract and PRINT_END's G10 did nothing. # _NOZZLE_RETRACT adds to the saved variable nozzle_retract, _NOZZLE_UNRETRACT # extrudes that amount again (over the bucket, in PRINT_START) and clears it. [gcode_macro _NOZZLE_RETRACT] description: Retract LENGTH mm (default variable_length) and remember it for _NOZZLE_UNRETRACT; EXTRA=mm already retracted elsewhere, only remembered variable_length: 5.0 # end-of-print retract; more stops leaking, too much can jam (PLA/heat creep) variable_max_total: 15.0 # never remember more than this in total gcode: {% set length = params.LENGTH|default(length)|float %} {% set extra = params.EXTRA|default(0)|float %} {% set done = printer.save_variables.variables.nozzle_retract|default(0)|float %} {% set length = [length, max_total - done - extra]|min %} {% if length > 0 and printer.extruder.can_extrude %} SAVE_GCODE_STATE NAME=_nozzle_retract M83 G1 E-{length} F1800 RESTORE_GCODE_STATE NAME=_nozzle_retract {% else %} {% set length = 0 %} {% endif %} {% if length + extra > 0 %} SAVE_VARIABLE VARIABLE=nozzle_retract VALUE={[done + extra + length, max_total]|min} {% endif %} [gcode_macro _NOZZLE_UNRETRACT] description: Extrude what _NOZZLE_RETRACT retracted (call over the bucket, nozzle hot) gcode: {% set done = printer.save_variables.variables.nozzle_retract|default(0)|float %} {% if done > 0 %} {% if printer.extruder.can_extrude %} SAVE_GCODE_STATE NAME=_nozzle_unretract M83 G1 E{done} F300 RESTORE_GCODE_STATE NAME=_nozzle_unretract SAVE_VARIABLE VARIABLE=nozzle_retract VALUE=0 {% else %} _WARN MSG="_NOZZLE_UNRETRACT: extruder too cold, {done} mm still retracted" {% endif %} {% endif %} [delayed_gcode _delayed_motors_off] gcode: M84