Gcode_button and logic

Basic Information:

Printer Model: Ender 5
MCU / Printerboard: SKR mini E3
klippy.log

As per previous posts, I am trying to build a MMU. With 5 extruder steppers and a bunch of switches to detect filament position. The coding/scripting proving to be much more difficult than anticipated.

I would like to use a Gcode button to monitor a switch and then use one of the extruder motors to push or retract filament to change the switch state and stop when it has.

I’ve recently started to get to grips with how klipper evaluates macros and I’m now starting to think that it might not be possible without advanced programming skills.

My current understanding is thus:

If I were to call a macro it has access to variable values at the time the macro is called. It cannot see any changes to the variables that exist outside of the macros being evaluated until it is called again.

I have a horrible feeling that if I call another macro from within the original macro. It for the most part has access to the same variable values that the original macro has. Thus I won’t be able change behaviour

Is my understanding correct? Any ideas how I could overcome it?

All I want to do I think is:

-Move filament 10mm
-check button variable
-move filament 10mm
-check button variable
… And so on until the variable changes

Thanks

Dan

An implementation like this might be helpful: Trying to implement a loop using delayed gcode

Unfortunately they weren’t successful in their efforts and pretty much confirms my suspicions that the entire macro chain is evaluated when the first macro is called.

I think I can still make my MMU work by using filament switches as the macro essential calls itself. Although I won’t be able to do anything clever when loading/unloading filament. It will just have to be loading/unloading set amount of filament and at the end of the macro when It returns to normal G code running. It will trigger a pause if something has gone wrong.

I would have liked to have tried loading filament again etc.

Looking at it, I would have to write a python script with the functions I want and call those functions using Jinga. Ive realised I was pretty naive about all this at the start of the project.

Is there any documentation on how you achieve and how that links back into the printer.cfg file. For some bed time reading?

In another thread I see you have implemented a MMU much like I want to.

How did you go about doing it? Is it much like I have described above?

I will be using 5 extruders. Basically your classic creality style duel driven roller extruders. I was planning on having a servo driven cam shaft that drives a dowel down on the extruder lever. So that once the filament is loaded and in the gears of the tool head extruder it can then freewheel essentially? Do you think that this is required? I am concerned about tension building up in the Bowden if I do not implement a free wheel system.

I have 6 stepper motors, each configured in a typical bowden setup, except these 6 “feeders” all feed into a 6-in-1-out “splitter,” which feeds into a direct-drive setup at the hotend. Each of the feeders is a Klipper “extruder stepper” and the direct-drive extruder is the “extruder.” Before starting a print I manually load the filament spools I want to use so that the tip of each filament is just to the mouth of the splitter (what I’ll call the “rest position”).

I’ve got custom load and unload macros that sync the appropriate extruder_stepper to the extruder motion queue and then either extrude or retract the filament the specific distance I measured between the rest position and the nozzle side of the heatbreak. (The unload does some tip-shaping moves first.)

While printing, both the “feeder” stepper and the direct-drive stepper are operating on the filament at the same time. This is actually a great setup because I can significantly reduce the tension on both extruders and reduce the run current (thereby letting the motors run cooler), as they’re both working together. This has eliminated the problems I used to have with the spur gears “biting” into the filament or rolling it into an oval shape with frequent retractions, while at the same time eliminating skipped steps and under extrusion.

My setup does not have any type of filament homing or detection. I just manually load each spool so that the tip of the filament is in the “rest area,” and as long as I use the load and unload filament macros, the filament tips are always returned to the rest area and ready to go the next time that filament is called for. I’ve been running this setup for more than 4 years now and haven’t had any problems that filament sensors or homing would have helped.

Thank you for sharing that, I will probably give the freewheeling camshaft a rain check. Gives me confidence to proceed. I have been hovering on buying/building ercf. But they seem to be very sensitive to filament friction which put me off.

Would you mind sharing your macros it would undoubtedly save me a lot of time

Thanks

Dan

Sorry for the delay, but the reason it’s taken me so long is that my macros are an unholy mess not fit for public consumption, mainly because they include a bunch of bells and whistles that are mostly specific to my setup. I’ll paste some of them below with this important caveat:

