Skip to content

Commit

Permalink
Support for N+1 exit led
Browse files Browse the repository at this point in the history
  • Loading branch information
moggieuk committed Nov 25, 2023
1 parent 9e44519 commit 022f744
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 49 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ Happy Hare has a built in help system to aid remembering the command set. It can
MMU_FORM_TIP : Convenience macro for calling the standalone tip forming functionality
MMU_HELP : Display the complete set of MMU commands and function
MMU_HOME : Home the MMU selector
MMU_LED : Manage mode of operation of optional MMU LED's
MMU_LOAD : Loads filament on current tool/gate or optionally loads just the extruder for bypass or recovery usage (EXTUDER_ONLY=1)
MMU_MOTORS_OFF : Turn off both MMU motors
MMU_PAUSE : Pause the current print and lock the MMU operations
Expand Down
42 changes: 21 additions & 21 deletions config/base/mmu_hardware.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -197,26 +197,30 @@ flowrate_samples: 20 # How many "movements" on the encoder to measure over for
#
# Define neopixel LEDs for your MMU. The chain_count should match or be greater than your number of gates.
# Requires the installation of Julian Schill's awesome LED effect module: https://github.com/julianschill/klipper-led_effect
# LED index 1..N should be connected from gate #0 to gate #N
# LED index N+1 can optionally be connected to exit from MMU (like encoder in ERCF design)
#
[neopixel mmu_leds]
pin: mmu:MMU_NEOPIXEL
chain_count: {mmu_num_gates}
chain_count: {mmu_num_leds} # Number gates + 1 (if you want exit effect)
color_order: GRBW # Set based on your particular neopixel specification

#
# Define LED effects for MMU. 'mmu_led_effect' is a wrapper for led_effect
# Define LED effects for MMU gate. 'mmu_led_effect' is a wrapper for led_effect
# (if included on your system) and will accept and create the defined effect on both
# the entire strip with the name you supply but also on each individual LED by addeding
# a `_<gate>` suffix. This makes it much easier to have per gate effects.
# the entire specified part of the strip with the name you supply but also on each
# individual LED up to N+1 gates by adding `_<gate+1>` suffix. This makes it much
# easier to have per gate effects.
#
# E.g. You define _mmu_flash on a 3 gate MMU:
# [mmu_led_effect _mmu_flash]
# E.g. You define mmu_flash on a 3 gate MMU:
# [mmu_led_effect mmu_flash]
#
# This will create effects:
# _mmu_flash on whole define strip
# _mmu_flash_1 on for gate 0
# _mmu_flash_2 on for gate 1
# _mmu_flash_3 on for gate 2
# mmu_flash on whole define strip
# mmu_flash_1 on for gate 0 (LED index 1)
# mmu_flash_2 on for gate 1 (LED index 2)
# mmu_flash_3 on for gate 2 (LED index 3)
# mmu_flash_4 for MMU exit (LED index 4)
#
# Then you can set effects with commands like:
# SET_LED_EFFECT EFFECT=_mmu_flash # apply effect to all leds in strip
Expand Down Expand Up @@ -244,35 +248,31 @@ layers: strobe 1 1.5 add (1.0, 1.0, 1.0)
breathing 2 0 difference (0.95, 0.0, 0.0)
static 0 0 top (1.0, 0.0, 0.0)

# None of the following are used on exit led, hence no range
[mmu_led_effect mmu_green]
frame_rate: 12
leds: neopixel:mmu_leds
leds: neopixel:mmu_leds (1-{mmu_num_gates})
layers: static 0 0 top (0.0, 0.5, 0.0)

[mmu_led_effect mmu_orange]
frame_rate: 12
leds: neopixel:mmu_leds
leds: neopixel:mmu_leds (1-{mmu_num_gates})
layers: static 0 0 top (0.5, 0.2, 0.0)

[mmu_led_effect mmu_black] # Needed because of STOP_LED_EFFECTS
frame_rate: 12
leds: neopixel:mmu_leds
layers: static 0 0 top (0.0, 0.0, 0.0)

