# gcode to run on printer start [delayed_gcode STARTUP] gcode: # grab saved variables {% set svv = printer.save_variables.variables %} {% set bed_leeway_temp = 10 %} {% set extruder_leeway_temp = 20 %} {% set hotend_filament = svv.hotend_filament %} # check if stored variables make sense, and set them to default values if not {% if not(svv.heater_mode == "auto" or svv.heater_mode == "manual" or svv.heater_mode == "slicer")%} { action_respond_info("setting heater_mode to AUTO, before: %s" % (svv.heater_mode)) } SAVE_VARIABLE VARIABLE=heater_mode VALUE='"auto"' {% endif %} # set temp variables - call variables macro VARIABLES # kickstart fan control macro UPDATE_DELAYED_GCODE ID=FAN_CONTROL_LOOP DURATION=2 # check the current heater states and re enable heaters if able {% if svv.extruder_state == 'hot' %} {% if printer.extruder.temperature - extruder_leeway_temp <= svv.extruder_temperature %} { action_respond_info("re-enabling extruder after printer shutoff") } {% else %} { action_respond_info("extruder was enabled before last shutoff. State updated to cold.") } SAVE_VARIABLE VARIABLE=extruder_state VALUE='"cold"' {% endif %} {% endif %} {% if svv.bed_state == 'hot' %} {action_respond_info(printer.heater_bed.temperature|string)} {action_respond_info(bed_leeway_temp|string)} {action_respond_info(svv.bed_temperature|string)} {% if printer.heater_bed.temperature - bed_leeway_temp <= svv.bed_temperature %} { action_respond_info("re-enabling bed after printer shutoff") } {% else %} { action_respond_info("bed was enabled before last shutoff. State updated to cold.") } SAVE_VARIABLE VARIABLE=bed_state VALUE='"cold"' {% endif %} {% endif %} # check the filament load state: # exit-entry-bowden # 000 unloaded # 001 unloaded # 010 invalid # 011 unloaded # 100 runout # 101 invalid # 110 near_runout # 111 loaded # store button vals {% set exit_sense = (printer["gcode_button extruder_exit"].state == "PRESSED") %} {% set entry_sense = (printer["gcode_button extruder_entry"].state == "PRESSED") %} {% set bowden_sense = (printer["gcode_button bowden_sensor"].state == "PRESSED") %} # detect unloaded {% if not(entry_sense and exit_sense) or (not(entry_sense) and bowden_sense) %} {% if svv.filament_load_state != "unloaded" %} { action_respond_info("Current filament state does not match filament state on last boot. Was " ~ (svv.filament_load_state|string) ~ ", currently unloaded.") } {% endif %} SET_FILAMENT_LOAD_STATE STATE="unloaded" SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=0 # loaded {% elif entry_sense and exit_sense and bowden_sense %} {% if svv.filament_load_state != "loaded" %} { action_respond_info("Current filament state does not match filament state on last boot. Was " ~ (svv.filament_load_state|string) ~ ", currently loaded. Double check filament path.") } {% endif %} # SAVE_VARIABLE VARIABLE=loaded_filament VALUE=none SET_FILAMENT_LOAD_STATE STATE="loaded" SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=1 # runout {% elif entry_sense and not(exit_sense) and not(bowden_sense) %} { action_respond_info("Current filament state is runout. Unable to print.") } SET_FILAMENT_LOAD_STATE STATE="runout" SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=0 # near_runout {% elif entry_sense and exit_sense and not(bowden_sense) %} { action_respond_info("Current filament state is runout. Unable to print.") } SET_FILAMENT_LOAD_STATE STATE="near_runout" SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=0 {% endif %} # set the currently loaded filament SET_FILAMENT NAME={loaded_filament['name']} initial_duration: 2 [gcode_macro TEST] gcode: {% set svv = printer.save_variables.variables %} {break} {action_respond_info(svv.filaments|selectattr("name", "in", [svv.filament_hotend, svv.filament_extruder])|map(attribute="extruder",default='None')|max|string)} ####### Calibration [gcode_macro calibrate_full] gcode: G28 QUAD_GANTRY_LEVEL BED_MESH_CALIBRATE METHOD=rapid_scan G0 X239 Y210 F{700*60} SET_GCODE_VARIABLE MACRO=VARIABLES VARIABLE=calibrate VALUE='"full"' [gcode_macro calibrate] gcode: {% set calibrate = printer["gcode_macro VARIABLES"].calibrate %} {% if calibrate == "none" %} G28 QUAD_GANTRY_LEVEL BED_MESH_CALIBRATE METHOD=rapid_scan {% elif calibrate == "home" %} QUAD_GANTRY_LEVEL BED_MESH_CALIBRATE METHOD=rapid_scan {% elif calibrate == "QGL" %} G0 X15 Y22 F{700*60} BED_MESH_CALIBRATE METHOD=rapid_scan {% endif %} G0 X239 Y210 F{700*60} SET_GCODE_VARIABLE MACRO=VARIABLES VARIABLE=calibrate VALUE='"full"' [gcode_macro calibrate_override] gcode: SET_GCODE_VARIABLE MACRO=VARIABLES VARIABLE=calibrate VALUE='"full"' [gcode_macro calibrate_query] gcode: {% set val = printer["gcode_macro VARIABLES"].calibrate %} { action_respond_info("a" + val|string) } ####### PRINT START AND STOP ETC [gcode_macro START_PRINT] description: Runs before the start of a print. Checks print readyness, corrects if nessesary, and primes the nozzle. gcode: {% set svv = printer.save_variables.variables %} # first, check calibration CALIBRATE # enable the encoder filament sensor SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=1 # check the state of the loaded filament {% if svv.filament_state in ["loaded", "primed"] and svv.filament_runout_state != "runout" %} # if in auto, only bother to set bed to loaded filament parameters. The others will be set when we purge/prime. {% if svv.heater_mode == "auto" %} #SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={svv.filaments|selectattr("name", "equalto", svv.filament_extruder)|map(attribute="bed",default='None')|first|string} MODE=auto; set extruder temp # if in slicer or manual mode, quickly sanity check the set temperatures: {% else %} {% if printer['extruder'].target != 0 %} {action_raise_error("Extruder temperature is set to at or below zero")} {% endif %} {% endif %} {% if svv.filament_extruder == svv.filament_hotend %} PRIME_FILAMENT {% else %} PURGE_FILAMENT {% endif %} {% elif svv.filament_runout_state == "runout" %} {action_raise_error("Error, filament in runout state")} {% else %} {action_raise_error("Error, filament not loaded. Filament is %s" %(svv.filament_state))} {% endif %} # final enable of heaters and wait for temperature to be reached SET_HEATERS_TO_FILAMENT_AND_WAIT [gcode_macro stop_print] gcode: {% set z = params.Z|default(50)|int %} ; z hop amount SET_FILAMENT_SENSOR SENSOR=bowden_encoder_sensor ENABLE=0 # reduce temperature of extruder by 10c to reduce oozing SET_HEATER_TEMPERATURE HEATER=extruder TARGET={printer['extruder'].target - 10} MODE=auto {% if (printer.gcode_move.position.z + z) < printer.toolhead.axis_maximum.z %} ; check that zhop doesn't exceed z max G91 ; relative positioning G1 Z{z} F900 ; raise Z up by z hop amount {% else %} G0 Z{printer.toolhead.axis_maximum.z} { action_respond_info("Pause zhop exceeds maximum Z height.") } {% endif %} G90 ; absolute positioning G1 Y{258} F6000 ; park toolhead [gcode_macro PAUSE] description: Pause the actual running print rename_existing: PAUSE_MAINSAIL gcode: # Parameters {% set z = params.Z|default(10)|int %} ; z hop amount #{% set idle_timeout = client.idle_timeout|default({60*5}) %} {% set idle_timeout = 60*5 %} # if printer is not already paused... {% if printer['pause_resume'].is_paused|int == 0 %} # set variables for reference in resume macro SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=posx VALUE={printer['gcode_move'].gcode_position.x} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=posy VALUE={printer['gcode_move'].gcode_position.y} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=posz VALUE={printer['gcode_move'].gcode_position.z} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=etemp VALUE={printer['extruder'].target} SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=btemp VALUE={printer['heater_bed'].target} SAVE_GCODE_STATE NAME=PAUSE # set a new idle_timeout value SET_IDLE_TIMEOUT TIMEOUT={idle_timeout} # {client.user_pause_macro|default("")} # reduce temperature of extruder by 10c to reduce oozing SET_HEATER_TEMPERATURE HEATER=extruder TARGET={printer['extruder'].target - 10} MODE=auto {% if (printer.gcode_move.position.z + z) < printer.toolhead.axis_maximum.z %} ; check that zhop doesn't exceed z max G91 ; relative positioning G1 Z{z} F900 ; raise Z up by z hop amount {% else %} G0 Z{printer.toolhead.axis_maximum.z} { action_respond_info("Pause zhop exceeds maximum Z height.") } {% endif %} G90 ; absolute positioning G1 Y{258} F6000 ; park toolhead SAVE_GCODE_STATE NAME=PAUSEPARK ; save parked position in case toolhead is moved during the pause (otherwise the return zhop can error) {% endif %} [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_MAINSAIL variable_posx: 0 variable_posy: 0 variable_posz: 0 variable_zhop: 0 variable_etemp: 0 variable_btemp: 0 gcode: # Parameters {% set e = params.E|default(2.5)|int %} ; hotend prime amount (in mm) {% set client = printer['gcode_macro _CLIENT_VARIABLE']|default({}) %} {% set velocity = printer.configfile.settings.pause_resume.recover_velocity %} {% set sp_move = client.speed_move|default(velocity) %} {% set runout_resume = True if client.runout_sensor|default("") == "" # no runout else True if not printer[client.runout_sensor].enabled # sensor is disabled else printer[client.runout_sensor].filament_detected %} # sensor status {% set can_extrude = True if printer.toolhead.extruder == '' # no extruder defined in config else printer[printer.toolhead.extruder].can_extrude %} # status of active extruder {% set do_resume = False %} {% set prompt_txt = [] %} # if printer is paused... {% if printer['pause_resume'].is_paused|int == 1 %} SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; set timeout back to configured value RESTORE_GCODE_STATE NAME=PAUSEPARK MOVE=1 MOVE_SPEED=200 ; go back to parked position in case toolhead was moved during pause (otherwise the return zhop can error) # reset temperatures {% if etemp > 0 %} SET_HEATER_TEMPERATURE HEATER=extruder TARGET={etemp} MODE=auto {% endif %} {% if btemp > 0 %} SET_HEATER_TEMPERATURE_AND_WAIT HEATER=heater_bed TARGET={btemp} MODE=auto {% endif %} {% if etemp > 0 %} SET_HEATER_TEMPERATURE_AND_WAIT HEATER=extruder TARGET={etemp} MODE=auto ; Wait for hotend temp {% endif %} G91 ; relative positioning M83 ; relative extruder positioning {% if printer[printer.toolhead.extruder].temperature >= printer.configfile.settings.extruder.min_extrude_temp %} G1 Z{zhop * -1} E{e} F900 ; prime nozzle by E, lower Z back down {% else %} G1 Z{zhop * -1} F900 ; lower Z back down without priming (just in case we are testing the macro with cold hotend) {% endif %} RESTORE_GCODE_STATE NAME=PAUSE MOVE=1 MOVE_SPEED=60 ; restore position {% endif %} [gcode_macro CANCEL_PRINT] rename_existing: CANCEL_PRINT_MAINSAIL gcode: {% set z = params.Z|default(10)|int %} ; z hop amount SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; set timeout back to configured value CLEAR_PAUSE PRINT_END # reduce temperature of extruder by 10c to reduce oozing SET_HEATER_TEMPERATURE HEATER=extruder TARGET={printer['extruder'].target - 10} MODE=auto {% if (printer.gcode_move.position.z + z) < printer.toolhead.axis_maximum.z %} ; check that zhop doesn't exceed z max G91 ; relative positioning G1 Z{z} F900 ; raise Z up by z hop amount {% else %} G0 Z{printer.toolhead.axis_maximum.z} { action_respond_info("Pause zhop exceeds maximum Z height.") } {% endif %} G90 ; absolute positioning G1 Y{258} F6000 ; park toolhead # clear pause_next_layer and pause_at_layer as preparation for next print SET_PAUSE_NEXT_LAYER ENABLE=0 SET_PAUSE_AT_LAYER ENABLE=0 LAYER=0 ###### HEATER AUTO HANDLING [gcode_macro SET_HEATERS_TO_FILAMENT_AND_WAIT] gcode: SET_HEATER_TEMPERATURE HEATER=extruder TARGET={svv.filaments|selectattr("name", "equalto", svv.filament_hotend)|map(attribute="extruder",default='None')|first|string} MODE=auto SET_HEATER_TEMPERATURE_AND_WAIT HEATER=heater_bed TARGET={svv.filaments|selectattr("name", "equalto", svv.filament_hotend)|map(attribute="bed",default='None')|first|string} MODE=auto SET_HEATER_TEMPERATURE_AND_WAIT HEATER=extruder TARGET={svv.filaments|selectattr("name", "equalto", svv.filament_hotend)|map(attribute="extruder",default='None')|first|string} MODE=auto ## MISC MACROS [gcode_macro DUMP_VARIABLES] gcode: {% set filter_name = params.NAME|default('')|string|lower %} {% set filter_value = params.VALUE|default('')|string|lower %} {% set show_cfg = params.SHOW_CFG|default(0)|int %} {% set out = [] %} {% for key1 in printer %} {% for key2 in printer[key1] %} {% if (show_cfg or not (key1|lower == 'configfile' and key2|lower in ['config', 'settings'])) and (filter_name in key1|lower or filter_name in key2|lower) and filter_value in printer[key1][key2]|string|lower %} {% set dummy = out.append("printer['%s'].%s = %s" % (key1, key2, printer[key1][key2])) %} {% endif %} {% else %} {% if filter_name in key1|lower and filter_value in printer[key1]|string|lower %} {% set dummy = out.append("printer['%s'] = %s" % (key1, printer[key1])) %} {% endif %} {% endfor %} {% endfor %} {action_respond_info(out|join("\n"))} [gcode_macro TEST_SPEED] # Home, get position, throw around toolhead, home again. # If MCU stepper positions (first line in GET_POSITION) are greater than a full step different (your number of microsteps), then skipping occured. # We only measure to a full step to accomodate for endstop variance. # Example: TEST_SPEED SPEED=300 ACCEL=5000 ITERATIONS=10 description: Test for max speed and acceleration parameters for the printer. Procedure: Home -> ReadPositionFromMCU -> MovesToolhead@Vel&Accel -> Home -> ReadPositionfromMCU gcode: # Speed {% set speed = params.SPEED|default(printer.configfile.settings.printer.max_velocity)|int %} # Iterations {% set iterations = params.ITERATIONS|default(5)|int %} # Acceleration {% set accel = params.ACCEL|default(printer.configfile.settings.printer.max_accel)|int %} # Minimum Cruise Ratio {% set min_cruise_ratio = params.MIN_CRUISE_RATIO|default(0.5)|float %} # Bounding inset for large pattern (helps prevent slamming the toolhead into the sides after small skips, and helps to account for machines with imperfectly set dimensions) {% set bound = params.BOUND|default(20)|int %} # Size for small pattern box {% set smallpatternsize = SMALLPATTERNSIZE|default(20)|int %} # Large pattern # Max positions, inset by BOUND {% set x_min = printer.toolhead.axis_minimum.x %} {% if x_min < 0 %} {% set x_min = 0 %} {% endif %} {% set y_min = printer.toolhead.axis_minimum.y %} {% if y_min < 0 %} {% set y_min = 0 %} {% endif %} {% set x_min = x_min + bound %} {% set x_max = printer.toolhead.axis_maximum.x - bound %} {% set y_min = y_min + bound %} {% set y_max = printer.toolhead.axis_maximum.y - bound %} # Small pattern at center # Find X/Y center point {% set x_center = (printer.toolhead.axis_minimum.x|float + printer.toolhead.axis_maximum.x|float ) / 2 %} {% set y_center = (printer.toolhead.axis_minimum.y|float + printer.toolhead.axis_maximum.y|float ) / 2 %} # Set small pattern box around center point {% set x_center_min = x_center - (smallpatternsize/2) %} {% set x_center_max = x_center + (smallpatternsize/2) %} {% set y_center_min = y_center - (smallpatternsize/2) %} {% set y_center_max = y_center + (smallpatternsize/2) %} # Save current gcode state (absolute/relative, etc) SAVE_GCODE_STATE NAME=TEST_SPEED # Output parameters to g-code terminal { action_respond_info("TEST_SPEED: starting %d iterations at speed %d, accel %d" % (iterations, speed, accel)) } # Home and get position for comparison later: M400 # Finish moves - https://github.com/AndrewEllis93/Print-Tuning-Guide/issues/66 # QGL if not already QGLd (only if QGL section exists in config) {% if printer.configfile.settings.quad_gantry_level %} {% if printer.quad_gantry_level.applied == False %} G28 QUAD_GANTRY_LEVEL G28 Z {% endif %} {% endif %} # Move 50mm away from max position and home again (to help with hall effect endstop accuracy - https://github.com/AndrewEllis93/Print-Tuning-Guide/issues/24) G90 G1 X{printer.toolhead.axis_maximum.x-50} Y{printer.toolhead.axis_maximum.y-50} F{100*60} M400 # Finish moves - https://github.com/AndrewEllis93/Print-Tuning-Guide/issues/66 G28 X Y G0 X{printer.toolhead.axis_maximum.x-1} Y{printer.toolhead.axis_maximum.y-1} F{100*60} G4 P1000 GET_POSITION # Go to starting position G0 X{x_min} Y{y_min} Z{bound + 10} F{speed*60} # Set new limits {% if printer.configfile.settings.printer.minimum_cruise_ratio is defined %} SET_VELOCITY_LIMIT VELOCITY={speed} ACCEL={accel} MINIMUM_CRUISE_RATIO={min_cruise_ratio} {% else %} SET_VELOCITY_LIMIT VELOCITY={speed} ACCEL={accel} ACCEL_TO_DECEL={accel / 2} {% endif %} {% for i in range(iterations) %} # Large pattern diagonals G0 X{x_min} Y{y_min} F{speed*60} G0 X{x_max} Y{y_max} F{speed*60} G0 X{x_min} Y{y_min} F{speed*60} G0 X{x_max} Y{y_min} F{speed*60} G0 X{x_min} Y{y_max} F{speed*60} G0 X{x_max} Y{y_min} F{speed*60} # Large pattern box G0 X{x_min} Y{y_min} F{speed*60} G0 X{x_min} Y{y_max} F{speed*60} G0 X{x_max} Y{y_max} F{speed*60} G0 X{x_max} Y{y_min} F{speed*60} # Small pattern diagonals G0 X{x_center_min} Y{y_center_min} F{speed*60} G0 X{x_center_max} Y{y_center_max} F{speed*60} G0 X{x_center_min} Y{y_center_min} F{speed*60} G0 X{x_center_max} Y{y_center_min} F{speed*60} G0 X{x_center_min} Y{y_center_max} F{speed*60} G0 X{x_center_max} Y{y_center_min} F{speed*60} # Small pattern box G0 X{x_center_min} Y{y_center_min} F{speed*60} G0 X{x_center_min} Y{y_center_max} F{speed*60} G0 X{x_center_max} Y{y_center_max} F{speed*60} G0 X{x_center_max} Y{y_center_min} F{speed*60} {% endfor %} # Restore max speed/accel/accel_to_decel to their configured values {% if printer.configfile.settings.printer.minimum_cruise_ratio is defined %} SET_VELOCITY_LIMIT VELOCITY={printer.configfile.settings.printer.max_velocity} ACCEL={printer.configfile.settings.printer.max_accel} MINIMUM_CRUISE_RATIO={printer.configfile.settings.printer.minimum_cruise_ratio} {% else %} SET_VELOCITY_LIMIT VELOCITY={printer.configfile.settings.printer.max_velocity} ACCEL={printer.configfile.settings.printer.max_accel} ACCEL_TO_DECEL={printer.configfile.settings.printer.max_accel_to_decel} {% endif %} # Re-home and get position again for comparison: M400 # Finish moves - https://github.com/AndrewEllis93/Print-Tuning-Guide/issues/66 # G28 # This is a full G28 to fix an issue with CoreXZ - https://github.com/AndrewEllis93/Print-Tuning-Guide/issues/12 # Go to XY home positions (in case your homing override leaves it elsewhere) G90motors G0 X{printer.toolhead.axis_maximum.x-1} Y{printer.toolhead.axis_maximum.y-1} F{100*60} G4 P1000 GET_POSITION # Restore previous gcode state (absolute/relative, etc) RESTORE_GCODE_STATE NAME=TEST_SPEED