DO NOT USE THESE MACROS AS-IS! They will NOT work!

If you’re comfortable in Python and Jinja2, you should be able to read through them and see generally what the logic flow is, and maybe there are some aspects you can borrow from that would be helpful. And I’m happy to answer any questions you might have about them.

[gcode_macro GLOBALS]
variable_active_slot:None
variable_bowden_length:490
variable_hotend_length:80
variable_park_x_pos:249
variable_park_y_pos:120
variable_cooling_amount:0
variable_ramming_distance:9.5
variable_ramming_speed:2000
variable_pressure_advance:0.03
variable_display_group:"_default_16x4"
variable_filament_id:None
variable_filament_temp:None
variable_filament_type:None
variable_filament_color_hex:None
variable_nozzle_prime_distance:15
variable_retract_length:0.6
variable_z_hop:0.4
variable_tip_shape_distance:26
variable_secondary_purge_volume:0
variable_lightness_factor:0.05
variable_lightening_factor:0.05
variable_euclidean_factor:0.05
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}

[gcode_macro FILAMENT_LOAD]
gcode:
    {% set last_filament = printer.save_variables.variables %}
    {% set filament_db = last_filament.filament_db %}
    {% set globals = printer["gcode_macro GLOBALS"] %}
    ; Don't pass EXTRUDER_STEPPER if calling this from another macro!
    M400
    {% if params.EXTRUDER_STEPPER %}
        {% if printer["gcode_macro SYNC_EXTRUDER_MOTION"].stepper_synced is not none %}
            { action_raise_error('An EXTRUDER_STEPPER is already synced.') }
        {% else %}
            SYNC_EXTRUDER_MOTION EXTRUDER=extruder_stepper_{params.EXTRUDER_STEPPER|int} MOTION_QUEUE=extruder
            SMART_HOME
        {% endif %}
    {% else %}
        ; The calling macro should already have synced an extruder stepper.
        {% if printer["gcode_macro SYNC_EXTRUDER_MOTION"].stepper_synced is none %}
            { action_raise_error('This will not work without a synced EXTRUDER_STEPPER.') }
        {% endif %}
    {% endif %}
    {% if last_filament.filament_loaded %}
        { action_raise_error('Filament is already loaded!') }
    {% endif %}
    ; Don't pass PRINT_TEMP if calling this from another macro!
    {% if params.PRINT_TEMP %}
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_id VALUE='"Manually Loaded Filament"'
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_temp VALUE={params.PRINT_TEMP}
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_type VALUE=None
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_color_hex VALUE=None
    {% else %}
        {% if "globals.filament_id" not in filament_db %}
            {% set db_values = {'temp': globals.filament_temp,
                               'type': globals.filament_type,
                               'color_hex': globals.filament_color_hex} %}
            {% set dummy = filament_db.__setitem__('%s'|format(globals.filament_id), db_values) %}
        {% else %}
            {% set dummy = filament_db[globals.filament_id].__setitem__('temp', '%s'|format(globals.filament_temp)) %}
            {% set dummy = filament_db[globals.filament_id].__setitem__('type', '%s'|format(globals.filament_type)) %}
            {% set dummy = filament_db[globals.filament_id].__setitem__('color_hex', '%s'|format(globals.filament_color_hex)) %}
        {% endif %}
        SAVE_VARIABLE VARIABLE=filament_db VALUE="{filament_db | pprint | replace("\n", "") | replace("\"", "\\\"")}"
    {% endif %}
    {% set print_temp = params.PRINT_TEMP|default(globals.filament_temp) %}
    {% if print_temp is none %}
        { action_raise_error('New filament temperature must be specified.') }
    {% endif %}
    {% set purge_temp = [last_filament.filament_temp, print_temp]|max %}
    M104 S{purge_temp}; Heat up hotend
    G91; Relative Coordinates
    G1 E25 F400; Medium insert
    G1 E25 F600
    G1 E25 F800
    G1 E{(globals.bowden_length) - 75 } F10000
    G1 E{(globals.hotend_length)} F10000
    SAVE_VARIABLE VARIABLE=filament_loaded VALUE=True
    SET_ACTIVE_SPOOL
    {% if not params.SKIP_PURGE %}
        {% set model_purge = params.MODEL_PURGE|default(0)|float %}
        M109 S{purge_temp}                              ; Heat up hotend and wait
        {% if not printer["gcode_macro SECONDARY_PURGE_TUNER"].tower_is_running %}
            _CALCULATE_SECONDARY_PURGE                  ; Calculate secondary purge
        {% endif %}
        M106 S256                                       ; Turn on fan (Comment out this line to make purge pellets)
        G1 E{globals.nozzle_prime_distance/2} F70       ; Prime nozzle at purge temp
        M104 S{print_temp}                              ; Start transitioning to print temp
        _PERFORM_SECONDARY_PURGE PRINT_TEMP={print_temp}
        M107 ;Cut the fan
        M400
        M109 S{print_temp}
        M106 S256
        {% if params.FIRST_LOAD %}
            G90; Absolute Coordinates
            G1 Z0 F420
            G91; Relative Coordinates
        {% endif %}
        G1 E{globals.nozzle_prime_distance/2} F50; purge more
    {% endif %}
    STORE_FILAMENT_DATA
    {% if not params.FIRST_LOAD %}
        M106 S{ printer.fan.speed * 510}
    {% else %}
        M107 ;Cut the fan
    {% endif %}
    WIPE_NOZZLE
    M400
    G92 E0; Zero Extruder
    # Dummy argument block for Mainsail
    {% set dummy = None if True else "
    {% set dummy = params.PRINT_TEMP|default(None)|float %}
    {% set dummy = params.EXTRUDER_STEPPER|default(None) %}
    {% set dummy = params.SKIP_PURGE|default(True)|bool %}
    {% set dummy = params.FIRST_LOAD|default(False)|bool %}
    " %} # End argument block for Mainsail

[gcode_macro FILAMENT_UNLOAD]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% set last_filament = printer.save_variables.variables %}
    G91; Relative Coordinates
    G92 E0; Zero Extruder
    {% if (printer.print_stats.state not in ['printing', 'paused']) and last_filament.filament_loaded %}
        {% if (printer["gcode_macro SET_PSU"].value)|int == 0 %}
            SET_PSU VALUE=1
        {% endif %}
        M104 S{last_filament.filament_temp}
        SMART_HOME
        PARK_TOOLHEAD
        M109 S{last_filament.filament_temp}
        SYNC_EXTRUDER_MOTION EXTRUDER={last_filament.last_synced_extruder} MOTION_QUEUE=extruder
        G1 E10 F70
    {% else %}
        G1 E-{globals.retract_length} F1500; Retract
        PARK_TOOLHEAD
    {% endif %}
    G1 E{globals.ramming_distance + globals.retract_length} F{globals.ramming_speed}
    G1 E-{globals.ramming_distance} F3000
    G1 E{globals.retract_length - globals.tip_shape_distance } F3000
    G1 E12 F200
    G1 E-12 F200
    G1 E12 F255
    G1 E-12 F255
    G1 E{globals.tip_shape_distance} F2000 ;move stringy tip into melt zone
    G1 E-{globals.tip_shape_distance} F4000 ;extract clean tip from melt zone
    M400
    CLEAR_ACTIVE_SPOOL
    G1 E-{globals.hotend_length + globals.bowden_length - globals.tip_shape_distance} F4000
    M400
    SAVE_VARIABLE VARIABLE=filament_loaded VALUE=False
    DESYNC_EXTRUDER_STEPPERS

