Retry in macro script

hello to all klipper guru’s

im trying to make a macro with a retry, but based on how a macro’s work (i guess that the macro is being excecuted on de host “if else statments needs to be done first” then the result of it is send to the printer in the serial buffer like normal gcode works) it’s not possible what i have in mind

below is my “attempt” at making a retry in the macro. what i want to do is to make QUAD_GANTRY_LEVEL more error resistent. it happend, and i think duo to the sensor (futher improvement) that QUAD_GANTRY_LEVEL errors out because of to many probe retry’s. After the error the printer would just resume and try to print with a not leveled Quantry.

   {%set Z_MIN_POS_X = 232 %}
   {%set Z_MIN_POS_Y = 350 %}
   {%set retry = 5 %}

   {%set XY_SPEED = 100 %} ; xy movements speed mm/s
   {%set Z_SPEED = 30 %} ; z movements speed mm/s
   {%set Z_LIFT = 5 %} ; z lift before XY home
   {%set HOMED_Z_LIFT = 10 %} ; z lift after Z home
   {%set PARK_SPEED = 0 %} ; parking movement speed mm/s

   {% set WAS_HOMED_XY = ('x' in printer.toolhead.homed_axes) and ('y' in printer.toolhead.homed_axes) %}
   
   G90
   {% if Z_LIFT|float > 0 %}
      G0 Z{Z_LIFT|float} F{(Z_SPEED * 60)|int}
   {% endif %}
   G28 X Y
   
   {%set HOME_Z%}
   G0 X335 Y310 F{(XY_SPEED * 60)|int}
   G0 X124 F{(XY_SPEED * 60)|int}
   G0 Y336 F{(XY_SPEED * 60)|int}
   
   G28 Z
   G0 Z20 
   G0 Y310 F{(XY_SPEED * 60)|int}
   {% endset %}
   {HOME_Z}
   
     
  {% if retry <= 0 %}
   { action_respond_info("Gantry leveling failed!! check printer, canceling print") }
   CANCEL_PRINT
  {% endif %}

  {% if (not WAS_HOMED_XY or not printer.quad_gantry_level.applied) and retry|int > 0 %}
   { action_respond_info("Gantry was non homed, running gantry level..") }
   QUAD_GANTRY_LEVEL
   G28 X Y
   {% if not printer.quad_gantry_level.applied %}
       { action_respond_info("Gantry failed, running gantry level. again") }
       {% set retry = retry - 1 %}
   {% endif %}
   {HOME_Z}
  {% endif %}
  

  G0 X335 F{(XY_SPEED * 60)|int}
  G0 Y335 F{(XY_SPEED * 60)|int}

so duo to not understanding Macro’s completly this might look like gibberish. to give some insight in my thinking, I thought that HOME_Z would be a call to the code from {%set HOME_Z%} and then run the code from there all the way down again. after reading this code again it would mean that i would have a unending loop on my hands and this is clearly not the case.

question remains, is it even possible to make a retry this way

Your understanding is mostly correct: the macro is first evaluated (or rendered as a gcode string), then executed (the gcode commands are interpreted one after the other).

At the evaluation stage, any template variable ({% ... %}) will see the state of the printer prior to the execution of any gcode it contains. That’s why, if not printer.quad_gantry_level.applied after QUAD_GANTRY_LEVEL can’t detect a failed leveling because it hasn’t happened yet!

The solution is to split the macro. Consider what happens during the execution of a MACRO_A that contains a MACRO_B command at the end:

  1. MACRO_A is evaluated which generate a gcode string,
  2. These gcode commands are executed, and might change the printer state. For example by calling QUAD_GANTRY_LEVEL. Then finally the MACRO_B is invoked,
  3. MACRO_B is evaluated, this time with an updated state that contain the results (side effects) of MACRO_A. That’s where you can ask for different behavior depending of the results of MACRO_A,
  4. The gcode that resulted from the evaluation of MACRO_B is executed.

I can’t offer a complete solution, but I hope this helps.
You’re on the right path with a recursive macro, but you need to test the new printer state in a different macro than the one calling QUAD_GANTRY_LEVEL.
You will probably need two macros, like HOME_Z that levels, then calls another macro CHECK_OR_RETRY_HOME_Z, which will check the result, and if it failed, re-level and call itself.
Note that some variables, like retry, might need to be persisted across macro invocations, {% set is not enough. Either pass it as an argument to the recursive invocation, or use a macro variable (see gcode_macro and SET_GCODE_VARIABLE doc).

ty for the info, this helps allot.

so this is my solution for now. did not test it yet but klipper finds it “OKE”.
the SET_GCODE_ VARIABLE did’nt work for me. like this

[gcode_macro test]
variable_test: 0
gcode:
       SET_GCODE_VARIABLE MACRO=test VARIABLE=variable_test VALUE=5

this always errors out that variable_test is not a valid option for macro test

so went with idee number 2, when calling macro also pass along the variable.

[homing_override]
gcode: 
   HOME_Z set_retry=5 initial_homing=1

[gcode_macro HOME_Z]
gcode: 
   {%set Z_MIN_POS_X = 232 %}
   {%set Z_MIN_POS_Y = 350 %}

   {%set XY_SPEED = 100 %} ; xy movements speed mm/s
   {%set Z_SPEED = 30 %} ; z movements speed mm/s
   {%set Z_LIFT = 5 %} ; z lift before XY home
   {%set HOMED_Z_LIFT = 10 %} ; z lift after Z home
   {%set PARK_SPEED = 0 %} ; parking movement speed mm/s
   {%set retry = params.set_retry|int %}

   {% set WAS_HOMED_XY = ('x' in printer.toolhead.homed_axes) and ('y' in printer.toolhead.homed_axes) %}

   
   {% set HOME_Z %}
   G0 X335 Y310 F{(XY_SPEED * 60)|int}
   G0 X124 F{(XY_SPEED * 60)|int}
   G0 Y336 F{(XY_SPEED * 60)|int}
   
   G28 Z
   G0 Z20 
   G0 Y310 F{(XY_SPEED * 60)|int}
   {% endset %}

   {% if params.initial_homing %}
       G90
       {% if Z_LIFT|float > 0 %}
           G0 Z{Z_LIFT|float} F{(Z_SPEED * 60)|int}
       {% endif %}
       G28 X Y
       {HOME_Z}
   {% endif %}
   
   {% if (not WAS_HOMED_XY or not printer.quad_gantry_level.applied) and retry|int > 0 %}
      { action_respond_info("Gantry was non homed, running gantry level..") }
      QUAD_GANTRY_LEVEL
      G28 X Y
      {HOME_Z}
   {% endif %}
   QGL_check set_retry={(retry|int)}
  

[gcode_macro QGL_check]
gcode: 
   {%set retry = (params.set_retry - 1)|int %}
   {% if not printer.quad_gantry_level.applied and retry > 0 %}
      { action_respond_info("Gantry failed, running gantry level. again") }
      HOME_Z set_retry={(retry|int)} initial_homing=0
   {% elif retry <= 0 %}
      { action_respond_info("Gantry leveling failed!! check printer, canceling print") }
      CANCEL_PRINT
   {% else %}
      G0 X335 F{(XY_SPEED * 60)|int}
      G0 Y335 F{(XY_SPEED * 60)|int}
   {% endif %}