Hi *,
to yesterday I implemented Material profiles for Klipper. They worked fine but was useless as some materials print fine with z-hop and other without, so I still needed to reslice.
So I implemented z-hop for firmware retraction. It is rarely tested until now, but a print that is known to print ugly without z-hop now looks fine. It has been tested for a while by multiply users, it should be safe to use on single extruder printers.
The strategy is to modify G0, G1, G2 and G3 to respect a positive Z-offset that is set while retract. All movements will then add this offset until the unretraction is done.
For not need to switch between modes and restore them the Z move will be made inside G10 (retract) and G11 (unretract) in the corresponding coordinate mode.
SET_ZHOP HEIGHT=0.2 VELOCITY=100
Will activate the zhop and save it to non-volatile memory (remains after restart/reboot…)
GET_ZHOP
Will print the current setting.
CLEAN_ZHOP
should be called in the start gcode, before any movement! It will set the z-offset to 0.
There is no setting for the Z movement speed you need to change it in the macro. Just find and replace F300
Ofc firmware retraction needs to be activated in the slicer for getting this work!
The methods also have a wait after retract setting. You can safe ignore it or remove it if you don’t need it. It was helpful for me in some situations.
[firmware_retraction]
retract_length: 1.5
# The length of filament (in mm) to retract when G10 is activated,
# and to unretract when G11 is activated (but see
# unretract_extra_length below). The default is 0 mm.
retract_speed: 45
# The speed of retraction, in mm/s. The default is 20 mm/s.
unretract_extra_length: 0.02
# The length (in mm) of *additional* filament to add when
# unretracting.
unretract_speed: 10
# The speed of unretraction, in mm/s. The default is 10 mm/s.
[gcode_arcs]
#If you allready have this somewhere you will need to remove it here or there
[gcode_macro G0]
rename_existing: G0.1
gcode:
G1 {rawparams}
[gcode_macro G1]
rename_existing: G1.1
variable_z_hop_offset = 0
gcode:
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
{% if printer.gcode_move.absolute_coordinates and OFFSET > 0 and ('Z' in params) %}
; Rewrite paramters for adjust Z if offset is activ and we are absulute
{% set new_params = ''|string %}
{% if ('E' in params) %}
{% set new_params = new_params ~ " E" ~ params.E %}
{% endif %}
{% if ('F' in params) %}
{% set new_params = new_params ~ " F" ~ params.F %}
{% endif %}
{% if ('X' in params) %}
{% set new_params = new_params ~ " X" ~ params.X %}
{% endif %}
{% if ('Y' in params) %}
{% set new_params = new_params ~ " Y" ~ params.Y %}
{% endif %}
{% set new_params = new_params ~ (' Z%g' % (params.Z|float + OFFSET))|string %}
; Make the movement
G1.1{new_params}
{% else %}
; Don't care if relativ or no offset activ
G1.1 {rawparams}
{% endif %}
[gcode_macro G2]
rename_existing: G2.1
gcode:
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
{% if printer.gcode_move.absolute_coordinates and OFFSET > 0 and ('Z' in params) %}
; Rewrite paramters for adjust Z if offset is activ and we are absulute
{% set new_params = [] %}
{% for key in params %}
{% if key == "Z" %}
{% set x = new_params.append('Z%g' % (params[key]|float + OFFSET)) %}
{% else %}
{% set x = new_params.append(key + params[key]) %}
{% endif %}
{% endfor %}
{% set new_params=new_params|join(" ") %}
; Make the movement
G2.1 {new_params}
{% else %}
; Don't care if relativ or no offset activ
G2.1 {rawparams}
{% endif %}
[gcode_macro G3]
rename_existing: G3.1
gcode:
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
{% if printer.gcode_move.absolute_coordinates and OFFSET > 0 and ('Z' in params) %}
; Rewrite paramters for adjust Z if offset is activ and we are absulute
{% set new_params = [] %}
{% for key in params %}
{% if key == "Z" %}
{% set x = new_params.append('Z%g' % (params[key]|float + OFFSET)) %}
{% else %}
{% set x = new_params.append(key + params[key]) %}
{% endif %}
{% endfor %}
{% set new_params=new_params|join(" ") %}
; Make the movement
G3.1 {new_params}
{% else %}
; Don't care if relativ or no offset activ
G3.1 {rawparams}
{% endif %}
# Hacked G11 (unretract) for have a short delay after unretract, remove it or set wait to 0, if this is not needed.
[gcode_macro G11]
rename_existing: G11.1
gcode:
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
; Z-UNHOP
{% if OFFSET > 0 %}
{% set VELOCITY = printer.save_variables.variables.current_zhop_velocity|default(300)|float %}
SET_GCODE_VARIABLE MACRO=G1 VARIABLE=z_hop_offset VALUE=0
{% set speed = printer.gcode_move.speed %}
; Make a different movement coresponting to current coordinate mode
{% if printer.gcode_move.absolute_coordinates %}
#G1.1 F{VELOCITY} Z{(printer.gcode_move.position.z - OFFSET)}
G91
G1.1 Z-{OFFSET} F{VELOCITY}
G90
{% else %}
G1.1 Z-{OFFSET} F{VELOCITY}
{% endif %}
G1.1 F{speed}
{% endif %}
G11.1
; Have an addional parameter for wait after unretract
{% set wait = printer.save_variables.variables.current_unretract_wait|default(0)|float %}
{% if wait > 0 %}
G4 P{'%d' %wait}
{% endif %}
# Hacked G10 (retract) with ZHOP
[gcode_macro G10]
rename_existing: G10.1
gcode:
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
; Make the retract
G10.1
; Make the ZHOP
{% set HEIGHT = printer.save_variables.variables.current_zhop_height|default(0)|float %}
{% if HEIGHT > 0 %}
{% if OFFSET > 0 %}
SHOW_MSG MSG="ZHOP allready activ"
{% else %}
{% set VELOCITY = printer.save_variables.variables.current_zhop_velocity|default(300)|float %}
{% set speed = printer.gcode_move.speed %}
SET_GCODE_VARIABLE MACRO=G1 VARIABLE=z_hop_offset VALUE={HEIGHT}
; Make a different movement coresponting to current coordinate mode
{% if printer.gcode_move.absolute_coordinates %}
#SHOW_MSG MSG="G10 abs up: {(printer.gcode_move.position.z + HEIGHT)}"
#G1.1 Z{(printer.gcode_move.position.z + HEIGHT)} F{VELOCITY}
G91
G1.1 Z{HEIGHT} F{VELOCITY}
G90
{% else %}
G1.1 Z{HEIGHT} F{VELOCITY}
{% endif %}
G1.1 F{speed}
{% endif %}
{% endif %}
# Set the wished ZHOP height/distance. Set to 0 will disable it!
[gcode_macro SET_ZHOP]
gcode:
{% set HEIGHT = params.HEIGHT|default(0)|float %}
{% set VELOCITY = params.VELOCITY|default(300)|float %}
{% if VELOCITY > 0 %}
SAVE_VARIABLE VARIABLE='current_zhop_velocity' VALUE={VELOCITY}
{% endif %}
{% if HEIGHT >= 0 %}
SAVE_VARIABLE VARIABLE='current_zhop_height' VALUE={HEIGHT}
SHOW_MSG MSG="ZHOP: Z{HEIGHT}/F{VELOCITY}"
{% endif %}
# This should allways be part of the start gcode. Worestcase you will print with an positive offset.
[gcode_macro CLEAR_ZHOP]
gcode:
SET_GCODE_VARIABLE MACRO=G1 VARIABLE=z_hop_offset VALUE=0
# Print ZHOP settings
[gcode_macro GET_ZHOP]
gcode:
{% set HEIGHT = printer.save_variables.variables.current_zhop_height|default(0)|float %}
{% set VELOCITY = printer.save_variables.variables.current_zhop_velocity|default(300)|float %}
{% set OFFSET = printer["gcode_macro G1"].z_hop_offset %}
SHOW_MSG MSG="ZHOP height: {HEIGHT}"
SHOW_MSG MSG="ZHOP velocity: {VELOCITY}"
SHOW_MSG MSG="ZHOP retracted: {'yes' if (OFFSET > 0) else 'no'}"
[gcode_macro SHOW_MSG]
gcode:
{% set MSG = params.MSG|default("No msg")|string %}
M117 {MSG}
RESPOND MSG={'"%s"' % MSG}
I’m not very happy with casting the deltas to float in relative mode. Rounding error could add up if no coordinates come in absolute mode. But not sure if float is really a float here and if this could be a real world problem.
Additionally, I’m not very sure my order is good:
- retract
- zhop
- movement
- unzhop
- unretract
I think the best thing would be:
- unretract 2/3
- start zhop and parallel unretract 1/3
- movement
- unzhop
- unretract
As this is difficult maybe it could be an idea to make zhop and retract parallel. It would be easy to implement, but I’m not sure, that this is an advantage.
If you see any issues please write!
Please also write if I forgot to supply some macros that are used by this, just the standard problem if some finds macros on the net ^^
If you want to test this code, don’t forget to add this or something similar to your config (thanks @Sitoxic and @dredivan):
[save_variables]
filename: ~/klipper-variables.cfg
#For SHOW_MSG macro:
[respond]
Thanks for reading
Edit:
- removed velocity bug
- added z velocity to the ZHOP settings.
- Repaired Typos in set function
- Changed the movement from absolute to relative (what fixed the issue we had while using CURA 5, but the root cause is sadly still unknown)
- Added
SHOW_MSG
macro - Did some test prints
- Added G2 and G3
- Removed a bug inside G2 and G3 caused variable by scope inside for loops
- Fixed problem with G3