[gcode_macro _CALCULATE_SECONDARY_PURGE]
variable_model_purge:0
gcode:
    {% set last_filament = printer.save_variables.variables %}
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% if globals.filament_id == last_filament.filament_id %}
        { action_respond_info('Same filament detected. Skipping secondary purge...') }
        {% set purge = 0 %}
    {% elif last_filament.filament_color_hex is none %}
        { action_respond_info('Last filament has unknown color. Enforcing minimum 10mm secondary purge...') }
        {% set purge = 10 %}
    {% else %}
        {% set color1_hex = last_filament.filament_color_hex %}
        {% set color2_hex = globals.filament_color_hex %}
        {% set c1 = [] %}
        {% set c2 = [] %}
        {% for i in range(0,6,2) %}
            {% set dummy = c1.append(color1_hex[i:i+2]|int(base=16)) %}
            {% set dummy = c2.append(color2_hex[i:i+2]|int(base=16)) %}
        {% endfor %}
        {% set lightnessX = globals.lightness_factor %}
        {% if not lightnessX %}
            # Calculate Euclidean distance
            {% set sums = [] %}
            {% for n in range(3) %}
                {% set dummy = sums.append((c2[n] - c1[n])**2) %}
            {% endfor %}
            {% set euclidean_raw = (sums|sum())**(1/2) %}
            # Calculate Euclidean distance multiplier
            {% set lightnessX = (euclidean_raw/442)*globals.euclidean_factor %}
        {% endif %}
        {% set lighteningX = globals.lightening_factor %}
        # Purge = Base + ((C2[R]+C2[G]+C2[B]) * euclideanX) + ((C2[R]-C1[R]),0)|max)+((C2[G]-C1[G]),0)|max)+((C2[B]-C1[B]),0)|max)) * lighteningX
        {% set purge = ((c2|sum) * lightnessX) + ((((c2[0]-c1[0]),0)|max) + (((c2[1]-c1[1]),0)|max) + (((c2[2]-c1[2]),0)|max)) * lighteningX %}
        {% set model_purge = printer["gcode_macro _CALCULATE_SECONDARY_PURGE"].model_purge %}
        {% if model_purge > 0 %}
            {% set purge = [(purge - model_purge), 0]|max %}
            { action_respond_info('%smm will be purged into model. Pre-adjusting secondary purge to %smm.'|format(model_purge, purge))}
        {% endif %}
        COLOR_LOG PURGE={purge}
        {% if globals.filament_type != last_filament.filament_type %}
            { action_respond_info('Different filament type detected. Enforcing minimum 10mm secondary purge...') }
            {% set purge = (purge,10)|max %}
        {% endif %}
    {% endif %}
    { action_respond_info('Purge volume calculated with lightening factor of %s and lightness factor of %s.'|format(lighteningX, lightnessX))}
    { action_respond_info('Setting final secondary purge volume to %smm...'|format(purge))}
    SET_GCODE_VARIABLE MACRO=_PERFORM_SECONDARY_PURGE VARIABLE=secondary_purge_volume VALUE={purge}

