I’ve rebased the branch.
Thanks. I’ll run through my tests some time today. You have any other features you are waiting on doing before you submit a PR? I’m here to help if you need anything. Thanks for all of your work, this is such a fun change.
I just wrapped up some significant upgrades to this machine around motors, belts, pulley’s and idlers. Currently have tested idex prints, but nothing yet on iqex. I’m guessing it’ll work great. Will hopefully get some time today to do it. Maybe tomorrow. Looking good so far with primary print modes and idex though. Probably have 20 hours of prints so far with no issues that aren’t my own ![]()
Alright, confirming that everything is working great from my testing. No regressions and all is well. Thanks again for the work here @dmbutyugin. It’s solid.
@dmbutyugin Can we get another rebase? I feel like the nag, but is there a feature or something you are working on before a PR is submitted?
Well, the PR was already created some time ago: [generic_cartesian] Full IQEX printers support by dmbutyugin · Pull Request #7165 · Klipper3d/klipper · GitHub
That’s great news! I’ve scooped up a patreon subscription on @koconnor and sent a small tip to you @dmbutyugin as well in support of the work here. I really appreciate the feature and open nature of klipper development. Thanks gang!
@transmutated You may also want to test generic_cartesian: Allow dual carriage inactivation by dmbutyugin · Pull Request #7194 · Klipper3d/klipper · GitHub
I’ve got a print going, but I’ll give this a go tomorrow once it wraps up. This is great functionality if ti works as documented! Does it only work with > 2 tools or should this be tested across 01 and 0123?
I think testing the full 4 tool setup is sufficient (I tested 2 tools on my machine already). But it would be interesting to test then a more complex parking logic (that parks inactive gantry too), e.g. something along the lines of:
[gcode_macro _PARK_AND_DISABLE_TOOL]
gcode:
{% set park_gantry0 = printer.dual_carriage.carriages["carriage carriage_t0"] == "INACTIVE" and printer.dual_carriage.carriages["dual_carriage carriage_t1"] == "INACTIVE" and params.CARRIAGE in ['carriage_t0', 'carriage_t1'] %}
{% set park_gantry1 = printer.dual_carriage.carriages["dual_carriage carriage_t2"] == "INACTIVE" and printer.dual_carriage.carriages["dual_carriage carriage_t3"] == "INACTIVE" and params.CARRIAGE in ['carriage_t2', 'carriage_t3'] %}
SAVE_GCODE_STATE NAME=disable_tool
{% if park_gantry0 %}
SET_DUAL_CARRIAGE CARRIAGE=carriage_gantry0_left MODE=INACTIVE
{% endif %}
{% if park_gantry1 %}
SET_DUAL_CARRIAGE CARRIAGE=carriage_gantry1_left MODE=INACTIVE
{% endif %}
SAVE_DUAL_CARRIAGE_STATE NAME=disable_tool
SET_DUAL_CARRIAGE CARRIAGE={params.CARRIAGE}
{% if park_gantry0 %}
{% set park_y = "Y" ~ printer.configfile.settings["carriage carriage_gantry0_left"].position_min %}
SET_DUAL_CARRIAGE CARRIAGE=carriage_gantry0_left
{% elif park_gantry1 %}
{% set park_y = "Y" ~ printer.configfile.settings["dual_carriage carriage_gantry1_left"].position_max %}
SET_DUAL_CARRIAGE CARRIAGE=carriage_gantry1_left
{% else %}
{% set park_y = "" %}
{% endif %}
G1 X{params.PARKING_POSITION} {park_y} F12000
M117 G1 X{params.PARKING_POSITION} {park_y} F12000
SYNC_EXTRUDER_MOTION EXTRUDER={params.EXTRUDER} MOTION_QUEUE=
RESTORE_DUAL_CARRIAGE_STATE NAME=disable_tool MOVE=0
RESTORE_GCODE_STATE NAME=disable_tool MOVE=0
[gcode_macro DISABLE_T0]
gcode:
SET_DUAL_CARRIAGE CARRIAGE=carriage_t0 MODE=INACTIVE
_PARK_AND_DISABLE_TOOL CARRIAGE=carriage_t0 EXTRUDER=extruder PARKING_POSITION={printer.configfile.settings["carriage carriage_t0"].position_min}
[gcode_macro DISABLE_T1]
gcode:
SET_DUAL_CARRIAGE CARRIAGE=carriage_t1 MODE=INACTIVE
_PARK_AND_DISABLE_TOOL CARRIAGE=carriage_t1 EXTRUDER=extruder1 PARKING_POSITION={printer.configfile.settings["dual_carriage carriage_t1"].position_max}
[gcode_macro DISABLE_T2]
gcode:
SET_DUAL_CARRIAGE CARRIAGE=carriage_t2 MODE=INACTIVE
_PARK_AND_DISABLE_TOOL CARRIAGE=carriage_t2 EXTRUDER=extruder2 PARKING_POSITION={printer.configfile.settings["dual_carriage carriage_t2"].position_min}
[gcode_macro DISABLE_T3]
gcode:
SET_DUAL_CARRIAGE CARRIAGE=carriage_t3 MODE=INACTIVE
_PARK_AND_DISABLE_TOOL CARRIAGE=carriage_t3 EXTRUDER=extruder3 PARKING_POSITION={printer.configfile.settings["dual_carriage carriage_t3"].position_max}
*feel free to add safety margins to position_min / position_max as appropriate.
So, basically, test disabling several tools, e.g. while printing (or simulating printing) in COPY or MIRROR modes
DISABLE_T0
...
DISABLE_T2
...
DISABLE_T1
or
DISABLE_T0
...
DISABLE_T3
...
DISABLE_T2
Alright, I’ve wrapped up printing and I’ve got everything in order to kick off some mirror/copy prints. Let me whip up some macros based on the examples, incorporate the PR into my local setup, and then we’ll kick off some prints. Should be able to test in the within the next hour I’d imagine.
Alright, got side tracked last night but I’ve got the PR merged and my macros prepped. Just kicked off a mirror print now
I’ll snag some video and see how the excludes go.
Alright, this functionality is next level! Great work @dmbutyugin! I’ll share my first macro attempt for the lolz. Shimmer of hope, but an eStop all the same: IMG_7970.mov
I hit the stop record button on my phone between tool 3 and 2 + 1, but it worked great!
Successful attempt 2…
Tool 3: IMG_7971.mov
Tools 2 & 1: IMG_7972.mov
Again, very impressive work @dmbutyugin. I hacked on your sample macro from the PR and it worked great. I’ll use it as boiler plate for some other things like turning off heaters. But this is a great feature that you can’t feel until you start copy and mirror prints ![]()
I noticed in this video that the all printing toolheads freeze when one stop printing. Is this intended, macros fault, or is there some limitation in the kinematics code?
Yeah, I’m assuming that is intentional… with all of the motion from the other tools, trying to print while that is happening would surely show up as a defect. At least I’d imagine it would.
Well, dual_carriage code does not support asynchronous motion of the carriages, as a result it is not possible to park one carriage while the others keep printing. Keep in mind that this is meant for the situations of a failed print with one of the toolheads, when the alternative is to cancel the print altogether. With that said, there are a few things that one can do to reduce the freeze time and its impact on printing artifacts on other objects:
- speed up the tool parking (for example, I use 1000 mm/sec speed and 10000 mm/sec^2 for tool swaps and parking, which reduces tool swap/park time to ~0.5 seconds)
- make sure to retract the filament while parking and unretract it afterwards
- cancel the print while the printer prints infill, or
- add gcode to layer change code (or elsewhere) that calls gcode_macro that would check if tool cancel is needed and cancel as appropriate (and add gcode macros to the Klipper config to handle all that) so that the tool is deactivated in predictable points when its not printing anything, or
- override
G0/G1commands to check if tool cancel is needed, and deactivate them only during non-printing moves (e.g., during a retract move).
And @transmutated thanks for testing!
BTW, @transmutated I thought that you may be also interested in testing fast tool swaps on your 4 tool machine (others are welcome to test this too, of course). Basically, this requires a custom branch that adds a feature to map carriages to dedicated GCode axes (e.g. SET_DUAL_CARRIAGE CARRIAGE=uc MODE=DIRECT GCODE_AXIS=U) and a post-processing gcode script for slicer that enables tools temperature management, and purging and wiping the extruder being activated (which I recently updated to support –num_tools=... with more than 2 tools). It does require some Klipper and slicer configuration changes (more details can be found here) and also some printer hardware features (nozzle wipers near extruders parked positions, ideally nozzle not being blocked at parked position (which may be somewhat counter-intuitive)), but then it enables very fast tool swaps of 0.5-1 second (e.g. video), with no purge tower required. From the videos you shared previously it looks like your printer would be (mostly?) compatible with this script, although you may be limited in accelerations and perhaps speeds because of unsupported linear rails being used as X gantries, but if you print parts with more than 1 filament simultaneously (e.g. multi-color prints, detacheable supports from different filament), it could still be very beneficial to give it a go and save considerable amount of time per print on tool swaps.
I’ll see if I can’t get some time in this weekend to test this out. Looks awesome!
Great! If you run into issues or have questions, feel free to reach out. For now the configuration of the whole thing end-to-end is a bit complicating and may seem overwhelming at first, but it is actually not too bad.
