Here’s the latest version of the mainsail config I have for klipper which allow me to use Pause and Resume.
NOTE: This should be used with caution, it is not complete AND not yet been tested on a CNC with an actual spindle connected
I haven’t yet worked out how to persist the speed the spindle was running at before pausing, so it’s hardcoded to resume at 5000.
I didn’t get much time to work on it yesterday and won’t tomorrow so wanted to share where I’m at.
This is my current complete mainsail.cfg
## Mainsail klipper macro definitions
##
## Copyright (C) 2022 Alex Zellner <alexander.zellner@googlemail.com>
##
## This file may be distributed under the terms of the GNU GPLv3 license
## Version 2.0
## add [include mainsail.cfg] to your printer.cfg
## Customization:
## copy the following macro to your printer.cfg (outside of mainsail.cfg)
#[gcode_macro _CLIENT_VARIABLE]
#variable_use_custom_pos : True ; use custom park coordinates for x,y [True/False]
#variable_custom_park_x : 100.0 ; custom x position; value must be within your defined min and max of X
#variable_custom_park_y : 100.0 ; custom y position; value must be within your defined min and max of Y
#variable_custom_park_dz : 2.0 ; custom dz value; the value in mm to lift the nozzle when move to park position
#variable_speed_hop : 200.0 ; z move speed in mm/s
#variable_speed_move : 200.0 ; move speed in mm/s
#variable_park_at_cancel : False ; allow to move the toolhead to park while execute CANCEL_PRINT [True,False]
#gcode:
## After you uncomment it add your custom values
## You now can use your PAUSE macro direct in your M600 here a short example:
#[gcode_macro M600]
#description: Tool change
#gcode: PAUSE X=10 Y=10 Z_MIN=50
## That will park your head front left with a minimum hight of 50mm above the bed. If your head
## is already above 50mm it will use only the z_hop specified with dz.
[virtual_sdcard]
path: ~/printer_data/gcodes
on_error_gcode: CANCEL_PRINT
[pause_resume]
[display_status]
[gcode_macro CANCEL_PRINT]
description: Cancel the actual running print
rename_existing: CANCEL_PRINT_BASE
gcode:
##### get user parameters or use default #####
{% set allow_park = False if printer['gcode_macro _CLIENT_VARIABLE'] is not defined
else False if printer['gcode_macro _CLIENT_VARIABLE'].park_at_cancel is not defined
else True if printer['gcode_macro _CLIENT_VARIABLE'].park_at_cancel|lower == 'true'
else False %}
##### end of definitions #####
{% if not printer.pause_resume.is_paused and allow_park %} _TOOLHEAD_PARK_PAUSE_CANCEL {% endif %}
CANCEL_PRINT_BASE
[gcode_macro PAUSE]
variable_restore: {'pos': {'x': 0, 'y':0, 'z':0}}
description: Pause the actual running print
rename_existing: PAUSE_BASE
gcode:
PAUSE_BASE
{% set restore = {'pos':
{'x': printer.gcode_move.gcode_position.x, 'y': printer.gcode_move.gcode_position.y, 'z': printer.gcode_move.gcode_position.z },
'rpm': 5000} %}
SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=restore VALUE="{restore}"
M117 Paused at X{restore.pos.x|int} Y{restore.pos.y|int} Z{restore.pos.z} spinning at {restore.rpm}rpm
_TOOLHEAD_PARK_PAUSE_CANCEL {rawparams}
[gcode_macro RESUME]
description: Resume the actual running print
rename_existing: RESUME_BASE
gcode:
##### get user parameters or use default #####
{% set macro_found = True if printer['gcode_macro _CLIENT_VARIABLE'] is defined else False %}
{% set client = printer['gcode_macro _CLIENT_VARIABLE'] %}
{% set paused_at = printer['gcode_macro PAUSE'] %}
{% set velocity = printer.configfile.settings.pause_resume.recover_velocity %}
{% set sp_move = velocity * 60 if not macro_found else client.speed_move|default(velocity) * 60 %}
{% set sp_hop = 900 if not macro_found else client.speed_hop|default(15) * 60 %}
##### define resume position
{% set x_resume = printer['gcode_macro PAUSE'].restore.pos.x %}
{% set y_resume = printer['gcode_macro PAUSE'].restore.pos.y %}
{% set z_resume = printer['gcode_macro PAUSE'].restore.pos.z %}
{% set rpm_resume = printer['gcode_macro PAUSE'].restore.rpm %}
##### end of definitions #####
#### move back to the saved position before resuming
M117 Resume to X{x_resume|int} Y{y_resume|int} then Z{z_resume} spinning as {rpm_resume}rpm
G90
#### restarting spindle, need to
M3 S{rpm_resume}
G1 X{x_resume} Y{y_resume} F{sp_move}
G1 Z{z_resume} F{sp_hop}
RESUME_BASE VELOCITY={params.VELOCITY|default(sp_move)}
[gcode_macro _TOOLHEAD_PARK_PAUSE_CANCEL]
description: Helper: park toolhead used in PAUSE and CANCEL_PRINT
gcode:
##### get user parameters or use default #####
{% set macro_found = True if printer['gcode_macro _CLIENT_VARIABLE'] is defined else False %}
{% set client = printer['gcode_macro _CLIENT_VARIABLE'] %}
{% set velocity = printer.configfile.settings.pause_resume.recover_velocity %}
{% set use_custom = False if not macro_found
else False if client.use_custom_pos is not defined
else True if client.use_custom_pos|lower == 'true'
else False %}
{% set custom_park_x = 0.0 if not macro_found else client.custom_park_x|default(0.0) %}
{% set custom_park_y = 0.0 if not macro_found else client.custom_park_y|default(0.0) %}
{% set park_dz = 2.0 if not macro_found else client.custom_park_dz|default(2.0)|abs %}
{% set sp_hop = 900 if not macro_found else client.speed_hop|default(15) * 60 %}
{% set sp_move = velocity * 60 if not macro_found else client.speed_move|default(velocity) * 60 %}
##### get config and toolhead values #####
{% set act = printer.toolhead.position %}
{% set max = printer.toolhead.axis_maximum %}
{% set cone = printer.toolhead.cone_start_z|default(max.z) %} ; hight as long the toolhead can reach max and min of an delta
{% set round_bed = True if printer.configfile.settings.printer.kinematics is in ['delta','polar','rotary_delta','winch']
else False %}
##### define park position #####
{% set z_min = params.Z_MIN|default(0)|float %}
{% set z_park = [[(act.z + park_dz), z_min]|max, max.z]|min %}
{% set x_park = params.X if params.X is defined
else custom_park_x if use_custom
else 0.0 if round_bed
else (max.x - 5.0) %}
{% set y_park = params.Y if params.Y is defined
else custom_park_y if use_custom
else (max.y - 5.0) if round_bed and z_park < cone
else 0.0 if round_bed
else (max.y - 5.0) %}
{% if "xyz" in printer.toolhead.homed_axes %}
G90
G1 Z{z_park} F{sp_hop}
#### stopping spindle
M5
G1 X{x_park} Y{y_park} F{sp_move}
{% if not printer.gcode_move.absolute_coordinates %} G91 {% endif %}
{% else %}
{action_respond_info("Printer not homed")}
{% endif %}
I currently have these variables include via my printer.cfg;
## Customization:
## copy the following macro to your printer.cfg (outside of mainsail.cfg)
[gcode_macro _CLIENT_VARIABLE]
variable_use_custom_pos : True ; use custom park coordinates for x,y [True/False]
variable_custom_park_x : 100.0 ; custom x position; value must be within your defined min and max of X
variable_custom_park_y : 100.0 ; custom y position; value must be within your defined min and max of Y
variable_custom_park_dz : 40.0 ; custom dz value; the value in mm to lift the nozzle when move to park position
variable_speed_hop : 5.0 ; z move speed in mm/s
variable_speed_move : 80.0 ; move speed in mm/s
#variable_park_at_cancel : False ; allow to move the toolhead to park while execute CANCEL_PRINT [True,False]
gcode:
I’ll be focusing on the drag chains and other modifications next, and still some time away from being ready for cutting. i.e. I need to build a table, speed control for the Makita etc.