[gcode_macro _PERFORM_SECONDARY_PURGE]
variable_secondary_purge_volume:0
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% set secondary_purge_volume = printer["gcode_macro _PERFORM_SECONDARY_PURGE"].secondary_purge_volume %}
    {% if secondary_purge_volume > 0 %}
        G1 E{secondary_purge_volume/2} F70  ; Do half of secondary purge during temp transition
        M109 S{params.PRINT_TEMP}           ; Stabilize at print temperature
        G1 E{secondary_purge_volume/2} F70  ; Do the other half of secondary purge
        {% if not printer["gcode_macro SECONDARY_PURGE_TUNER"].tower_is_running %}
            SET_GCODE_VARIABLE MACRO=_PERFORM_SECONDARY_PURGE VARIABLE=secondary_purge_volume VALUE=0
        {% endif %}
    {% endif %}

[gcode_macro PARK_TOOLHEAD]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    { action_respond_info('Parking print head...') }
    G90; Absolute Coordinates
    G1 X{globals.park_x_pos} F9000 ; Move to bucket
    {% if not printer.gcode_move.absolute_coordinates %}
        G91; Relative Coordinates
    {% endif %}

[gcode_macro FILAMENT_CHANGE]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% set spool_registry = printer.save_variables.variables.spool_registry %}     
    {% set x_pos = params.NEXT_X|default(printer.toolhead.position.x)|float %}
    {% set y_pos = params.NEXT_Y|default(printer.toolhead.position.y)|float %}
    {% set z_pos = params.NEXT_Z|default(printer.toolhead.position.z)|float %}
    M400
    M107; Cut the fan
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_id VALUE='"{params.FILAMENT_ID}"'
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_temp VALUE={params.NEXT_EXTRUDER_TEMP}
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_type VALUE='"{params.FILAMENT_TYPE}"'
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_color_hex VALUE='"{params.FILAMENT_COLOR_HEX}"'
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=retract_length VALUE={params.RETRACT_LENGTH}
    SET_GCODE_VARIABLE MACRO=_CALCULATE_SECONDARY_PURGE VARIABLE=model_purge VALUE={params.MODEL_PURGE|default(0)|float}
    FILAMENT_UNLOAD
    M400
    {% for slot in spool_registry %}
        {% if spool_registry[slot]['name'] == params.FILAMENT_ID %}
            SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=active_slot VALUE={slot|int}
        {% endif %}
    {% endfor %}
    SELECT_EXTRUDER
    RESTORE_DEFAULT_PA
    G91; Relative Coordinates
    G1 Z{globals.z_hop} F18000
    FILAMENT_LOAD
    G91; Relative Coordinates
    G1 E-{globals.retract_length} F1500 ;Retract
    G90; Absolute Coordinates
    G1 X{x_pos} Y{y_pos} Z{z_pos + globals.z_hop} F18000

