M109 and M190 blocked [delayed gcode xxx]

Hallo
Is it normal that
M104 and M190 blocking the [delayed g code xxx] macro?

[delayed_gcode TEST]
initial_duration: 2
gcode:
  {action_respond_info ("TEST called:% .1f"% (printer.extruder.temperature | float))}
  UPDATE_DELAYED_GCODE ID = TEST DURATION = 2

How can I prevent this?

lg Chris

M190 is supposed to wait until the bed reaches temperature:

https://reprap.org/wiki/G-code#M190:_Wait_for_bed_temperature_to_reach_target_temp

Why M104 does it too, I don’t know. Maybe a typo and you typed in M109?

https://reprap.org/wiki/G-code#M109:_Set_Extruder_Temperature_and_Wait

You’re right. I meant M109, of course.
It is clear to me that these Gcodes are waiting. But it is not clear to me why everything is blocked. Apart from an emergency stop, you cannot execute a cancel or an M105 or something similar.
lg Chris

Because it is the way it is meant to work.

If you want to have the different way, you have to use M104 and M140

Great, it’s like when I drive the car and can only turn on the indicator when the car is stationary

That is the reason you have different commands.
In most circumstances you have to wait until the temperature is reached.

Like you have to have a certain number of revolutions with your car before you change gears.

I don’t think this will lead to anything.
I can stop except “wait until temperature is reached” is nothing.
No temperature query, no interruption, no LEDs control what else do I know what.
Ok, I got it. It’s because that’s the way it is. And you shouldn’t change that because the ancient people have already done it that way. :wink:

Maybe I do not understand this discussion, but:
M140: Start heating “in the background” and continue
M104: Start heating and WAIT until temperature is reached before continuing
Same goes for M190 / M109

So what is the issue in using the non-blocking variants?

I think this should be considered a bug. If delayed gcode is scheduled to be run in 5 seconds, but doesn’t run for 20 minutes because TEMPERATURE_WAIT is blocking it, this is a problem.

For example, lets say delayed gcode is used to implement some custom control loop. Now some other gcode that is run (like TEMPERATURE_WAIT) causes this delayed gcode to be blocked. The control loop will stop running and there will be no process control.

I spent a lot of time trying to find a way to override TEMPERATURE_WAIT (as it’s the biggest offender), but can’t find any way to do it. There are no while loops, or goto in the gcode macro support that I can find.

I reported this issue on github #5797, but it was marked not on github, so I’ll leave my comments here.

Suppose you want to wait for a temperature without stopping all other delayed gcode from running. How do you do this using the non-blocking variants? I can’t find any way to do this as I see no while loop or goto in the gcode macro support.

It’s not reasonable to expect all gcode to be modified to not use any blocking gcodes in order for delayed gcode execution to not be blocked.

Sorry, but that is a contradiction. You can’t wait and do not stop at the same time.

If you want to go on with your further gcode commands, you may use M104/M140 instead.
Or you put your delicate code stuff in front of the temperature command.

You may share a code snippet of what you are talking about, so we may see clearer.

No, you are taking a limited view of the gcode. You are viewing things as a single thread, which is the problem. Delayed gcode should be viewed as an interrupt or separate thread that is implementing control functions not related to the base gcode program. See my previous comments where I use delayed gcode to implement a custom control loop.

Would you expect the bed temperature PID to stop running if you execute a TEMPERATURE_WAIT on the hot end? Clearly this would be a problem. I personally use delayed gcode to implement a custom control loop for my chamber temperature. I don’t want this control loop to stop running because PRINT_START is waiting for the bed or hot end temperature target to be reached.

You will have the same with Marlin and M109/M190.
Or take M104/M104

3D printing is a singe thread process. The firmware is s single thread process.

BTW: The heating process is always controlled by the firmware PID, also during M109/M190 (as long it’s activated)

I’m not saying Marlin is any different. I also understand the heater PID are in firmware, I was using that as an example.

Delayd gcode to me should be handled like an interrupt. I saw an example somewhere on the Klipper site about a load filament macro using delayed gcode to clear a message to the screen indicating completion after a certain amount of time. If a TEMPERATURE_WAIT were executed after displaying the message, but before clearing it, the message would stay up there for a long time (until the TEMPERATURE_WAIT completed). Clearly this isn’t the desired behavior, and the delayed gcode is not intended to be synchronized with the base gcode program execution.

With delayed gcode being blocked by blocking gcodes, there is no good way to implement custom process control loops. This severely limits the usefulness of gcode macros. I feel Klipper gcode macros could be much more powerful if a second thread were used to execute delayed gcode at the scheduled time. If this isn’t agreeable, then at least goto, or some type of loop until should be added so a version of TEMPERATURE_WAIT could be coded that wouldn’t block delayed gcode.

Are you sure this was inside the gcode command fifo process or another process outside the gcode command handling as an additional Klipper plugin/subroutine.

It was an example in the gcode macro section of the manual. The macro loaded filament, displayed a message on the display, then scheduled delayed gcode to clear the message after a few seconds. Just found the code:

[delayed_gcode clear_display]
gcode:
  M117

[gcode_macro load_filament]
gcode:
 G91
 G1 E50
 G90
 M400
 M117 Load Complete!
 UPDATE_DELAYED_GCODE ID=clear_display DURATION=10

Here is the URL, scroll down to “Delayed Gcodes”: https://github.com/Klipper3d/klipper/blob/master/docs/Command_Templates.md

Curious to see that code.

I can see how changing the gcode execution architecture to be multi-threaded would be a major change. A simpler alternative would be as follows:

  1. Recode all blocking gcode to be spin loops of multiple gcode commands (add goto or some type of while loop).

  2. Insert delayed gcode at the head of FIFO when scheduled. Alternatively a 2nd high priority FIFO could be added for delayed gcode.

This solution seems like minimal architectural changes and would prevent delayed gcode from being blocked for long periods of time.

Sorry for putting this reply here, I’m limited to 3 replies, lol.

I want to use delayed gcode to implement a custom process control loop for my chamber temperature. It controls bed fans, with a PID loop and some other delta T algorithms to not adversely affect bed temperature. It works great (keeps chamber within +/-0.1C), except when the delayed gcode gets blocked by blocking gcode like TEMPERATURE_WAIT in PRINT_START.

What I end up doing is setting temps manually using non-blocking gcodes. Then wait until all temp targets are reached before starting a print. The chamber control loop then keeps the chamber temp steady during the print. It’s not as nice as it could be, but it works for now.

If you can think of another way to implement the process control, I’m listening. I tried to find a way to override the blocking TEMPERATURE_WAIT gcodes with spin loops, but that requires goto, or some type of while loop, neither of which I see in klipper.

I see, now I understand your dilemma.

So, what you want to achieve with the delayed gcode, does that give an informative output or is it meant to influence the following gcode commands?

Maybe it can be done ‘outside’ the gcode processing.

Just a silly idea of me:

I run an IDEX printer on Klipper with two independent heaters with their own PID loops.
Those run well.

If you ‘miss use’ an extruder heater for the heated chamber?
The problem I see there, you need some fake pins for the necessary (not existing ) connections to the extruder driver.