Newer
Older
jeltz-klipper-config / config / filament_sensors.cfg
@Cory Tucker Cory Tucker 6 days ago 13 KB fix #2, adding in some prototype idle code
# filament states:
# is_ready_to_print -
# load_state
# hotend_filament - the filament currently in the hotend. Set to the current loaded filament
# loaded_filament - the filament spool which is currently connected to the extruder. Modifiable when filament is
# heater_state - cold, heating, heated
#       if the heater state is 'heated' on printer boot,
#       and the current hotend and bed temperature is within 15c of the set temperature, then turn the heaters back on.

[filaments]
on_set_filament_gcode:
#   A list of G-Code commands to execute after the SET_FILAMENT macro runs. See
#   docs/Command_Templates.md for G-Code format. These parameters are passed
#   to the gcode:
#   * 'EXTRUDER' - the name of the extruder. 'extruder', 'extruder1' etc.
#   * 'T' - the integer index of the extruder
#   * 'PRESET' - the filament preset that was just assigned to th extruder
#   * 'LAST_PRESET' - the filament preset that was previously assigned to the extruder, if any
on_clear_filament_gcode:
#   A list of G-Code commands to execute after the CLEAR_FILAMENT macro runs. See
#   docs/Command_Templates.md for G-Code format. These parameters are pass to the gcode:
#   * 'EXTRUDER' - the name of the extruder. 'extruder', 'extruder1' etc.
#   * 'T' - the integer index of the extruder
#   * 'LAST_PRESET' - the filament preset that was previously assigned to the extruder, if any

[gcode_macro QUERY_FILAMENT]
description: Prompts the user to select a filament, and sets the value of filament_extruder to that filament
gcode:
  {% set response = params.RESPONSE|default(False) %}
  {% set name = params.NAME|default(False) %}
  {% set return_macro = params.RETURN_MACRO|default(False) %}
  
  {% if not response %}
    RESPOND TYPE=command MSG="action:prompt_begin Select Filament"
    {% for filament_name in printer.filaments.presets|map(attribute='name',default='None') %}
      RESPOND TYPE=command MSG="action:prompt_button {filament_name}|QUERY_FILAMENT {rawparams} NAME={filament_name} RESPONSE=True|primary"
    {% endfor %}
    RESPOND TYPE=command MSG="action:prompt_show"
  {% else %}
    # close the dialog
    RESPOND TYPE=command MSG="action:prompt_end"
    SET_EXTRUDER_FILAMENT NAME={name}
    # if we've specified a return macro, run this next.
    {% if return_macro %}
      {return_macro} 
    {% endif %}
  {% endif %}
    

[gcode_macro UNPRIME_FILAMENT]
description: Unprimes the filament, leaving it in a state where it can be unloaded without changing temperatures
gcode:
  {% set svv = printer.save_variables.variables %}
  {% set unload = params.UNLOAD|default(False) %}
  
  {% if svv.filament_load_state == "primed" %}
    # check if there is a valid value for the currently loaded filament. if not, prompt the user for it.
    {% if not svv.filament_extruder in printer.filaments.presets|map(attribute='name',default='yeet') %}
      # if there isn't a set loaded filament, run QUERY_FILAMENT
    {% else %}
      QUERY_FILAMENT RETURN_MACRO=LOAD_FILAMENT
      SET_FILAMENT_LOAD_STATE STATE="processing"
      
      # tell the end macro wether to call the unload macro after this
      SET_GCODE_VARIABLE MACRO=END_UNPRIME_FILAMENT VARIABLE=unload VALUE={unload}
      # If the extruder was cold, keep it cold after finishing.
      SET_GCODE_VARIABLE MACRO=END_UNPRIME_FILAMENT VARIABLE=etemp VALUE={printer['extruder'].target}
      
      # set temperature of extruder
      # if in auto mode, set temperature and wait. Otherwise wait for the set temperature if it it's above 25c.
      {% if svv.heater_mode == "auto" %}
        SET_TEMPERATURE_AND_WAIT HEATER=extruder TARGET={printer['extruder'].filament.extruder} MODE=auto
      {% elif printer['extruder'].target > 25 %}
        TEMPERATURE_WAIT SENSOR=extruder MINIMUM={printer['extruder'].target|float - 1} MAXIMUM={printer['extruder'].target|float + 2}
      {% endif %}
      
      # run the loop to retract until the switch is no longer pressed
      CLEAN_NOZZLE
      # mini purge to ensure filament remains connected
      _CLIENT_LINEAR_MOVE E=10 F={60*20}
      _CLIENT_LINEAR_MOVE E=-30 F={60*30}
      
      UPDATE_DELAYED_GCODE ID=LOOP_UNPRIME_FILAMENT DURATION=0.15
      # retract filament until the button is no longer pressed
    {% endif %}
  {% else %}
    {action_respond_info("unable to unprime filament. Current filament state: %s " %(svv.filament_load_state))}
  {% endif %}
  