[gcode_macro _CLEAR_FILAMENT_GLOBALS]
gcode:
    { action_respond_info('Clearing filament globals...') }
    {% for param in ['id', 'temp', 'type', 'color_hex'] %}
        SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=filament_{param} VALUE=None
    {% endfor %}

[gcode_macro STORE_FILAMENT_DATA]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    { action_respond_info('Saving filament properties to disk...') }
    {% if globals.filament_id is none %}
        SAVE_VARIABLE VARIABLE=filament_id VALUE=None
    {% else %}
        SAVE_VARIABLE VARIABLE=filament_id VALUE='"{globals.filament_id}"'
    {% endif %}
    {% if globals.filament_type is none %}
        SAVE_VARIABLE VARIABLE=filament_type VALUE=None
    {% else %}
        SAVE_VARIABLE VARIABLE=filament_type VALUE='"{globals.filament_type}"'
    {% endif %}
    {% if globals.filament_color_hex is none %}
        SAVE_VARIABLE VARIABLE=filament_color_hex VALUE=None
    {% else %}
        SAVE_VARIABLE VARIABLE=filament_color_hex VALUE='"{globals.filament_color_hex}"'
    {% endif %}
    SAVE_VARIABLE VARIABLE=filament_temp VALUE={globals.filament_temp}
    SAVE_VARIABLE VARIABLE=last_synced_extruder VALUE='"{printer["gcode_macro SYNC_EXTRUDER_MOTION"].stepper_synced}"'
    _CLEAR_FILAMENT_GLOBALS

[gcode_macro PRINT_END]
gcode:
    M106 S0 ; turn off cooling fan
    M140 S0 ; turn off bed
    FILAMENT_UNLOAD
    WIPE_NOZZLE
    M220 S100 ;Reset speed override to 100%
    M221 S100 ;Reset extrusion factor override to 100%
    M104 S0 ; turn off extruder
    G90
    G1 Y200; Remove Print Position
    M84 ; disable motors
    DESYNC_EXTRUDER_STEPPERS
    SET_SKEW CLEAR=1
    SET_GCODE_VARIABLE MACRO=SECONDARY_PURGE_TUNER VARIABLE=tower_is_running VALUE=False

[gcode_macro WIPE_NOZZLE]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    G90; Absolute Coordinates
    G1 X{globals.park_x_pos}
    G91; Relative Coordinates
    M106 S256
    G4 P1000
    G1 X-15 F10000
    G4 P1000
    G1 X15 F10000
    G1 X-15 F10000
    G1 X15 F10000
    M106 S{ printer.fan.speed * 510}
    {% if printer.gcode_move.absolute_coordinates %}
        G90; Absolute Coordinates
    {% else %}
        G91; Relative Coordinates
    {% endif %}

[gcode_macro RESTORE_DEFAULT_PA]
gcode:
    SET_PRESSURE_ADVANCE ADVANCE={(printer["gcode_macro GLOBALS"].pressure_advance)}