# These are always on whole strip, hence just `led_effect`...
# These only on whole strip, hence just `led_effect`...
[led_effect mmu_curtain]
frame_rate: 24
leds: neopixel:mmu_leds
leds: neopixel:mmu_leds (1-{mmu_num_gates})
layers: comet 1 0.7 add (0.7, 0.7, 0.7),(0.7, 0.0, 0.0)
comet -1 0.7 top (0.7, 0.7, 0.7),(0.0, 0.0, 0.7)

[led_effect mmu_sparkle]
frame_rate: 24
leds: neopixel:mmu_leds
leds: neopixel:mmu_leds (1-{mmu_num_gates})
layers: twinkle 8 0.15 top (0.3, 0.3, 0.3), (0.4, 0.0, 0.25)

[led_effect mmu_pulsing_white_fast]
frame_rate: 24
leds: neopixel:mmu_leds
leds: neopixel:mmu_leds (1-{mmu_num_gates})
layers: breathing 0.6 0 top (0.5, 0.5, 0.5)

70 changes: 53 additions & 17 deletions config/base/mmu_software.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,15 @@ gcode:
{% set gate_color = printer['mmu']['gate_color'] %}

{% if ACTION == "Loading" %}
_MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate}
_MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate} EXIT_EFFECT=mmu_pulsing_white_slow
{% elif ACTION == "Unloading" %}
_MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate}
_MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate} EXIT_EFFECT=mmu_pulsing_white_slow
{% elif ACTION == "Heating" %}
_MMU_SET_LED EFFECT=mmu_breathing_red GATE={gate}
_MMU_SET_LED EFFECT=mmu_breathing_red GATE={gate} EXIT_EFFECT=mmu_breathing_red
{% elif ACTION == "Idle" %}
_MMU_SET_LED EFFECT=default
_MMU_SET_LED EFFECT=default EXIT_EFFECT=default
{% elif ACTION == "Selecting" %}
_MMU_SET_LED EFFECT=mmu_pulsing_white_fast FADETIME=0
_MMU_SET_LED EFFECT=mmu_pulsing_white_fast EXIT_EFFECT=off FADETIME=0
{% endif %}


Expand Down Expand Up @@ -387,15 +387,15 @@ gcode:
{% elif STATE == "pause_locked" %}
_MMU_SET_LED EFFECT=mmu_strobe
{% elif STATE == "paused" %}
_MMU_SET_LED EFFECT=mmu_strobe GATE={gate}
_MMU_SET_LED EFFECT=mmu_strobe GATE={gate} EXIT_EFFECT=mmu_strobe
{% elif STATE == "complete" %}
_MMU_SET_LED EFFECT=mmu_sparkle DURATION=20
{% elif STATE == "error" %}
_MMU_SET_LED EFFECT=mmu_strobe DURATION=20
{% elif STATE == "cancelled" %}
_MMU_SET_LED EFFECT=default
{% elif STATE == "standby" %}
_MMU_SET_LED EFFECT=off
_MMU_SET_LED EFFECT=off EXIT_EFFECT=off
{% endif %}


Expand All @@ -411,19 +411,25 @@ variable_led_enable: 1
# Name of the neopixel or dotstar strip. Use complete name line in quotes e.g. "neopixel:mmu_leds"
variable_leds: "neopixel:mmu_leds"

# Default effect. Can be anything but typical hard-coded choices are as:
# Default effect for gate LEDs. Can be anything but typical hard-coded functional choices are as:
# "off" - LED's off when on action occuring
# "gate_status" - indicate gate availability
# "filament_color" - indicate filament color
variable_default_effect: "gate_status"
variable_default_gate_effect: "gate_status"

# Default effect for exit LED, perhaps lighting the PTFE tube
# "off" - LED's off when on action occuring
# "filament_color" - indicate current filament color
variable_default_exit_effect: "filament_color"

