moggieuk / Happy-Hare

MMU software driver for Klipper (ERCF, Tradrack, Prusa)
GNU General Public License v3.0
473 stars 118 forks source link

Variable printer['mmu'].runout appears to be written too late #219

Closed TTom1088 closed 7 months ago

TTom1088 commented 7 months ago

In the event of a "normal fault" the printer switches to my own PAUSE macro as normal. In case of runout, the variable "printer['mmu'].runout" should be set to "True". This means I can then activate a different procedure during runout in the pause macro.

If Runout is now activated, the printer goes directly to pause and the query: {% set runout = printer['mmu'].runout %} {% if runout == True %} is ignored. The variable is probably still set to “False”. I can only use my own macro because the print head also changes its Z height during runout. This requires a separate macro to avoid collisions.

Thank you in advance Thomas T.

moggieuk commented 7 months ago

Ah, that is true. Good catch. It's all because of the way that klipper uses jinja templates -- the context is evaluated before execution and thus printer variables will not change within a macro. A classic trick is to have one macro call another so the execution context is renewed. This would probably work, but I'll have to think about if there is anything I can do better. Yes I can set earlier, but the pause occurs before I know if it is a runout or not. There may be a way, I'll look into it.

moggieuk commented 7 months ago

Ok. I pushed a branch that you can validate. It is a small change but I want to be careful with this. To switch to this branch:

cd ~Happy-Hare
./install.sh -b issue219

Let me know it that works. I think it will. Once I hear back from you I'll merge into main..

BTW to get back to main branch you redo the above with -b main

TTom1088 commented 7 months ago

First of all, thank you for the quick processing. I've now been able to do some tests and it works with a detour.

Runout is detected (tested via MMU_TEST_RUNOUT). But now no “pause” is activated. Therefore I had to go to the purge box using the __MMU_PRE_UNLOAD macro to switch. And use the _MMU_POST_LOAD to clean the nozzle and return to pressure level. Here is the modified macro

[gcode_macro _MMU_PRE_UNLOAD_RUNOUT] description: Optional pre unload routine for filament change with runout gcode: {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} {% set park_after_form_tip = vars.park_after_form_tip|default(false)|lower == 'true' %} SAVE_GCODE_STATE NAME=MMU_PRE_UNLOAD_state _MMU_AUTO_HOME _MMU_SAVE_POSITION {% if not park_after_form_tip %} _MMU_PARK {%endif% {vars.user_pre_unload_extension|default("")} RESTORE_GCODE_STATE NAME=MMU_PRE_UNLOAD_state _RUNOUT_ABFRAGE_POSITIONIERUNG

in the macro _RUNOUT_ABFRAGE_POSITIONIERUNG is then the query

{% set runout = printer['mmu'].runout %} {% if runout == True %}

and the same with the [gcode_macro _MMU_POST_LOAD_RUNOUT] macro I then used these in the parameters.cfg.

I'll test everything again in a real test one day by cutting the filament and see if everything fits.

Of course, if you have an idea to make the whole thing more user-friendly, I would be open to any idea. One idea would be to enter a runout macro directly in parameters.cfg. But that's how it works :-)

Thank you

TTom1088 commented 7 months ago

Theoretically I could also insert the macros via the mmu_macro_vars

variable_user_pre_unload_extension : '' ; Executed after default logic

insert so: variable_user_pre_unload_extension : '_RUNOUT_QUERY_POSITIONING' ; Executed after default logic

The same then with variable_user_post_load_extension This is of course much more convenient :-)

moggieuk commented 7 months ago

My changes to the "issue219" branch were kind of quick. Basically I avoid sending the PAUSE until the last minute -- in theory if the runout is handled by endlessSpool, then there is not need to pause at all (it is just an inserted "toolchange"). I can't remember why are always pause but I don't think it is necessary.... [can you think of errors in this logic?]

By waiting to the last minute to pause I'm able to know better if it is a runout or a clog. The problem is that if the runout comes from a sensor that is NOT the encoder I know it is a runout (may need to pause but only if endless spool can't help). This the "runout" is from the encoder then I need a further test (wiggling the filament and looking for encoder movement) to know if its a runout or clog.

Anyway, is the way it is working in the branch and using the "pre_unload_extension" hook (which is the right way to do it and will survive upgrades and so be much less pain for you), is this working ok?

TTom1088 commented 7 months ago

Hello, it's me again. The big practical test came today and I found a small hurdle. First I added my runout variable only in the mm_macro_vars. variable_user_pre_unload_extension :

variable_user_pre_unload_extension : '_RUNOUT_ABFRAGE_POSITIONIERUNG' variable_user_post_load_extension : '_RUNOUT_ABFRAGE_NOZZLE_REINIGEN'

this has worked so far. But the printer stopped printing after the change. https://youtube.com/shorts/aJ2YIaSp0Gk

first a change of the _MMU_PRE_UNLOAD and _MMU_POST_LOAD_RUNOUT Macros led to success because the entire MMU logic was switched off during runout

#########################################################################

[gcode_macro _MMU_PRE_UNLOAD_RUNOUT] description: Optional pre unload routine for filament change mit Runout gcode: {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} {% set park_after_form_tip = vars.park_after_form_tip|default(false)|lower == 'true' %} {% set runout = printer['mmu'].runout %}

{% if runout != True %}
    SAVE_GCODE_STATE NAME=MMU_PRE_UNLOAD_state
    _MMU_AUTO_HOME
    _MMU_SAVE_POSITION
    {% if not park_after_form_tip %}
        _MMU_PARK
    {% endif %}

  #{vars.user_pre_unload_extension|default("")}
  RESTORE_GCODE_STATE NAME=MMU_PRE_UNLOAD_state
{% endif %}
_RUNOUT_ABFRAGE_POSITIONIERUNG

