Nozzle brush macro only works on second run

Basic Information:

Printer Model: Micron 180
MCU / Printerboard: BTT Manta M8P
klippy.log
klippy.zip (1.7 MB)

Describe your issue:

Hello everyone, apologies in advance for the long macro incoming:

I’m using a slightly modified version of the KOMB nozzle brush macro by TmRxJD. The macro is supposed to heat up the nozzle, home, purge some filament, retract a certain amount (retract_before), scrub the nozzle on the brush, and finally retract again by the amount retract_after.

The strange issue I’m having is that the first time I run the macro on Klipper startup, the retractions don’t happen. Everything else in the macro works as intended, i.e., homing, scrubbing, purging. Only when I run the macro a second time do the retractions actually occur. As a result, the filament oozing from the nozzle ruins my z offset calibration (I’m using Auto Z Calibration), since I run KOMB right before the calibration in my print_start macro.

I’ve already checked that pre-homing the printer doesn’t make a difference; neither does running a different macro beforehand. In fact, I added some RESPOND commands before the retraction commands, and on the first run of the macro these don’t even execute. (Before anyone asks, I’ve already checked that the extruder temperature is sufficient and that retract_before and retract_after have values. Also, the original, non-modified version of the macro has the same issue.)

I went through the code several times already, and perhaps due to my inexperience with writing Klipper macros, I wasn’t able to find anything out of the ordinary. Can anyone else see what could be the cause of the issue? (The first 3/4 of the code is all calculating the scrubbing trajectory; the move and extrude commands follow.)

Thanks in advance.

