diff --git a/printer_data/config/printer.cfg b/printer_data/config/printer.cfg index 725cedc..f6a142c 100644 --- a/printer_data/config/printer.cfg +++ b/printer_data/config/printer.cfg @@ -665,24 +665,82 @@ gcode: STATUS_PRINTING [gcode_macro LINE_PURGE] -description: Fixed front purge line that stays below Klipper's extrusion safety limit +description: Adaptive purge outside the print; safely skips when no free edge exists gcode: + {% set objects = printer.exclude_object.objects %} + {% set points = objects | map(attribute='polygon') | sum(start=[]) %} + {% set line_length = 100.0 %} + {% set wipe_length = 5.0 %} + {% set clearance = 8.0 %} + {% set x_offset = printer.configfile.settings.cartographer.x_offset|float %} + {% set y_offset = printer.configfile.settings.cartographer.y_offset|float %} + # Both nozzle and protruding Cartographer must remain at least 5 mm inside + # the 250 mm plate. The rear limit also avoids the brush at nozzle Y=250.5. + {% set safe_x_min = [printer.toolhead.axis_minimum.x|float + 5.0, 5.0 - x_offset]|max %} + {% set safe_x_max = [printer.toolhead.axis_maximum.x|float - 5.0, 245.0 - x_offset]|min %} + {% set safe_y_min = [printer.toolhead.axis_minimum.y|float + 5.0, 5.0 - y_offset]|max %} + {% set safe_y_max = [printer.toolhead.axis_maximum.y|float - 5.0, 245.0 - y_offset]|min %} + {% if "xyz" not in printer.toolhead.homed_axes %} { action_raise_error("LINE_PURGE requires homed X, Y and Z") } {% elif not printer.extruder.can_extrude %} { action_raise_error("LINE_PURGE requires a hot extruder") } + {% elif points|length == 0 %} + { action_respond_info("LINE_PURGE skipped: slicer supplied no object polygons") } + {% elif safe_x_max - safe_x_min < line_length + wipe_length or safe_y_max - safe_y_min < line_length + wipe_length %} + { action_respond_info("LINE_PURGE skipped: configured safe area is too small") } {% else %} + {% set object_x_min = points | map(attribute=0) | min | float %} + {% set object_x_max = points | map(attribute=0) | max | float %} + {% set object_y_min = points | map(attribute=1) | min | float %} + {% set object_y_max = points | map(attribute=1) | max | float %} + {% set front_gap = object_y_min - safe_y_min %} + {% set left_gap = object_x_min - safe_x_min %} + {% set right_gap = safe_x_max - object_x_max %} + {% set rear_gap = safe_y_max - object_y_max %} + {% set largest_gap = [front_gap, left_gap, right_gap, rear_gap]|max %} + {% set x_center = (object_x_min + object_x_max) / 2.0 %} + {% set y_center = (object_y_min + object_y_max) / 2.0 %} + {% set purge_x = [[x_center - line_length / 2.0, safe_x_min]|max, safe_x_max - line_length - wipe_length]|min %} + {% set purge_y = [[y_center - line_length / 2.0, safe_y_min]|max, safe_y_max - line_length - wipe_length]|min %} + + {% if largest_gap < clearance %} + { action_respond_info("LINE_PURGE skipped: print occupies every safe bed edge") } + {% else %} # 12 mm of 1.75 mm filament over 100 mm = about 0.289 mm2, # safely below max_extrude_cross_section=0.64 mm2 for the 0.4 mm nozzle. SAVE_GCODE_STATE NAME=LINE_PURGE_STATE G90 M83 - G0 X30 Y10 Z2 F12000 - G0 Z0.4 F600 - G1 X130 E12 F600 - G1 X135 F1800 + {% if largest_gap == front_gap %} + {% set edge = "front" %} + G0 X{purge_x} Y{object_y_min - clearance} Z2 F12000 + G0 Z0.4 F600 + G1 X{purge_x + line_length} E12 F600 + G1 X{purge_x + line_length + wipe_length} F1800 + {% elif largest_gap == left_gap %} + {% set edge = "left" %} + G0 X{object_x_min - clearance} Y{purge_y} Z2 F12000 + G0 Z0.4 F600 + G1 Y{purge_y + line_length} E12 F600 + G1 Y{purge_y + line_length + wipe_length} F1800 + {% elif largest_gap == right_gap %} + {% set edge = "right" %} + G0 X{object_x_max + clearance} Y{purge_y} Z2 F12000 + G0 Z0.4 F600 + G1 Y{purge_y + line_length} E12 F600 + G1 Y{purge_y + line_length + wipe_length} F1800 + {% else %} + {% set edge = "rear" %} + G0 X{purge_x} Y{object_y_max + clearance} Z2 F12000 + G0 Z0.4 F600 + G1 X{purge_x + line_length} E12 F600 + G1 X{purge_x + line_length + wipe_length} F1800 + {% endif %} G0 Z2 F600 RESTORE_GCODE_STATE NAME=LINE_PURGE_STATE MOVE=0 + { action_respond_info("LINE_PURGE used the %s free edge with 8 mm object clearance" % edge) } + {% endif %} {% endif %} [gcode_macro _PRINT_CLEANUP]