Frix-x / klippain

Generic Klipper configuration for 3D printers
GNU General Public License v3.0
849 stars 221 forks source link

Filament sensor management ineffective during filament management macros #300

Closed austinrdennis closed 11 months ago

austinrdennis commented 12 months ago

Klippain branch

Version

4.4.1 Release

Describe the bug and expected behavior

Due to the way klipper executes gcode macros, the filament management macros (LOAD_FILAMENT, UNLOAD_FILAMENT, etc.) do not execute commands as I think you intended them to.

As they are implemented currently, the filament runnout sensor deactivates and re-activates long before the extrude G0 command has finished moving the extruder motor. This is because Klipper will issue the G0 command to the MCU and continue executing the macro without regard for when the move completes (it buffers move commands). This guarantees pause at the very beginning of every print file if the LINE_PURGE or PURGE (bucket purge) macros are called during the START_PRINT sequence and the filament sensor type is motion_sensor.

I'm looking into a way to solve this and I'll submit a PR when I figure it out as this isn't trivial. I just wanted to get this documented.

Additional information

You can see this in action during this macro call for LOAD_FILAMENT with the filament loaded into the hotend without being loaded into the sensor:

image

You can see the sensor is de-activated and re-activated in the same second the macro is called, indicating that it doesn't wait for the G0 command to finish moving before re-activating the sensor. This caused my runnout sensor to initiate a pause and notify me of the error while the filament was loading since I had not routed filament through it. I believe that this is unintended behavior.

Excerpt from the klipper command templates section of the documentation:

Macros are first evaluated in entirety and only then are the resulting commands executed. If a macro issues a command that alters the state of the printer, the results of that state change will not be visible during the evaluation of the macro. This can also result in subtle behavior when a macro generates commands that call other macros, as the called macro is evaluated when it is invoked (which is after the entire evaluation of the calling macro).

Frix-x commented 11 months ago

Thank you for bringing this issue to attention. You're right about the problem, and I believe I have already the solution :)

Macros are first evaluated in entirety and only then are the resulting commands executed. If a macro issues a command that alters the state of the printer, the results of that state change will not be visible during the evaluation of the macro. This can also result in subtle behavior when a macro generates commands that call other macros, as the called macro is evaluated when it is invoked (which is after the entire evaluation of the calling macro).

To clarify, it is not really the macro that is fully evaluated first, but the Jinja template. The Jinja engine evaluates first the template to "generate" pure static Gcode. Then in a second step, Klipper reads this static Gcode to direct the printer's movements and controls. That's why, if you modify variables, they will only be assessed during the Jinja template's expansion phase, not afterward, because we are working with static Gcode at that point.

Given this, the problem we're facing is slightly different. The Jinja template processes and produces the following output:

SET_FILAMENT_SENSOR SENSOR="runout_sensor" ENABLE=0
RESPOND MSG="Runout sensor deactivated to unload filament"
SAVE_GCODE_STATE NAME=UNLOAD_FILAMENT_state
_LOW_TEMP_CHECK T={TEMP}
_TIP_SHAPING
M83
G1 E-20 F3600
G4 P3000
G1 E-105 F3000
RESTORE_GCODE_STATE NAME=UNLOAD_FILAMENT_state
SET_FILAMENT_SENSOR SENSOR="runout_sensor" ENABLE=1
RESPOND MSG="Filament unloaded, runout sensor reactivated"

Klipper then reads this and buffers some of the lines (I'm don't remember of the exact number of lines buffered but it doesn't matter). The issue arises because the G1 command to unload the filament doesn't stop the execution, and the remaining buffered lines continues to be evaluated.

To prevent this, we need to flush Klipper's buffer before executing the SET_FILAMENT_SENSOR command. We can achieve this by using the M400 command, which I agree should be incorporated here. This command will finish the execution of all the Gcode lines buffered before continuing to the next one.

I've never had any filament sensor triggering during a load/unload and that's why I never saw this before today, but thanks for the report! I'll push a fix in a couple of minutes :)

Frix-x commented 11 months ago

A fix was pushed in e4f0121d8eb8541f4eee568edcb23cdfb574fb21 to be released in the next version :)

austinrdennis commented 11 months ago

Wow, I learned something new here and now that makes 100% sense to me. I had no idea there was a way to flush the buffer and that's extremely handy. Awesome work, love the project!