####################################################################

[gcode_macro _MMU_POST_LOAD_RUNOUT] description: Optional post load routine for filament change mir Runout gcode: {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} {% set timelapse = vars.timelapse|default(false)|lower == 'true' %} {% set mmu_paused = printer.mmu.is_locked %} {% set runout = printer['mmu'].runout %}

{% if runout != True %}
  SAVE_GCODE_STATE NAME=MMU_POST_LOAD_state

  {% if timelapse %}
      TIMELAPSE_TAKE_FRAME
  {% endif %}

# A good place to implement custom purging logic and/or nozzle cleaning
# prior to returning to print/wipetower
#{vars.user_post_load_extension|default("")}

  {% if not mmu_paused %}
      _MMU_RESTORE_POSITION
  {% endif %}
  RESTORE_GCODE_STATE NAME=MMU_POST_LOAD_state
{% endif %}
_RUNOUT_ABFRAGE_NOZZLE_REINIGEN

############################################################### That's how it worked

https://youtube.com/shorts/OPF-k0DeTAs

TTom1088 commented 7 months ago

I have now found another error. When the printer is on pause. e.g. because of a node in the buffer and you then remove the filament while it is paused, the runout process will still be started. Would it be possible to disable runout detection during _mmu_pause?

moggieuk commented 7 months ago

runout should be disabled. Can you share the mmu.log...

TTom1088 commented 7 months ago

Sorry. I reinstalled Klipper for this printer because there were mcu problems after a Klipper update. But the error only occurred at one point: For example, if T1 was loaded and a knot had formed in the buffer, it could not unload properly. Happy hare activated the pause macro. But T1 was "officially" still loaded. When I then removed the filament to untangle it, it activated the runout routine. This could of course also be due to the other sequence macro. This state is also difficult to simulate.

Once the fix for the runout variable has been made in the main branch, I will continue to work on it. For now, it has to run safely 😅. I have to finish printing my orders first.

TTom1088 commented 7 months ago

mmu.log I found the MMU log on the old SD card. The runout event during the should be documented here at the end

https://drive.google.com/file/d/18GNN8Jb3gD8677Ru4ifZZiyWpYAvlbfN/view?usp=sharing

TTom1088 commented 7 months ago

Since the last update the runout routine has been working perfectly. You definitely have to use the runout macro BASE_PAUSE and BASE_RESUME Install it so that the printer continues printing after changing the roll. Here are my runout macros as an example

############################################################

[gcode_macro _RUNOUT_ABFRAGE_POSITIONIERUNG] description: Runout wird abgefragt und es wird zur Purgebox gefahren. variable_fan_drehzahl: 0

gcode: {% set runout = printer['mmu'].runout %}

{% if runout == True %} SET_GCODE_VARIABLE MACRO=_RUNOUT_ABFRAGE_NOZZLE_REINIGEN VARIABLE=runout VALUE=1
M118 Runout erkannt Druckkopf faehrt zur Purgebox RESPOND PREFIX=tgalarm MSG="Endlessspool wechselt die Rolle" SET_GCODE_VARIABLE MACRO=_RUNOUT_ABFRAGE_POSITIONIERUNG VARIABLE=fan_drehzahl VALUE={printer['fan'].speed}
M106 S0 M117 Rollenwechsel G1 F96000 G90 SAVE_GCODE_STATE NAME=Rollenwechsel G10 G91 G1 E-1 F2100 G1 Z1 G90 G1 X31 Y350 F96000
G92 E0 SAVE_GCODE_STATE NAME=Rollenwechsel_OBEN G1 Z4.5 {% endif %}

###################################################

[gcode_macro _RUNOUT_ABFRAGE_NOZZLE_REINIGEN] description: nach Runout wird Nozzle gereinigt variable_runout:0 #wird nur in _RUNOUT_ABFRAGE_POSITIONIERUNG freigegeben variable_fluss_ausgleich:2 #0.5 SET_GCODE_VARIABLE MACRO=_RUNOUT_ABFRAGE_NOZZLE_REINIGEN VARIABLE=fluss_ausgleich VALUE=2

gcode: {% if runout == 1 %} G90 G1 F96000 G92 E0 G91 G1 F200 E15
G1 F2000 E-3 G92 E0 G10 G90 NOZZLE_WISCHEN G1 X31 Y350 F96000
RESTORE_GCODE_STATE NAME=Rollenwechsel_OBEN MOVE=1 SPEED=200 M106 S{printer["gcode_macro _RUNOUT_ABFRAGE_POSITIONIERUNG"].fan_drehzahl*255} G91 G1 F2000 E{3-fluss_ausgleich} #soll blobs verhindern G90 G11 Licht_dunkel LED_Drucken RESTORE_GCODE_STATE NAME=Rollenwechsel MOVE=1 MOVE_SPEED=300 SET_GCODE_VARIABLE MACRO=_RUNOUT_ABFRAGE_NOZZLE_REINIGEN VARIABLE=runout VALUE=0 RESPOND PREFIX=tgalarm MSG="Rollenwechsel Erfolgreich" M118 Rollenwechsel ist fertig G11 BASE_PAUSE BASE_RESUME {% endif %}

###################################

These macros are then inserted into the mmu_macro_vars

variable_user_pre_unload_extension : '_RUNOUT_ABFRAGE_POSITIONIERUNG'
variable_user_post_load_extension : '_RUNOUT_ABFRAGE_NOZZLE_REINIGEN'