[delayed_gcode LOOP_UNPRIME_FILAMENT]
# Retracts filament until the extruder_exit button is no longer pressed
gcode:
    {% if printer["gcode_button extruder_exit"].state == "PRESSED" %}
        G0 E-2 F{20*60}
        # retract by -2mm at 20mm/s (0.1s)
        UPDATE_DELAYED_GCODE ID=LOOP_UNPRIME_FILAMENT DURATION=0.15
        # really long wait here. Otherwise klipper gets angry and queues up moves or something.  
    {% else %}
        END_UNPRIME_FILAMENT
    {% endif %}

[gcode_macro END_UNPRIME_FILAMENT]
description: Called by LOOP_UNPRIME_FILAMENT, finishes up unpriming the filament.
variable_etemp = 0
variable_unload = False
gcode:
  # reload filament by an extra 10mm to press the button again
  G0 E10 F{40*60}

  M82 # absolute extruder moves

  # set temperature to what it was before
  SET_HEATER_TEMPERATURE HEATER='extruder' TARGET={etemp} MODE=auto

  # set filament state
  SET_FILAMENT_LOAD_STATE STATE="loaded"

  # if we want to unload after this, do so
  {% if unload %}
    UNLOAD_FILAMENT
  {% endif %}
  
[gcode_macro UNLOAD_FILAMENT]
description: Unloads the current filament
gcode:
  {% set svv = printer.save_variables.variables %}

  # check against current filament state
  {% if svv.filament_load_state == "loaded" %}

    # retract filament by 30mm
    M83 # relative extruder moves
    G0 E-30 F{40*60}
    M82 # absolute extruder moves
    SET_STEPPER_ENABLE STEPPER=extruder ENABLE=0
    SET_FILAMENT_LOAD_STATE STATE="unloaded_waiting"
    SET_EXTRUDER_FILAMENT NAME="None"

  {% elif svv.filament_load_state == "primed" %}
    UNPRIME_FILAMENT UNLOAD=True
  {% else %}
    {action_respond_info("unable to unload filament. Current filament state: %s " %(svv.filament_load_state))}
  {% endif %}

[gcode_macro LOAD_FILAMENT]
# loads filament after it has been detected in the entry sensor or manually triggered
gcode:
  {% set svv = printer.save_variables.variables %}
  {% set prompt = params.PROMPT|default(False) %}M84 E
  {% set prime = params.PRIME|default(False) %}
  
  # tell the end macro wether to call the prime macro after this
  SET_GCODE_VARIABLE MACRO=END_LOAD_FILAMENT VARIABLE=prime VALUE={prime}

  {% if not filament_state in ['unloaded'] %}
    # forward the filament name to the next macro
    SET_GCODE_VARIABLE MACRO=END_LOAD_FILAMENT VARIABLE=name VALUE="'{params.NAME}'"
    # we could set it here, but it avoids weird states if the macro fails for some reason.
  
    SET_FILAMENT_LOAD_STATE STATE="processing"
    M83 # relative extruder moves
    # load filament into extruder gear
    UPDATE_DELAYED_GCODE ID=LOOP_LOAD_FILAMENT DURATION=0.15
  {% else %}
    {action_respond_info("unable to load filament. Current filament state: %s " %(svv.filament_load_state))}
  {% endif %}