[gcode_macro SYNC_EXTRUDER_MOTION]
rename_existing: BASE_SYNC_EXTRUDER_MOTION
variable_stepper_synced: None
gcode:
    {% if params.MOTION_QUEUE == '' %}
        SET_GCODE_VARIABLE MACRO=SYNC_EXTRUDER_MOTION VARIABLE=stepper_synced VALUE=None
    {% else %}
        SET_GCODE_VARIABLE MACRO=SYNC_EXTRUDER_MOTION VARIABLE=stepper_synced VALUE='"{params.EXTRUDER}"'
    {% endif %}
    BASE_SYNC_EXTRUDER_MOTION {rawparams}

[gcode_macro SELECT_EXTRUDER]
gcode:
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% if globals.active_slot is none %}
        { action_raise_error('Cannot activate extruder without an active slot.') }
    {% endif %}
    {% set slot = (globals.active_slot|int - 1) %}
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder_stepper_{slot} MOTION_QUEUE=extruder    
    M400
    SET_PRESSURE_ADVANCE ADVANCE={globals.pressure_advance}
    SET_PRESSURE_ADVANCE EXTRUDER=extruder_stepper_{slot} ADVANCE={globals.pressure_advance}

[gcode_macro DESYNC_EXTRUDER_STEPPERS]
gcode:
    SET_GCODE_VARIABLE MACRO=GLOBALS VARIABLE=active_slot VALUE=None
    {% for n in range(6) %}
        SYNC_EXTRUDER_MOTION EXTRUDER=extruder_stepper_{n} MOTION_QUEUE=
    {% endfor %}

[gcode_macro _CHECK_FOR_REQUESTED_FILAMENT]
gcode:
    {% set name = params.NAME %}
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% set spool_registry = printer.save_variables.variables.spool_registry %}
    {% set filament_list = [] %}
    {% for slot in spool_registry %}
        {% set dummy = filament_list.append(spool_registry[slot]['name']) %}
    {% endfor %}
    {% if name in filament_list %}
        { action_respond_info('Requested filament "%s" found.'|format(name))}
    {% else %}
        { action_raise_error('Load "%s" filament in a spool slot and try again!'|format(name)) }
    {% endif %}

[gcode_macro SET_ACTIVE_SPOOL]
gcode:
    {% set spool_registry = printer.save_variables.variables.spool_registry %}
    {% set globals = printer["gcode_macro GLOBALS"] %}
    {% if globals.active_slot is not none %}
        {% set id = spool_registry["%s"|format(globals.active_slot)]['id'] %}
        {action_call_remote_method(
           "spoolman_set_active_spool",
           spool_id=id
        )}
    {% else %}
        {action_respond_info("No slot selected. Could not set active spool.")}
    {% endif %}

[gcode_macro CLEAR_ACTIVE_SPOOL]
gcode:
  {action_call_remote_method(
    "spoolman_set_active_spool",
    spool_id=None
  )}
1 Like

Thank you for coming back to me!

There is certainly some information to digest there. Would appear to be very thorough!

I have a filament cutter on my print head. So I’m hoping that the code I need will be much simpler.

I will definitely be referring to this when I get I to the nitty gritty of writing the macros.

I’m interested in how you implement that. When I first cobbled together my setup I was thinking of trying to include a filament cutter because I was having a really hard time forming the tips of retracted filament so as to prevent them from catching or jamming when trying to reload them later.

I eventually found the key was to start the retraction/cooling sequence by first forcing the filament quickly toward the nozzle and then quickly retracting it again to force out as much of the already softened plastic as possible without softening any more of it. This is reflected in the macros as the “ramming distance,” and I found 9.5mm to be a good value for this. That was at least 2 years ago and I haven’t had a single filament jam since then.

https://www.printables.com/model/713588-eva-24-combined-filament-sensor-and-filament-cutte

I altered an EVA2.4 official part.

I did most of it in tinkercad tbh, so no lovely cad drawings I’m afraid. But if you look at it in tinkercad (link supplied. You can see how I did it)

https://www.printables.com/model/713588-eva-24-combined-filament-sensor-and-filament-cutte

People have made them for Stealth Burner and EVA 3.0 if you happen to have any of those tool heads

It works by ramming into a mount on the frame if you catch my drift. So you don’t need a servo on the toolhead itself

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