`[gcode_macro KOMB]
gcode:
SAVE_GCODE_STATE NAME=clean_nozzle_state
status_cleaning

## Define color-wrapper
{% set ns2 = namespace() %}
{% macro color_text(text='', color='primary') -%}
    {% set color = color | string %}
    {% set text = text | string  %}
    {% set ns2.out = '<span class=' + color + '--text>' + text + '</span>'| string %}
{% endmacro %}

# Welcome message
{ color_text(color="primary", text="K") }
{% set msg = ns2.out %}
{ color_text(color="error", text="O") }
{% set msg = msg + ns2.out %}
{ color_text(color="warning", text="M") }
{% set msg = msg + ns2.out %}
{ color_text(color="accent", text="B") }
{% set msg = msg + ns2.out %}
{ color_text(color="success", text="ing") }
{% set msg = msg + ns2.out %}
{ color_text(color="primary", text=" Started") }
{% set msg = msg + ns2.out %}
{ color_text(color="secondary", text="!") }
{% set msg = msg + ns2.out %}
{ action_respond_info( msg ) }

{% set vars = printer["gcode_macro _KOMB_Variables"] %}

{% set x_min = params.BRUSH_LOCATION_X|default(vars.brush_location_x)|float %}
{% set size_x = params.BRUSH_SIZE_X|default(vars.brush_size_x)|float %}    
{% set offset = params.OFFSET|default(vars.offset)|float %}
{% set repeat = params.REPEAT|default(vars.repeat)|int %}
{% set y_min = params.BRUSH_LOCATION_Y|default(vars.brush_location_y)|float %}
{% set size_y = params.BRUSH_SIZE_Y|default(vars.brush_size_y)|float %}
{% set step = params.STEP_SIZE|default(vars.step)|float %}
{% set reverse = params.ENABLE_REVERSE|default(vars.reverse_enable)|abs %}
{% set z_max = params.BRUSH_LOCATION_Z|default(vars.brush_location_z)|float %}
{% set size_z = params.BRUSH_SIZE_Z|default(vars.brush_size_z)|float %}
{% set z_step = params.Z_STEP_SIZE|default(vars.z_step)|float %}
{% set z_hop_height = params.Z_HOP_HEIGHT|default(vars.z_hop_height)|float %}
{% set speed = params.SPEED|default(vars.speed)|int %}
{% set retract_before = params.RETRACT_BEFORE_WIPE|default(vars.retract_before_wipe)|float %}
{% set auto_home = params.ENABLE_AUTO_HOMING|default(vars.auto_home_enable)|abs %}
{% set opposite_side = params.START_OPPOSITE_SIDE|default(vars.start_opposite_side)|abs %}
{% set speed_up = params.SPEED_UP_BY|default(vars.speed_up)|int %}
{% set retract_during = params.RETRACT_DURING_WIPE|default(vars.retract_during_wipe)|float %}
{% set auto_heat = params.AUTO_HEAT_NOZZLE|default(vars.auto_heat_nozzle) | abs %}
{% set adjacent_side = params.START_ADJACENT_SIDE|default(vars.start_adjacent_side)|abs %}
{% set travel_speed = params.TRAVEL_SPEED|default(vars.travel_speed)|int %}
{% set retract_after = params.RETRACT_AFTER_WIPE|default(vars.retract_after_wipe)|float %}
{% set retract_speed = params.RETRACT_SPEED|default(vars.retract_speed)|float %}
{% set cold_clean = params.CLEAN_WHILE_COLD|default(vars.clean_while_cold)|abs %}
{% set pattern = params.PATTERN|default(vars.pattern) %}
{% set verbose = params.ENABLE_VERBOSE_OUTPUT|default(vars.verbose_enable)|abs %}
{% set verbose_points = params.ENABLE_VERBOSE_POINTS|default(vars.verbose_points)|abs %}
{% set temp = params.TEMPERATURE|default(vars.temp)|float %}
{% set angle = params.ANGLE|default(vars.angle) %}
{% set return_to_start = params.ENABLE_RETURN_TO_START|default(vars.return_to_start)|abs %}
{% set purge = params.PURGE_AMOUNT|default(vars.purge_amount)|float %}
{% set purge_x = params.PURGE_LOCATION_X|default(vars.purge_location_x)|float %}
{% set purge_y = params.PURGE_LOCATION_Y|default(vars.purge_location_y)|float %}
{% set purge_z = params.PURGE_LOCATION_Z|default(vars.purge_location_z)|float %}
{% set current_x = printer.toolhead.position.x %}
{% set current_y = printer.toolhead.position.y %}
{% set current_z = printer.toolhead.position.z %}
{% set additional_z = params.ADD_MOVE_Z|default(0)|float %}

#Set Y or X brush size to current location if size and location set to 0
{% if y_min == 0 %} 
    {% set y_min = printer.toolhead.position.y %}
{% elif x_min == 0 %} 
    {% set x_min = printer.toolhead.position.y %}
{% endif %}   
{% if z_max == 0 %} 
    {% set z_max = printer.toolhead.position.z %}
{% endif %}

{% set x_max, y_max, z_min = x_min + size_x, y_min + size_y, z_max - size_z | float %}

#Recalcualte min/max with offset
{% set x_min, y_min = x_min - offset, y_min - offset | float %} 
{% set x_max, y_max = x_max + offset, y_max + offset | float %} 
{% set z_hop = z_max + z_hop_height | float %}

# Check if min/max exceed configured limits and correct to avoid errors.
{% set x_min = x_min if x_min <= printer.toolhead.axis_maximum.x or x_min >= printer.toolhead.axis_minimum.x else printer.toolhead.axis_minimum.x %}
{% set x_max = x_max if x_max >= printer.toolhead.axis_minimum.x or x_max <= printer.toolhead.axis_minimum.x else printer.toolhead.axis_maximum.x %}
{% set y_min = y_min if y_min >= printer.toolhead.axis_minimum.y or y_min <= printer.toolhead.axis_minimum.y else printer.toolhead.axis_minimum.y %}
{% set y_max = y_max if y_max <= printer.toolhead.axis_maximum.y or y_max >= printer.toolhead.axis_minimum.y else printer.toolhead.axis_maximum.y %}   
{% set z_min = z_min if z_min >= printer.toolhead.axis_minimum.z or z_min <= printer.toolhead.axis_minimum.z else printer.toolhead.axis_minimum.z %}
{% set z_max = z_max if z_max <= printer.toolhead.axis_maximum.z or z_max >= printer.toolhead.axis_maximum.z else printer.toolhead.axis_maximum.z %}
{% set z_hop = z_hop if z_hop >= printer.toolhead.axis_minimum.z or z_hop <= printer.toolhead.axis_maximum.z else z_max %}

{% set y_min = printer.toolhead.position.y if size_y == 0 and y_min == 0 else y_min %}
{% set y_max = printer.toolhead.position.y if size_y == 0 and y_max == 0 else y_max %}
{% set z_min = printer.toolhead.position.z if size_z == 0 and z_min == 0 else z_min %}
{% set z_max = printer.toolhead.position.z if size_z == 0 and z_max == 0 else z_max %}

#Adjust brush size based on recalculated min/max values
{% set size_x = x_max - x_min | round(1) %}
{% set size_y = y_max - y_min | round(1) %}
{% set size_z = z_max - z_min | round(1) %}  

#Set X brush size to current location if size set to 0
{% if x_min == 0 and size_x == 1 %} 
    {% set x_min = printer.toolhead.position.x %}
    {% set x_max = printer.toolhead.position.x %}

#Set Y brush size to current location if size set to 0
{% elif y_min == 0 and size_y == 1 %} 
    {% set y_min = printer.toolhead.position.y %}
    {% set y_max = printer.toolhead.position.y %}
{% endif %}

{% set x_center, y_center, z_center = (x_min + x_max) / 2, (y_min + y_max) / 2, (z_min + z_max) / 2 | round(1) %}

# Calculate aspect ratio
{% set long_side = (size_x, size_y) | max %}
{% set short_side = (size_x, size_y) | min if size_y != 0 or size_x != 0 else 1 %}
{% set aspect_ratio = (long_side / short_side) | round(1) if short_side != 0 else long_side / 1 %}

{% set long_center = (x_max + x_min) / 2 if long_side == size_x else (y_max + y_min) / 2 %}
{% set short_center = (y_max + y_min) / 2 if short_side == size_y else (x_max + x_min) / 2 %}

# Taylor series approximations for sin and cos for performing diagonal movement calculations 
{% set angle_rad = angle | float * 3.141592653589793 / 180.0 | float | round(5) %}
{% set sin_angle = (angle_rad - (angle_rad**3)/6 + (angle_rad**5)/120|float) if angle != 45 else 1 %}
{% set cos_angle = (1 - (angle_rad**2)/2 + (angle_rad**4)/24|float) if angle != 45 else 1 %} 

{% if pattern == 1 %}    
    {% set r_val = retract_before if printer.extruder.temperature >= temp else 0 %}
    
    {% set points = [] %}
    {% set i_val = 0 %}
    {% set j_val = 0 %}
    {% set f_val = speed %}

    {% set ns = namespace() %}
    {% set ns.nozzle_pos = [x_min, y_min, z_max, i_val, j_val, r_val, f_val] if not opposite_side else [x_max, y_max, z_max, i_val, j_val, r_val, f_val] %}
    {% set nozzle_pos = ns.nozzle_pos %}
    {% set start_pos = ns.nozzle_pos %}
    {% set _ = points.append(ns.nozzle_pos) %}
         
    # Calculate the number of steps in all directions 
    {% set long_points = ((long_side / step) | round) if size_y != 0 else 1 %}
    {% set short_points = short_side / step | round if size_y != 0 or size_x != 0 else 1 %}

    {% for r in range(1 + repeat|int) %} 
        {% set tmp_points = [] %}
        {% for i in range(long_points|int) %}
            # Generate 1st point
            {% if not adjacent_side %}
                {% if not opposite_side %} 
                    {% set x_val = nozzle_pos[0] + size_y + i | round(1) if size_y != 0 else nozzle_pos[0] + size_x | round(1) %}
                    {% set y_val = nozzle_pos[1] + size_y if size_y != 0 else nozzle_pos[1] %}
                {% else %} # If opposite_side = true and adjacent side = false
                    {% set x_val = nozzle_pos[0] - size_y - i | round(1) if size_y != 0 else nozzle_pos[0] - size_x | round(1) %}
                    {% set y_val = nozzle_pos[1] - size_y if size_y != 0 else nozzle_pos[1] %}%}
                {% endif %}
            {% else %} # if adjacent side = true
                {% if not opposite_side %}
                    {% set x_val = nozzle_pos[0] + size_x if size_x != 0 else nozzle_pos[0] %}
                    {% set y_val = nozzle_pos[1] + size_x + i | round(1) if size_x != 0 else nozzle_pos[0] + size_y | round(1) %}
                {% else %} # If opposite_side = true 
                    {% set x_val = nozzle_pos[0] - size_x if size_x != 0 else nozzle_pos[0] %}%}
                    {% set y_val = nozzle_pos[1] - size_x - i | round(1) if size_x != 0 else nozzle_pos[0] - size_y | round(1) %}
                {% endif %}
            {% endif %}
            {% set z_val = ns.nozzle_pos[2] if nozzle_pos[2] != 0 else printer.toolhead.position.z %} 
            {% set r_val = 0 %}
            {% set f_val = ns.nozzle_pos[6] %}
            {% set nozzle_pos = [x_val, y_val, z_val, i_val, j_val, r_val, f_val] %}
            {% set _ = tmp_points.append(nozzle_pos) %}
            # Generate 2nd point
            {% if not adjacent_side %}
                {% if not opposite_side %}
                    {% set x_val2 = start_pos[0] + (step * cos_angle) + i | round(1) if size_y != 0 else start_pos[0] %}
                    {% set y_val2 = start_pos[1] if angle != 0 else start_pos[1] + step + i %}
                {% else %} 
                    {% set x_val2 = start_pos[0] - (step * cos_angle) - i | round(1) if size_y != 0 else start_pos[0] %}
                    {% set y_val2 = start_pos[1] if angle != 0 else start_pos[1] - step - i %}   
                {% endif %}
            {% else %} 
                {% if not opposite_side %}
                    {% set x_val2 = start_pos[0] if angle != 0 else start_pos[0] + step + i %}
                    {% set y_val2 = start_pos[1] + (step * sin_angle) + i | round(1) if size_x != 0 else start_pos[1] %}   
                {% else %} 
                    {% set x_val2 = start_pos[0] if angle != 0 else start_pos[0] - step - i %}
                    {% set y_val2 = start_pos[1] - (step * sin_angle) - i | round(1) if size_x != 0 else start_pos[1] %}      
                {% endif %}
            {% endif %}
            {% set nozzle_pos2 = [x_val2, y_val2, z_val, i_val, j_val, r_val, f_val] %}
            {% set _ = tmp_points.append(nozzle_pos2) %}
        {% endfor %}
    
        {% if reverse %}
            {% set nozzle_rev = tmp_points[:] %}
            {% set _ = nozzle_rev.reverse() %}
            {% set _ = tmp_points.extend(nozzle_rev) %}
        {% endif %}

        {% set z_val = (ns.nozzle_pos[2] - z_step) if ns.nozzle_pos[2] - z_step >= z_min else start_pos[2] %}
        {% set r_val = retract_during if printer.extruder.temperature >= temp else 0 %}
        {% set f_val = nozzle_pos[6] + speed_up + r %}
        {% set ns.nozzle_pos = [nozzle_pos[0], nozzle_pos[1], z_val, i_val, j_val, r_val, f_val] %}
        {% set _ = tmp_points.append(ns.nozzle_pos) %}        
        {% set _ = points.extend(tmp_points) %}
    {% endfor %}

{% elif pattern == 2 %}    
    
    {% set r_val = retract_before if printer.extruder.temperature >= temp else 0 %}

    # Calculate the diameter of the brush
    {% set diameter = (size_x, size_y) | min %}
    {% set radius = diameter / 2 %}
    {% set x_min, x_max = (x_min + radius) - step, (x_max - radius) + step %} 

    {% set i_val = radius if adjacent_side else 0 %}
    {% set j_val = 0 if adjacent_side else radius %}
    {% set f_val = speed %}

    # Calculate the number of steps in all directions 
    {% set long_points = (x_max - x_min) / step | round(1) if long_side == size_x else (y_max - y_min) / step | round(1) %}
    {% set short_points = (y_max - y_min) / step | round(1) if short_side == size_y else (x_max - x_min) / step | round(1) %}

    {% set ns = namespace() %}
    {% set ns.nozzle_pos = [x_min, y_min, z_max, i_val, j_val, r_val, f_val] if not opposite_side else [x_max, y_min, z_max, i_val, j_val, r_val, f_val] %}
    {% set nozzle_pos, start_pos = ns.nozzle_pos, ns.nozzle_pos %}
    {% set points = [] %}
    {% set _ = points.append(ns.nozzle_pos) %}

           
    {% for r in range(1 + repeat|int) %} 
        {% set tmp_points = [] %}
        {% for i in range(long_points|int) %}        
            {% if not opposite_side %} 
                {% set x_val = nozzle_pos[0] + step + i if not adjacent_side else nozzle_pos[0] %}
                {% set y_val = nozzle_pos[1] if not adjacent_side else nozzle_pos[0] + step + i %}
                {% set i_val = 0 if not adjacent_side else radius %}
                {% set j_val = radius if not adjacent_side else 0 %}
            {% else %} 
                {% set x_val = nozzle_pos[0] - step - i if not adjacent_side else nozzle_pos[0] %}
                {% set y_val = nozzle_pos[1] if not adjacent_side else nozzle_pos[0] - step - i %}
                {% set i_val = 0 if not adjacent_side else -radius %}
                {% set j_val = -radius if not adjacent_side else 0 %}
            {% endif %}  
            {% set z_val = ns.nozzle_pos[2] if nozzle_pos[2] != 0 else printer.toolhead.position.z %} 
            {% set r_val = 0 %}
            {% set f_val = nozzle_pos[6] %}
            {% set nozzle_pos = [x_val, y_val, z_val, i_val, j_val, r_val, f_val] %}
            {% set _ = tmp_points.append(nozzle_pos) %}
        {% endfor %}

        {% if reverse %}
            {% set nozzle_rev = tmp_points[:] %}
            {% set _ = nozzle_rev.reverse() %}
            {% set _ = tmp_points.extend(nozzle_rev) %}
        {% endif %}

        {% set z_val = (ns.nozzle_pos[2] - z_step) if ns.nozzle_pos[2] - z_step >= z_min else start_pos[2] %}
        {% set r_val = retract_during if printer.extruder.temperature >= temp else 0 %}
        {% set f_val = nozzle_pos[6] + speed_up + r %}
        {% set ns.nozzle_pos = [start_pos[0], start_pos[1], z_val, i_val, j_val, r_val, f_val] %}
        {% set _ = tmp_points.append(ns.nozzle_pos) %}        
        {% set _ = points.extend(tmp_points) %}
    {% endfor %}

    {% else %}
    { action_raise_error("Must choose either 1 or 2 for pattern") }
{% endif %}

    
{% if not cold_clean %}
    {% if auto_heat and printer.extruder.temperature < temp %}
        SET_HEATER_TEMPERATURE HEATER=extruder TARGET={temp + 1}
        TEMPERATURE_WAIT SENSOR=extruder MINIMUM={temp}
        # G1 E{retract_before}
    {% endif %}
{% endif %}

#if not homed and auto home is set to true then home the printer
{% if not 'xyz' in printer.toolhead.homed_axes and auto_home %}
    {% set homed = "false" %}
    G28    
    
{% elif not 'xyz' in printer.toolhead.homed_axes and not auto_home %}
    {% set homed = "false" %}
    { action_raise_error("Printer must be homed first!") }
{% elif 'xyz' in printer.toolhead.homed_axes %}
     {% set homed = "true" %}
{% endif %}

G90 # absolute coordinates
M83 # relative extrusion distance
G0 Z{z_hop}

{% if purge > 0 %}
    KOMB_purge
{% endif %}

# Move additional z amount if defined
G0 X{points[0][0]} Y{points[0][1]} F{travel_speed * 60}
G0 Z{points[0][2] - additional_z}

RESPOND msg={retract_before}
RESPOND msg={retract_after}
RESPOND msg={retract_speed}

{% if printer.extruder.temperature >= temp and retract_before != 0 %}
    RESPOND msg="Retract Before!"
    G1 E{retract_before * -1} F{retract_speed * 60}
{% endif %}

{% for point in points[1:] %}
    G1 X{point[0]} Y{point[1]} Z{point[2]} E{-point[5]} F{point[6] * 60}
    
    {% if pattern == 2 %}
        {% if opposite_side %}
            G3 I{point[3]} J{point[4]} 
        {% else %}
            G2 I{point[3]} J{point[4]} 
        {% endif %}
        
    {% endif %}
    
{% endfor %}

{% if printer.extruder.temperature >= temp and retract_after != 0 %}
    RESPOND msg="Retract After!"
    G1 E{retract_after * -1} F{retract_speed * 60}
{% endif %}

{% if return_to_start %}
    G0 Z{current_z + z_hop}
    G0 X{current_x} Y{current_y} F{travel_speed * 60}
    
{% endif %}

# move toolhead up clear of brush
G91
G0 Z{z_hop} {F450}
G90

RESTORE_GCODE_STATE NAME=clean_nozzle_state`

See Help with Macro: SET_GCODE_VARIABLE doesnt set my variable - #10 by theophile and following posts

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.