viesturz / klipper-toolchanger

Toolcahnging extension for Klipper
GNU General Public License v3.0
49 stars 16 forks source link

Add an unretract property to tools #2

Closed fiferboy closed 7 months ago

fiferboy commented 8 months ago

I wanted a way to retract before parking but then to extruder after the active extruder was changed but before any of the pickup moves were performed. This allows me to have a nozzle wiper in the pickup path to knock any loose filament off the nozzle before continuing travel to the print.

This tunable method allows me to be ready to extrude on the wipe tower but without a large blob forming from over-extrusion that eventually knocks the wipe tower over.

viesturz commented 8 months ago

Thanks, a few thoughts:

All the tool change states are a bit complicated, let me add a diagram on what happens when.

fiferboy commented 8 months ago

A diagram would be helpful. I tried putting an extrude in the toolchanger.after_change_gcode but it seemed to do the extrude after movng the toolhead back to the purge tower, and when I put it in new_tool.pickup_gcode it appeared to overwrite the pickup_gcode from the toolchanger and didn't perform the pickup moves.

Putting it in the slicer only allows a before toolchange insertion as far as I'm aware and I want to be able to retract before the docking moves (which can be done in toolchanger.dropoff_gcode) and then extrude before the pickup moves. This was the most convenient way I could think to achieve that but I'm completely open to other solutions.

viesturz commented 8 months ago

Assuming this gets merged, it makes sense to add both retract and unretract.

And there is a hole plethora of ooze prevention tweaks, like idle temps, wipe moves.

I see two directions here - just adding to pikcup_gcode, or a new prime_nozzle_gcode which is called when:

viesturz commented 8 months ago

Saw your reply. Maybe try this:

I generally prefer adding more structure to the tool changer than creating a maze of macros, so let's keep going with the idea.

fiferboy commented 8 months ago

I like the idea of a prime_nozzle_gcode - I was going to look at something similar but I went for the minimum change at this point. I can take a crack at refactoring this into a new gcode section it you want.

I'll give your latest comment a try first. I was attempting it with hardcoded G1 E20 in toolchanger.pickup_gcode before, so I'm not sure it is going to work. Just to be clear, toolchanger.pickup_gcode is executed after the active extruder is switched, right? I just realized it isn't in the "The selection sequence is as follows:" section of the markdown for toolchanger.md

fiferboy commented 8 months ago

This method worked! I think we can close this pull request as unneeded. For the record, here are my relevant config sections for this functionality:

[tool T0]
tool_number: 0
extruder: extruder
fan: multi_fan T0_partfan
gcode_x_offset: 0
gcode_y_offset: 0
gcode_z_offset: 0
params_retract_amount: 20.0
params_unretract_amount: 6.5
params_park_x: 322.5
params_park_y: -1.5
params_park_z: 321.0
params_type: 'tripod_sc'

...

[tool T1]
tool_number: 1
extruder: extruder1
fan: multi_fan T1_partfan
gcode_x_offset: -0.068750
gcode_y_offset: 1.846875
#gcode_z_offset: -1.846250
gcode_z_offset: -1.000
params_retract_amount: 20.0
params_unretract_amount: 7.0
params_park_x: 25.0
params_park_y: -3.8
params_park_z: 320.0
params_type: 'tripod_sc'

...

  dropoff_gcode:
    {% set x = tool.params_park_x|float %} 
    {% set y = tool.params_park_y|float %} 
    {% set z = tool.params_park_z|float %} 
    {% set fast = tool.params_fast_speed|float %}
    {% set path = tool['params_' ~ tool.params_type ~ '_path'] %}
    {% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
    {% set cur_z = printer.toolhead.position[2]|float %}
    RESPOND TYPE=echo MSG='Dropping off {tool.name}'

    {% if printer[printer.toolhead.extruder].can_extrude and tool.params_retract_amount %}
      G1 E-{tool.params_retract_amount}
    {% endif %}

    G90
    ; Move 1 mm up to avoid crashing into things
    G0 Z{ [cur_z+1.0, max_z]|min } F{fast}    
    #   ##############  Move up to the dock  ##############    
    ROUNDED_G0 Y={tool.params_safe_y} D=20 F={fast}
    ROUNDED_G0 X={x} D=150 F={fast}
    ROUNDED_G0 Z={z + path[0]['z']|float} D=20 F={fast}
    ROUNDED_G0 Y={y + path[0]['y']|float} D=0 F={fast}
    STOP_TOOL_PROBE_CRASH_DETECTION
    #  ############## Run the path ##############
    {% for pos in path %}
        G0 Y{y + pos['y']|float} Z{z + pos['z']|float} F{tool.params_path_speed|float * (pos.get('f', 1.0)|float) }
    {% endfor %}

  pickup_gcode:
    {% set x = tool.params_park_x|float %} 
    {% set y = tool.params_park_y|float %} 
    {% set z = tool.params_park_z|float %} 
    {% set fast = tool.params_fast_speed|float %}
    {% set path = tool['params_' ~ tool.params_type ~ '_path'] %}
    RESPOND TYPE=echo MSG='Picking up {tool.name}'

    {% if printer[printer.toolhead.extruder].can_extrude and tool.params_unretract_amount %}
      G1 E{tool.params_unretract_amount}
    {% endif %}
    TIMELAPSE_TAKE_FRAME

    G90
    #   ##############  Fast to the last point  ##############
    ROUNDED_G0 Y={tool.params_close_y} F={fast} D=5
    ROUNDED_G0 X={x} Z={z + path[-1]['z']|float} F={fast} D=5
    ROUNDED_G0 Y={y + path[-1]['y']|float} F={fast} D=0
    # Wait for temp before actually picking up the tool, while the nozzle is resting on it's pad.

    {% if tool.extruder %}
      M109 T{tool.tool_number} S{printer[tool.extruder].target|int}
    {% endif %}
    # Run the path in reverse
    {% for pos in path|reverse %}
      G0 Y{y + pos['y']|float} Z{z + pos['z']|float} F{tool.params_path_speed|float * (pos.get('f', 1.0)|float) }      
      {% if 'f' in pos %} # Use the f presence as marker that we have made contact with the tool.
        START_TOOL_PROBE_CRASH_DETECTION T={tool.tool_number}
      {% endif %}
    {% endfor %}
    # Restore the position with smooth rounded move.
    ROUNDED_G0 Y={tool.params_safe_y} F={fast} D=20
    {% if 'Z' in restore_position %}
      ROUNDED_G0 Z={restore_position.Z} F={fast} D=150
    {% endif %}
    {% if 'X' in restore_position %}
      ROUNDED_G0 X={restore_position.X} F={fast} D=1000
    {% endif %}
    {% if 'Y' in restore_position %}
      ROUNDED_G0 Y={restore_position.Y} F={fast} D=0
    {% endif %}
    ROUNDED_G0 D=0