[delayed_gcode LOOP_LOAD_FILAMENT]
gcode:
  {% if printer["gcode_button extruder_exit"].state == "RELEASED" %}
      G0 E2 F{20*60}
      # Extrude by 2mm at 20mm/s (0.1s)
      UPDATE_DELAYED_GCODE ID=LOOP_LOAD_FILAMENT DURATION=0.15
      # really long wait here. Otherwise klipper gets angry and queues up moves or something. 
  {% else %}
    END_LOAD_FILAMENT
  {% endif %}


[gcode_macro END_LOAD_FILAMENT]
variable_prime = False
variable_name = None
gcode:
  {% set svv = printer.save_variables.variables %}
  M82 # absolute extruder moves
  # set loaded filament
  SET_FILAMENT_LOAD_STATE STATE="loaded"
  
  # check if there is a valid value for the currently loaded filament. if not, prompt the user for it.
  {% if not svv.filament_extruder in printer.filaments.presets|map(attribute='name',default='yeet') %}
    # if there isn't a set loaded filament, extrude a bit then run QUERY_FILAMENT
    G0 E4 F{20*60}
    QUERY_FILAMENT RETURN_MACRO=LOAD_FILAMENT
  {% endif %}

  {% if prime %}
    PRIME_FILAMENT
  {% endif %}



[gcode_macro PRIME_FILAMENT]
gcode:
  {% set svv = printer.save_variables.variables %}

  {% if svv.filament_load_state in ['unloaded', 'loaded', 'primed'] %}
  # check if there is a valid value for the currently loaded filament. if not, prompt the user for it.
    {% if not svv.filament_extruder in printer.filaments.presets|map(attribute='name',default='yeet') %}
      # if there isn't a set loaded filament, run QUERY_FILAMENT
      QUERY_FILAMENT RETURN_MACRO=PRIME_FILAMENT
      
    {% elif svv.filament_load_state in ['unloaded'] %}
      LOAD_FILAMENT PRIME=True
    {% elif svv.filament_load_state in ['loaded', 'primed'] %}
      # ensure that the filament in the hotend is the same as the filament in the extruder
      {% if svv.filament_extruder == svv.filament_hotend %}
        # wait for temperature to be set
        SET_HOTEND_TO_FILAMENT WAIT=True
        # move to purge bucket
        # z hop slightly
        _CLIENT_LINEAR_MOVE Z=5 F={60*30}
        # move to correct xy position
        _CLIENT_LINEAR_MOVE Y=258 X=230 F={60*500} ABSOLUTE=1
        # z down
        _CLIENT_LINEAR_MOVE Z=-1.5 F={60*30} ABSOLUTE=1

        {% if svv.filament_load_state in ['loaded'] %}
          _CLIENT_LINEAR_MOVE E=25 F={60*20}
        {% endif %}
        _CLIENT_LINEAR_MOVE E=10 F={60*10}
        _CLIENT_LINEAR_MOVE E=-2 F={60*10}
  
        CLEAN_NOZZLE
        
        SET_FILAMENT_LOAD_STATE STATE=primed
      {% else %}
        {action_respond_info("unable to prime filament. Filament in hotend doesn't match current filament")}
      {% endif %}
    {% endif %}
  {% else %}
    {action_respond_info("unable to prime filament. Current filament state: %s " % (svv.filament_load_state))}
  {% endif %}
  
[gcode_macro PURGE_FILAMENT]
gcode:
  {% set svv = printer.save_variables.variables %}

  {% if not svv.filament_extruder in printer.filaments.presets|map(attribute='name',default='yeet') %}
    # if there isn't a set loaded filament, run QUERY_FILAMENT
    QUERY_FILAMENT RETURN_MACRO=PURGE_FILAMENT
    
  {% elif svv.filament_load_state in ["loaded", "primed"] %}
    # if the filament is loaded or primed, then continue
    SET_HOTEND_TO_FILAMENT WAIT=True POSITION=both
    # move to purge bucket
    
    # z hop slightly
    _CLIENT_LINEAR_MOVE Z=5 F={60*30}
    # move to correct xy position
    _CLIENT_LINEAR_MOVE Y=258 X=230 F={60*500} ABSOLUTE=1
    # z down
    _CLIENT_LINEAR_MOVE Z=-1.5 F={60*30} ABSOLUTE=1
    
    _CLIENT_LINEAR_MOVE E=25 F={60*20}
    _CLIENT_LINEAR_MOVE E=50 F={60*10}
    _CLIENT_LINEAR_MOVE E=-2 F={60*10}

    CLEAN_NOZZLE
    
    SET_FILAMENT_LOAD_STATE STATE=primed
    SET_HOTEND_FILAMENT NAME=svv.filament_extruder
    SET_FILAMENT_LOAD_STATE STATE=primed
  {% else %}
    {action_respond_info("unable to purge filament. Current filament state: %s " %(svv.filament_load_state))}
  {% endif %}

  