gcode:
{% if printer['gcode_macro _MMU_SET_LED']['led_enable'] > 0 %}
{% set leds = printer['gcode_macro _MMU_SET_LED']['leds'] %}
{% set leds_name = leds.split(':')[1] %}
{% set default_effect = printer['gcode_macro _MMU_SET_LED']['default_effect'] %}
{% set default_gate_effect = printer['gcode_macro _MMU_SET_LED']['default_gate_effect'] %}
{% set EFFECT = params.EFFECT|default("")|string %}
{% set GATE = params.GATE|default(-1)|int %}
{% set EXIT_EFFECT = params.EXIT_EFFECT|default("")|string %}
{% set index = GATE + 1 %}
{% set DURATION = params.DURATION|default(-1)|int %}
{% set FADETIME = params.FADETIME|default(1)|int %}
Expand All @@ -435,11 +441,10 @@ gcode:
{% endif %}

{% if EFFECT == "default" %}
{% set EFFECT=default_effect %}
{% set EFFECT=default_gate_effect %}
{% endif %}

{% if EFFECT == "" or EFFECT == "off" %} # Off
# PAUL TODO keep map of RGB color vs effect for each gate..
{% if EFFECT == "off" %}
{% if GATE >= 0 %}
STOP_LED_EFFECTS LEDS="{leds} ({index})" FADETIME={FADETIME}
SET_LED LED={leds_name} INDEX={index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
Expand All @@ -456,7 +461,7 @@ gcode:
{% elif gate_status[GATE] > 0 %}
SET_LED_EFFECT EFFECT=mmu_green_{index} FADETIME={FADETIME} REPLACE=1
{% else %}
SET_LED_EFFECT EFFECT=mmu_black_{index} FADETIME={FADETIME} REPLACE=1
STOP_LED_EFFECTS LEDS="{leds} ({index})" FADETIME={FADETIME}
{% endif %}
{% else %}
{% set ns = namespace(index = 1) %}
Expand All @@ -466,7 +471,7 @@ gcode:
{% elif status > 0 %}
SET_LED_EFFECT EFFECT=mmu_green_{ns.index} FADETIME={FADETIME} REPLACE=1
{% else %}
SET_LED_EFFECT EFFECT=mmu_black_{ns.index} FADETIME={FADETIME} REPLACE=1
STOP_LED_EFFECTS LEDS="{leds} ({ns.index})" FADETIME={FADETIME}
{% endif %}
{% set ns.index = ns.index + 1 %}
{% endfor %}
Expand Down Expand Up @@ -497,13 +502,44 @@ gcode:
SET_LED LED={leds_name} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
{% endif %}

{% else %} # Simple effect by name
{% elif EFFECT != "" %} # Simple effect by name
{% if GATE >= 0 %}
SET_LED_EFFECT EFFECT={EFFECT}_{index} FADETIME={FADETIME} REPLACE=1
{% else %}
SET_LED_EFFECT EFFECT={EFFECT} FADETIME={FADETIME} REPLACE=1
{% endif %}
{% endif %}

# Apply desired effect to exit LED
{% if EXIT_EFFECT == "default" %}
{% set EXIT_EFFECT=default_exit_effect %}
{% endif %}

{% set gate_color_rgb = printer['mmu']['gate_color_rgb'] %}
{% set exit_index = gate_color_rgb|length + 1 %}
{% if EXIT_EFFECT == "off" %}
STOP_LED_EFFECTS LEDS="{leds} ({exit_index})" FADETIME={FADETIME}
SET_LED LED={leds_name} INDEX={exit_index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1

{% elif EXIT_EFFECT == "filament_color" %} # Filament color
{% set gate = printer['mmu']['gate'] %}
M118 PAUL gate={gate}
STOP_LED_EFFECTS LEDS="{leds} ({exit_index})"
{% if gate >= 0 %}
{% set rgb = gate_color_rgb[gate] %}
SET_LED LED={leds_name} INDEX={exit_index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
{% else %}
SET_LED LED={leds_name} INDEX={exit_index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
{% endif %}

{% elif "," in EXIT_EFFECT %} # Not effect, just simple RGB color
{% set rgb = EXIT_EFFECT.split(",") %}
STOP_LED_EFFECTS LEDS="{leds} ({exit_index})"
SET_LED LED={leds_name} INDEX={exit_index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1

{% elif EXIT_EFFECT != "" %} # Simple effect by name
SET_LED_EFFECT EFFECT={EXIT_EFFECT}_{exit_index} FADETIME={FADETIME} REPLACE=1
{% endif %}
{% endif %}


Expand All @@ -512,7 +548,7 @@ gcode:
#
[delayed_gcode _MMU_RESET_LED]
gcode:
_MMU_SET_LED EFFECT=default
_MMU_SET_LED EFFECT=default EXIT_EFFECT=default


###########################################################################
Expand Down
2 changes: 1 addition & 1 deletion doc/command_ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Firstly you can get a quick reminder of commands using the `MMU_HELP` command fr
| `MMU_SELECT_BYPASS` | Select the bypass selector position if configured | None |
| `MMU_CHANGE_TOOL` | Perform a tool swap (generally called from 'Tx' macros). Use `STANDALONE=1` option in your print_start macro to saftely load the initial tool | `TOOL=[0..n]` <br>`STANDALONE=[0\|1]` Optional to force standalone logic (tip forming)<br> `QUIET=[0\|1]` Optional to always suppress swap statistics |
| `MMU_LOAD` | Loads filament in currently selected tool/gate to extruder. Optionally performs just the extruder load part of the sequence - designed for bypass loading or non MMU use | `EXTRUDER_ONLY=[0\|1]` To force just the extruder loading (automatic if bypass selected) |
| `MMU_LED` | Quick way to try/test modes of operation of optional MMU LEDs | `ENABLE=[0\|1]` Whether LED's are operational or not <br> `EFFECT=[off|gate_status|filament_color` Selects the default effect for gate LEDs when no action is taking place |
| `MMU_LED` | Quick way to try/test modes of operation of optional MMU LEDs | `ENABLE=[0\|1]` Whether LED's are operational or not <br> `EFFECT=[off\|gate_status\|filament_color]` Selects the default effect for gate LEDs when no action is taking place <br> `EXIT_EFFECT=[off\|filament_color]` Selects the default effect for exit LED when no action is taking place |
| `MMU_EJECT` | `MMU_UNLOAD` | Eject filament and park it in the MMU gate or does the extruder unloading part of the unload sequence if in bypass | `EXTRUDER_ONLY=[0\|1]` To force just the extruder unloading (automatic if bypass selected) <br>`SKIP_TIP=[0\|1]` if set the tip forming/cutting macro will be skipped |
| `MMU_PRELOAD` | Helper for filament loading. Feed filament into gate, MMU will catch it and correctly position at the specified gate | `GATE=[0..n]` The specific gate to preload. If omitted the currently selected gate can be loaded |
| `MMU_PAUSE` | Pause the current print and lock the MMU operations. (`MMU_UNLOCK + RESUME` or just `RESUME` to continue print) | `FORCE_IN_PRINT=[0\|1]` This option forces the handling of pause as if it occurred in print and is useful for testing. Calls `PAUSE` by default or your `pause_macro` if set |
Expand Down
16 changes: 10 additions & 6 deletions extras/mmu.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ def __init__(self, config):
# Some initial assumed values for Tradrack
self.cad_gate_width = 17.
self.cad_gate0_pos = 0.5
self.gate_parking_distance = 17.5
if "e" in self.mmu_version_string:
self.gate_parking_distance = 39. # Using Encoder
else:
self.gate_parking_distance = 17.5 # Using Gate switch
elif self.mmu_vendor.lower() == self.VENDOR_PRUSA.lower():
raise self.config.error("Support for Prusa systems is comming soon! You can try with vendor=Other")
else:
Expand Down Expand Up @@ -2681,11 +2684,12 @@ def cmd_MMU_LED(self, gcmd):
if gcode_macro is not None:
variables = gcode_macro.variables
led_enable = gcmd.get_int('ENABLE', int(variables['led_enable']), minval=0, maxval=1)
default_effect = gcmd.get('EFFECT', variables['default_effect'])
gcode_macro.variables.update({'led_enable':led_enable,'default_effect':default_effect})
self._wrap_gcode_command("_MMU_SET_LED EFFECT=default")
self._log_always("LEDs are %s, Default effect: '%s'" % ("enabled" if led_enable else "disabled", default_effect))
self._log_always("ENABLE=[0|1] EFFECT=[off|gate_status|filament_color]")
default_gate_effect = gcmd.get('EFFECT', variables['default_gate_effect'])
default_exit_effect = gcmd.get('EXIT_EFFECT', variables['default_exit_effect'])
gcode_macro.variables.update({'led_enable':led_enable, 'default_gate_effect':default_gate_effect, 'default_exit_effect':default_exit_effect})
self._wrap_gcode_command("_MMU_SET_LED EFFECT=default EXIT_EFFECT=default")
self._log_always("LEDs are %s, Default gate effect: '%s', Default exit effect: `%s`" % ("enabled" if led_enable else "disabled", default_gate_effect, default_exit_effect))
self._log_always("ENABLE=[0|1] EFFECT=[off|gate_status|filament_color] EXIT_EFFECT=[off|filament_color]")
else:
self._log_error("LEDs not available")

Expand Down
8 changes: 4 additions & 4 deletions extras/mmu_led_effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ def __init__(self, config):
super(MmuLedEffect, self).__init__(config)

printer = config.get_printer()
leds = config.get("leds").replace(":", " ")
leds = config.get("leds").split(' ', 1)[0].replace(":", " ")
pixels = self.printer.lookup_object(leds)
num_gates = pixels.led_helper.get_led_count()
for i in range(num_gates):
num_leds = pixels.led_helper.get_led_count()
for i in range(num_leds):
new_section = self._add_config_section(config, config.get_name(), i+1)
_ = ledEffect(new_section)

Expand All @@ -32,7 +32,7 @@ def _add_config_section(self, config, section_from, index):
new_section = config.fileconfig.add_section(section_to)
for item in items:
if item[0] == "leds":
new_leds = "%s (%d)" % (item[1], index)
new_leds = "%s (%d)" % (item[1].split(' ', 1)[0], index)
config.fileconfig.set(section_to, item[0], new_leds)
else:
config.fileconfig.set(section_to, item[0], item[1])
Expand Down
5 changes: 5 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,8 @@ copy_config_files() {
# Now substitute pin tokens for correct brd_type
if [ "${brd_type}" == "unknown" ]; then
cat ${dest}.tmp | sed -e "\
s/{mmu_num_gates}/${mmu_num_gates}/; \
s/{mmu_num_leds}/${mmu_num_leds}/; \
s/{extruder_uart_pin}/${PIN[extruder_uart_pin]}/; \
s/{extruder_step_pin}/${PIN[extruder_step_pin]}/; \
s/{extruder_dir_pin}/${PIN[extruder_dir_pin]}/; \
Expand All @@ -479,6 +481,8 @@ copy_config_files() {
" > ${dest} && rm ${dest}.tmp
else
cat ${dest}.tmp | sed -e "\
s/{mmu_num_gates}/${mmu_num_gates}/; \
s/{mmu_num_leds}/${mmu_num_leds}/; \
s/{extruder_uart_pin}/${PIN[extruder_uart_pin]}/; \
s/{extruder_step_pin}/${PIN[extruder_step_pin]}/; \
s/{extruder_dir_pin}/${PIN[extruder_dir_pin]}/; \
Expand Down Expand Up @@ -940,6 +944,7 @@ questionaire() {
break
fi
done
mmu_num_leds=$(expr $mmu_num_gates + 1)

echo
echo -e "${PROMPT}${SECTION}Do you have a toolhead sensor you would like to use?"
Expand Down

0 comments on commit 022f744

Please sign in to comment.