From 904cb2f52f8022e7e1b1fe9853589524ab501029 Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:32:55 +0200 Subject: [PATCH 1/6] Add tool change behavior configuration options Added configuration options for tool change behavior, including parking location and nozzle cleaning settings. --- macros/indx.cfg | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/macros/indx.cfg b/macros/indx.cfg index d393507..a33ac01 100644 --- a/macros/indx.cfg +++ b/macros/indx.cfg @@ -95,6 +95,37 @@ variable_t2_dock_y: -26 variable_t3_x: 102.0 variable_t3_dock_y: -26 +# ── Tool change behaviour when printing ─────────────────────────────────────── +# park_on_ooze_pad = if you have an ooze pad or filament scraper on your X/Y axes +# The nozzle will go to this location after a tool change to heat up. + +# pad_x = Location on X axis. +# pad_Y = Location on Y axis. + +# restore_pos = goes to the last location before the tool change to heat up +# best used with your slicer's "Tool Change on Wipe Tower" setting. + +# NOTE: park_on_ooze_pad overrides the restore_pos setting! Also if both are set False +# the standard Bondtech tool change process is carried out. + +# NOTE: Don't set pad_x or pad_y where they'll hit the edge of the printer's travel +# on either axis as you could end up with layer shifts &/or possible machine damage. + +# tc_scrub = Choose to use a gantry mounted nozzle cleaner if you have one. +# pass_count = Choose how many times the nozzle moves from tcs_start to tcs_fin locations. + +variable_park_on_ooze_pad: False +variable_pad_x: 10.00 +variable_pad_y: 26.00 +variable_restore_pos: True + +variable_tc_scrub: False +variable_pass_count: 2 +variable_tcs_start_x: 10 +variable_tcs_start_y: 26 +variable_tcs_fin_x: 10 +variable_tcs_fin_y: 46 + # ── Assembled at startup from the variables above — do not edit ────────────── variable_tools: [] From c0e731826746495871f6c2c7aee5412440f99115 Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:34:37 +0200 Subject: [PATCH 2/6] Enhance tool change macros with new variables and logic Added variables for exit pickup and restore coordinates in the tool change macros. Enhanced G-code macros to handle tool change logic more robustly, including checks for valid restore positions and scrub functionality. --- macros/indx-tc-macros.cfg | 110 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/macros/indx-tc-macros.cfg b/macros/indx-tc-macros.cfg index 01c7a36..ae0eb67 100644 --- a/macros/indx-tc-macros.cfg +++ b/macros/indx-tc-macros.cfg @@ -61,6 +61,10 @@ variable_accel_mult: 0.7 variable_speed_mult: 0.7 variable_toolhead_state: 0 # 0=Locked, 2=Open variable_rotation_dist_overridden: 0 +variable_exit_pickup: False +variable_valid_restore: True +variable_restore_x: 50 +variable_restore_y: 50 gcode: [delayed_gcode INIT_STATE] @@ -213,14 +217,109 @@ gcode: _SET_MODE M=sport A=1.0 S=1.0 C=1 [gcode_macro _TC_G0] gcode: {% set v = printer["gcode_macro _TOOLCHANGE_VARS"] %} + {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} {% set final_f = (printer.configfile.settings.printer.max_velocity * 60 * v.speed_mult) %} - G0 {% if 'X' in params %}X{params.X} {% endif %}{% if 'Y' in params %}Y{params.Y} {% endif %}{% if 'Z' in params %}Z{params.Z} {% endif %}F{params.F|default(final_f)|int} + + {% if (not tp.park_on_ooze_pad and not tp.restore_pos) or not v.exit_pickup %} + G0 {% if 'X' in params %}X{params.X} {% endif %}{% if 'Y' in params %}Y{params.Y} {% endif %}{% if 'Z' in params %}Z{params.Z} {% endif %}F{params.F|default(final_f)|int} + + {% else %} + G0 {% if 'X' in params %}X{params.X} {% endif %}{% if 'Y' in params %}Y{params.Y} {% endif %} F{params.F|default(final_f)|int} + M400 + + {% if 'Z' in params %} + {% if v.exit_pickup %} + {% if printer.print_stats.state in ["printing", "paused"] %} + # On exit_pickup when printing the toolhead moves to an ooze pad or filament scraper loaction to heat the tool. + {% if tp.park_on_ooze_pad %} + {% if tp.dock_dir == -1 and tp.pad_y|float < tp.clearance_y|float %} + RESPOND TYPE=error MSG="⚠️ TOOL CHANGE park_on_ooze_pad pad_y is set less than clearance_y please correct this to activate this feature!" + + {% elif tp.dock_dir == 1 and tp.pad_y|float > tp.clearance_y|float %} + RESPOND TYPE=error MSG="⚠️ TOOL CHANGE park_on_ooze_pad pad_y is set greater than clearance_y please correct this to activate this feature!" + + {% else %} + G0 X{tp.pad_x|float} Y{tp.pad_y|float} F{params.F|default(final_f)|int} + {% endif %} + + # On exit_pickup when printing the toolhead moves back to exact loaction where the tool change was issued. + # When used with "Tool change on wipe tower" this makes sure the nozzle waits & heats on the tower to catch any oozing as there are no guards yet. + {% elif tp.restore_pos %} + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=valid_restore VALUE=True + _TC_XY_RESTORE_CHECK + M400 + _TC_XYZ_RESTORE Z={params.Z} + {% endif %} + + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=exit_pickup VALUE=False + + {% else %} + G0 Z{params.Z} F{params.F|default(final_f)|int} + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=exit_pickup VALUE=False + {% endif %} + {% endif %} + {% endif %} + {% endif %} + +[gcode_macro _TC_XY_RESTORE_CHECK] +gcode: + {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} + {% set v = printer["gcode_macro _TOOLCHANGE_VARS"] %} + {% set act = printer.save_variables.variables.active_tool|default(-1)|int %} + + {% for i in range(tp.tools|length) %} + {% set p_x = "t" ~ i ~ "_x"|string %} + {% set p_y = tp.clearance_y|float %} + + {% if tp.dock_dir == -1 %} + {% if (v.restore_x == tp[p_x] and v.restore_y|float == p_y) or (i == act and v.restore_y|float < p_y) %} + RESPOND TYPE=COMMAND MSG="Restore coordinates create a non-valid exit point. Skipping restore...." + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=valid_restore VALUE=False + {% endif %} + + {% else %} + {% if (v.restore_x == tp[p_x] and v.restore_y|float == p_y) or (i == act and v.restore_y|float > p_y) %} + RESPOND TYPE=COMMAND MSG="Restore coordinates create a non-valid exit point. Skipping restore...." + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=valid_restore VALUE=False + {% endif %} + {% endif %} + {% endfor %} + +[gcode_macro _TC_XYZ_RESTORE] +gcode: + {% set v = printer["gcode_macro _TOOLCHANGE_VARS"] %} + {% set final_f = (printer.configfile.settings.printer.max_velocity * 60 * v.speed_mult) %} + + {% if v.valid_restore %} + G0 X{v.restore_x|float} Y{v.restore_y|float} F{params.F|default(final_f)|int} + M400 + G0 Z{params.Z|float} F{params.F|default(final_f)|int} + {% endif %} + +[gcode_macro _TC_SCRUB] +gcode: + {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} + {% set v = printer["gcode_macro _TOOLCHANGE_VARS"] %} + {% set final_f = (printer.configfile.settings.printer.max_velocity * 60 * v.speed_mult) %} + + {% if tp.dock_dir == -1 and (tp.tcs_start_y|float < tp.clearance_y|float or tp.tcs_fin_y|float < tp.clearance_y|float) %} + RESPOND TYPE=error MSG="⚠️ TOOL CHANGE tc_scrub tcs_start_y or tcs_fin_y is set less than clearance_y please correct this to activate this feature!" + + {% elif tp.dock_dir == 1 and (tp.tcs_start_y|float < tp.clearance_y|float or tp.tcs_fin_y|float > tp.clearance_y|float) %} + RESPOND TYPE=error MSG="⚠️ TOOL CHANGE tc_scrub tcs_start_y or tcs_fin_y is set greater than clearance_y please correct this to activate this feature!" + + {% else %} + {% for passes in range(1, (tp.pass_count + 1)) %} + G0 X{tp.tcs_start_x|float} Y{tp.tcs_start_y|float} F{params.F|default(final_f)|int} + G0 X{tp.tcs_fin_x|float} Y{tp.tcs_fin_y|float} F{params.F|default(final_f)|int} + {% endfor %} + {% endif %} [gcode_macro _LINEAR_EXIT] gcode: {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} {% set c = printer["gcode_macro _INDX_CONSTANTS"] %} - {% set restore_z = params.RESTORE_Z|default("")|string %} + {% set restore_z = params.RESTORE_Z|default(0)|float %} {% set clearance_y = tp.clearance_y %} @@ -236,7 +335,8 @@ gcode: # nozzle across the part. G90 _TC_G0 Y={"%.3f"|format(clearance_y)} - {% if restore_z != "" %} + {% if restore_z > 0 %} + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=exit_pickup VALUE=True M400 _TC_G0 Z={restore_z} {% endif %} @@ -503,6 +603,10 @@ gcode: M109 S{params.TARGET|default(0)|float} {% endif %} + {% if printer.print_stats.state in ["printing", "paused"] and tp.tc_scrub == True and tp.restore_pos == False %} + _TC_SCRUB + {% endif %} + # Record last — save active_tool and increment counter after physical pickup completes _RECORD_TOOLCHANGE TOOL={t} From 9e2e8adf9817b8b7fb5acc7df32b15375880ebfe Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Thu, 27 Aug 2026 01:24:05 +0200 Subject: [PATCH 3/6] Introduce _RESTORE_GRABBER macro for tool changes Added _RESTORE_GRABBER macro to manage tool change positions. --- macros/indx-tc-macros.cfg | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/macros/indx-tc-macros.cfg b/macros/indx-tc-macros.cfg index ae0eb67..faa08c2 100644 --- a/macros/indx-tc-macros.cfg +++ b/macros/indx-tc-macros.cfg @@ -450,6 +450,7 @@ gcode: # drags the nozzle across the print at both ends of the change. {% set zhop = tp.z_hop|float %} {% set restore_z = "%.3f"|format(printer.gcode_move.gcode_position.z) %} + _RESTORE_GRABBER # 6. Physical tool swap {% if act != -1 %} @@ -614,6 +615,11 @@ gcode: # 6. HELPER MACROS ##################################################################### +[gcode_macro _RESTORE_GRABBER] +gcode: + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=restore_x VALUE={"%.3f"|format(printer.gcode_move.gcode_position.x)} + SET_GCODE_VARIABLE MACRO=_TOOLCHANGE_VARS VARIABLE=restore_y VALUE={"%.3f"|format(printer.gcode_move.gcode_position.y)} + [gcode_macro _RECORD_TOOLCHANGE] description: Inner — saves active_tool and increments the toolchange counter after every successful pickup gcode: From af288ca77cc0215d1c28792727c5a1f166c0d301 Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Thu, 27 Aug 2026 09:41:25 +0200 Subject: [PATCH 4/6] Update exit pickup handling in indx-tc-macros.cfg Refactor exit pickup logic and remove unused _TC_SCRUB macro. --- macros/indx-tc-macros.cfg | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/macros/indx-tc-macros.cfg b/macros/indx-tc-macros.cfg index faa08c2..f28f71c 100644 --- a/macros/indx-tc-macros.cfg +++ b/macros/indx-tc-macros.cfg @@ -231,16 +231,10 @@ gcode: {% if v.exit_pickup %} {% if printer.print_stats.state in ["printing", "paused"] %} # On exit_pickup when printing the toolhead moves to an ooze pad or filament scraper loaction to heat the tool. - {% if tp.park_on_ooze_pad %} - {% if tp.dock_dir == -1 and tp.pad_y|float < tp.clearance_y|float %} - RESPOND TYPE=error MSG="⚠️ TOOL CHANGE park_on_ooze_pad pad_y is set less than clearance_y please correct this to activate this feature!" - - {% elif tp.dock_dir == 1 and tp.pad_y|float > tp.clearance_y|float %} - RESPOND TYPE=error MSG="⚠️ TOOL CHANGE park_on_ooze_pad pad_y is set greater than clearance_y please correct this to activate this feature!" - - {% else %} - G0 X{tp.pad_x|float} Y{tp.pad_y|float} F{params.F|default(final_f)|int} - {% endif %} + {% if tp.park_on_ooze_pad %} + G0 X{tp.pad_x|float} + M400 + Y{tp.pad_y|float} F{params.F|default(final_f)|int} # On exit_pickup when printing the toolhead moves back to exact loaction where the tool change was issued. # When used with "Tool change on wipe tower" this makes sure the nozzle waits & heats on the tower to catch any oozing as there are no guards yet. @@ -296,25 +290,6 @@ gcode: G0 Z{params.Z|float} F{params.F|default(final_f)|int} {% endif %} -[gcode_macro _TC_SCRUB] -gcode: - {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} - {% set v = printer["gcode_macro _TOOLCHANGE_VARS"] %} - {% set final_f = (printer.configfile.settings.printer.max_velocity * 60 * v.speed_mult) %} - - {% if tp.dock_dir == -1 and (tp.tcs_start_y|float < tp.clearance_y|float or tp.tcs_fin_y|float < tp.clearance_y|float) %} - RESPOND TYPE=error MSG="⚠️ TOOL CHANGE tc_scrub tcs_start_y or tcs_fin_y is set less than clearance_y please correct this to activate this feature!" - - {% elif tp.dock_dir == 1 and (tp.tcs_start_y|float < tp.clearance_y|float or tp.tcs_fin_y|float > tp.clearance_y|float) %} - RESPOND TYPE=error MSG="⚠️ TOOL CHANGE tc_scrub tcs_start_y or tcs_fin_y is set greater than clearance_y please correct this to activate this feature!" - - {% else %} - {% for passes in range(1, (tp.pass_count + 1)) %} - G0 X{tp.tcs_start_x|float} Y{tp.tcs_start_y|float} F{params.F|default(final_f)|int} - G0 X{tp.tcs_fin_x|float} Y{tp.tcs_fin_y|float} F{params.F|default(final_f)|int} - {% endfor %} - {% endif %} - [gcode_macro _LINEAR_EXIT] gcode: {% set tp = printer["gcode_macro TOOL_POSITIONS"] %} @@ -604,10 +579,6 @@ gcode: M109 S{params.TARGET|default(0)|float} {% endif %} - {% if printer.print_stats.state in ["printing", "paused"] and tp.tc_scrub == True and tp.restore_pos == False %} - _TC_SCRUB - {% endif %} - # Record last — save active_tool and increment counter after physical pickup completes _RECORD_TOOLCHANGE TOOL={t} From 8cc3415ad15056d69b32e351669bf6fbb5b8f670 Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Thu, 27 Aug 2026 09:42:29 +0200 Subject: [PATCH 5/6] Clean up unused nozzle cleaning configuration Removed unused variables related to nozzle cleaning and pass count. --- macros/indx.cfg | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/macros/indx.cfg b/macros/indx.cfg index a33ac01..723c65b 100644 --- a/macros/indx.cfg +++ b/macros/indx.cfg @@ -111,21 +111,11 @@ variable_t3_dock_y: -26 # NOTE: Don't set pad_x or pad_y where they'll hit the edge of the printer's travel # on either axis as you could end up with layer shifts &/or possible machine damage. -# tc_scrub = Choose to use a gantry mounted nozzle cleaner if you have one. -# pass_count = Choose how many times the nozzle moves from tcs_start to tcs_fin locations. - variable_park_on_ooze_pad: False variable_pad_x: 10.00 variable_pad_y: 26.00 variable_restore_pos: True -variable_tc_scrub: False -variable_pass_count: 2 -variable_tcs_start_x: 10 -variable_tcs_start_y: 26 -variable_tcs_fin_x: 10 -variable_tcs_fin_y: 46 - # ── Assembled at startup from the variables above — do not edit ────────────── variable_tools: [] From e617cbba7fadb486e4810cd5757adc7c406a94e1 Mon Sep 17 00:00:00 2001 From: 3DPrintDemon <122202359+3DPrintDemon@users.noreply.github.com> Date: Fri, 28 Aug 2026 18:32:03 +0200 Subject: [PATCH 6/6] Update macros/indx-tc-macros.cfg Co-authored-by: Charlie <81966433+charliemayall@users.noreply.github.com> --- macros/indx-tc-macros.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/indx-tc-macros.cfg b/macros/indx-tc-macros.cfg index f28f71c..762732a 100644 --- a/macros/indx-tc-macros.cfg +++ b/macros/indx-tc-macros.cfg @@ -234,7 +234,7 @@ gcode: {% if tp.park_on_ooze_pad %} G0 X{tp.pad_x|float} M400 - Y{tp.pad_y|float} F{params.F|default(final_f)|int} + G0 Y{tp.pad_y|float} F{params.F|default(final_f)|int} # On exit_pickup when printing the toolhead moves back to exact loaction where the tool change was issued. # When used with "Tool change on wipe tower" this makes sure the nozzle waits & heats on the tower to catch any oozing as there are no guards yet.