[gcode_macro CLEAN_NOZZLE]
# for now assumes no print on the bed
gcode:
  # z hop slightly
  _CLIENT_LINEAR_MOVE Z=5 F={60*30}
  # move to correct xy position
  _CLIENT_LINEAR_MOVE Y=258 X=230 F={60*500} ABSOLUTE=1
  # z down
  _CLIENT_LINEAR_MOVE Z=-1.5 F={60*30} ABSOLUTE=1

  # wipe a few times
  {% for x in range(2) %}
    _CLIENT_LINEAR_MOVE X=-55 F={60*700} 
    _CLIENT_LINEAR_MOVE X=55 F={60*700}
  {% endfor %}
  
  # set z up again
  _CLIENT_LINEAR_MOVE Z=10 F={60*30} ABSOLUTE=1
  
[gcode_button bowden_sensor]
pin: PF2
press_gcode:
    {% set svv = printer.save_variables.variables %}
    { action_respond_info("bowden_load") } #DEBUG
    
    # TODO - USER LOAD FILAMENT. Setup some sort of response? Maybe wake printer from sleep mode and turn on lights?
    # can't switch back frgom near runout as the extruder can't grab further filament

release_gcode:
    {% set svv = printer.save_variables.variables %}
    {% if svv.filament_load_state in ['primed', 'loaded'] %}
        {action_raise_error("Warning: bowden sensor released, nearing filament runout")}
        # disable the encoder sensor

        # TODO IMPLEMENT MORE WARNINGS.
    {% elif svv.filament_load_state != 'unloaded' %}
        {action_raise_error("Warning: bowden sensor released during nonsensical filament state.")}
    {% endif %}

[filament_motion_sensor bowden_encoder_sensor]
detection_length: 10
extruder: extruder
switch_pin: ^PF3
pause_on_runout: False
insert_gcode:
runout_gcode:
  # if the printer is both printing, and the bowden sensor is pressed, then pause print.
  {% if (printer["gcode_button bowden_sensor"].state == "PRESSED") and
  printer['print_stats'].state == "printing" %}
    PAUSE
  {% endif %}
  # check if the bowden sensor is pressed
  
  
[gcode_button extruder_entry]
pin: printHead:PB7
press_gcode:
 {% set svv = printer.save_variables.variables %}
 
 { action_respond_info("extruder_entry_insert") }
 
 {% if svv.filament_load_state == 'unloaded' %}
    LOAD_FILAMENT
 {% endif %}

release_gcode:
 { action_respond_info("extruder_entry_release") }
 {% set svv = printer.save_variables.variables %}
 {% if svv.filament_load_state == 'loaded' %}
      {action_raise_error("Warning: extruder entry sensor released, filament runout")}
      SET_FILAMENT_LOAD_STATE STATE="runout"
      {% if svv.printer_state == 'printing'%}
        PAUSE
      {% endif %}
      # TODO IMPLEMENT MORE WARNINGS.
  {% elif svv.filament_load_state == 'unloaded_waiting' %}
      SET_FILAMENT_LOAD_STATE STATE="unloaded"
  {% elif svv.filament_load_state != 'unloaded' %}
      {action_raise_error("Warning: bowden sensor released during nonsensical filament state.")}
  {% endif %}

[gcode_button extruder_exit]
pin: printHead:PB5

press_gcode:
  {% set svv = printer.save_variables.variables %}
# not much here, this is handled by repeatedly checking the state in the filamet unload macro
  { action_respond_info("extruder_exit_insert") }

release_gcode:
  {% set svv = printer.save_variables.variables %}
  { action_respond_info("extruder_exit_runout") }
  { action_respond_info(svv.filament_load_state|string) }