Support of COPY and MIRROR modes for IDEX

Hi,

I’ve put together a branch with more extended IDEX support, namely COPY and MIRROR modes are supported for the dual carriage. It is not based on the previously created code by @Tircown, although offers very similar functionality. If you have IDEX printer and are interested in this topic (e.g. have been using his branch previously), please give it a try and report any problems you may encounter. I have some (albeit, not very high) hopes that it can be merged into the mainline. Note that I do not have IDEX printer myself, so I can only do this much in testing it. It was tested by others already, and at least cartesian kinematics seems to work, but hybrid_corexy/z were tested much less thoroughly.

The configuration of the dual carriage is pretty much the same as in the mainline, with a few highlights:

[dual_carriage]
axis: x
...............
safe_distance: 50  # set to the minimum distance to maintain between the carriages

[extruder]
..........

[extruder1]
...........

[input_shaper]
# Intentionally empty

[delayed_gcode init_shaper]
initial_duration: 0.1
gcode:
  SET_DUAL_CARRIAGE CARRIAGE=1
  SET_INPUT_SHAPER SHAPER_TYPE_X=<dual_carriage_shaper> SHAPER_FREQ_X=<dual_carriage_freq> SHAPER_TYPE_Y=<y_shaper> SHAPER_FREQ_Y=<y_freq>
  SET_DUAL_CARRIAGE CARRIAGE=0
  SET_INPUT_SHAPER SHAPER_TYPE_X=<primary_carriage_shaper> SHAPER_FREQ_X=<primary_carriage_freq> SHAPER_TYPE_Y=<y_shaper> SHAPER_FREQ_Y=<y_freq>

Then the regular switching between primary and dual carriage can be done as usual (see e.g. config/sample-idex.cfg for more insights and some of the macros):

[gcode_macro T0]
gcode:
    PARK_{printer.toolhead.extruder}
    ACTIVATE_EXTRUDER EXTRUDER=extruder
    SET_DUAL_CARRIAGE CARRIAGE=0

[gcode_macro T1]
gcode:
    PARK_{printer.toolhead.extruder}
    ACTIVATE_EXTRUDER EXTRUDER=extruder1
    SET_DUAL_CARRIAGE CARRIAGE=1

The copy and mirror modes, on the other hand, can be configured as follows (most easily done in the slicer start code):

......................
G28
......................
; set bed temp
M190 S<...> 
......................

; Configure the carriage 0
SET_DUAL_CARRIAGE CARRIAGE=0 MODE=PRIMARY
; Set the initial position of the primary carriage
G0 X<...> Y<...> Z<...> F<...>
; Set the printing parameters for the primary extruder
ACTIVATE_EXTRUDER EXTRUDER=extruder
SET_PRESSURE_ADVANCE EXTRUDER=extruder ADVANCE=<filament_0_pa>
M104 T0 S<filament_0_temp>

; Configure the carriage 1
SET_DUAL_CARRIAGE CARRIAGE=1 MODE=PRIMARY
; Set the initial position of the dual carriage (Y and Z must stay the same)
G0 X<...> F<...>
SET_DUAL_CARRIAGE CARRIAGE=1 MODE=COPY
SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder
SET_PRESSURE_ADVANCE EXTRUDER=extruder1 ADVANCE=<filament_1_pa>
M104 T1 S<filament_1_temp>

M109 T0 S<filament_0_temp>
M109 T1 S<filament_1_temp>

And similarly for mirror mode just with an appropriate position for the dual carraige (accounting for mirroring of the moves) and SET_DUAL_CARRIAGE CARRIAGE=1 MODE=MIRROR command.

Also note that if you have [bed_mesh] enabled, you should disable it prior to any actual printing in COPY or MIRROR mode (e.g. by calling BED_MESH_CLEAR in the start script, and not calling BED_MESH_CALIBRATE or BED_MESH_PROFILE LOAD=... commands). This is important because it is not possible to make two carriages on the same (Y) axis follow different Z profiles (both carriages must have the same Z height from the buildplate). Activating bed mesh in this case will make both carriages follow the bed mesh for carriage_0, which may result in a crash of carriage_1 with the bed. Instead, bed must be rather flat and leveled such that neither of the carriages can crash into the bed. You may want to print the first layer thicker and with larger line width than you’d normally print to avoid potential problems with the first layer adhesion, or even activate the raft in the slicer if you still get problems with the bed flatness.

4 Likes

This is great news!

Well done :+1:

Just finished building my cartesian IDEX:

Maybe I’ll give it a try.

Thank you for this great work!

Thank you for working on this. I will test it out later today or tomorrow.
I posted a link in the DoomCube Tridex discord, so hopefully some others there will help test.

You might want to put something in there to disable bed mesh since both toolheads can’t follow the same contours.

You are right about bed mesh. One could call BED_MESH_CLEAR there to disable any possible bed mesh adjustments. Since it may not be entirely obvious, I’ll edit the original post to mention it.

1 Like

Copy and Mirror mode work as expected. I was able to print in both and received correct out of bounds warnings if either toolhead tried to move past an X limit or come within the safe_distance.

I am able to cause toolhead crashes when switching modes multiple times and moving the toolheads around in Fluidd. I’d hoped to post instructions to replicate the issue, but have run out of time for testing today. Thought I’d go ahead and mention it in case anyone else wants to focus their testing efforts there.

EDIT: Skip this explanation and see next post.

The location of one of the toolheads is getting offset from where it should be. It happens when I activate copy or mirror mode, activate CARRIAGE1, move it around a lot using the fluidd controls, activate CARRIAGE0, and move it. One of the carriages ends up off from where it should be. The last time was after activating mirror mode. If moved CARRIAGE1 toward CARRIAGE0, klipper would give an out of bounds error too soon (around 14mm away from the actual safe_distance). It would also allow me to run CARRIAGE1 past the right x max limit. It is like Klipper has the position of the second carriage 14mm left of where it actually is. Another time instead of giving me the out of bounds warning too soon it allowed me to crash CARRIAGE1 into CARRIAGE0. It think that time I had used copy mode, but I am not certain. Both of these occurred after making multiple mode switches and moving the carriages around between them. Fluidd is switching to relative positioning and back to absolute when making the moves, so I don’t know if the timing of that would be a factor.[/spoiler]

I know this is vague and not all that useful. I will make instructions with the simplest moves to replicate it when I get time and figure it out. I wanted to let you know that I am testing and have come across an issue.

It bothered me to leave it so vague, so I worked on it some more instead of doing the things I should.

I believe the issue is related to negative coordinates. On my printer (hybrid corexy) carriage0 parks at -50 so the other carriage can reach more of the build plate. Safe distance is set to 70. If I move carriage0 to -25, activate MIRROR mode, then switch to carriage1 in primary mode and move it to 50 the nozzles are 75 apart. There is no problem moving carriage1 into this position.

But then when I switch back to carriage0 and try to move it will give an out of bounds for any movement. There should be enough room for the carriage to move 1 in either direction, but it gives the out of bounds warning. If I switch back to carriage1 primary it will also give an out of bounds warning for any movement and Fluidd says it is at 25, not 50 where it actually is.

This will create the issue:

G28
G90
G1 Y5 X-25 F7800
SET_DUAL_CARRIAGE CARRIAGE=1 MODE=MIRROR
SET_DUAL_CARRIAGE CARRIAGE=1 MODE=PRIMARY
G1 X50 F7800
SET_DUAL_CARRIAGE CARRIAGE=0 MODE=PRIMARY

It does not happen if I shift the coordinates over to 25 and 100.

If carriage1 is only moved to 150 while carriage0 is at -25, then the carriages can still move, but the position of carriage1 will be off, allowing it to crash past xmax.

OK, thank you for providing the test case, I think I found and fixed the problem. Please check that it’s fixed now.

1 Like

It is fixed now.

I will test SAVE/RESTORE_IDEX_STATE and input shaping sometime next week.

Hi, I tested cartesian kinematics on IDEX COPY and MIRROR mods. Movement and guard collision carriages is fine.
I didn’t find anything wrong with the kinematics.

-Petr

Thank you all for the work and bug fixing.
Already upgraded to the latest version but have to finish setting up everything before testing it.

@dmbutyugin

SYNC_EXTRUDER_MOTION allows extrusion when the second extruder is below min_extrude_temp

It’s not an issue unless the printer is malfunctioning or a macro is poorly written, but should probably be addressed IMO.

I believe I’ve put input shaper through its paces enough to say it works in copy and mirror modes.

I printed test cubes in mirror mode without input shaper, in mirror mode with input shaper, and in copy mode with input shaper. Cubes printed with input shaper enabled have less ringing. This was using my usual input shaping frequency and type. I also measured the cubes to make sure they were both the same dimensionally.

Then I checked that TEST_RESONANCES still worked while in copy and mirror modes. Had to adjust the probe point, but it worked fine with both toolheads resonating. Toolhead movement was opposite for mirror mode, as it should be.

I haven’t tried to optimize input shaper for the modes, but everything appears to work as it should.

1 Like

SAVE_IDEX_STATE and RESTORE_IDEX_STATE work correctly both assigning a name and omitting the name and letting it use “default”.

This will get more testing when I get around to making better macros, but it appears to all work as it should.

1 Like

That’s true, but it is true in the general case of SYNC_EXTRUDER_MOTION use. If you use it for anything else, e.g. some different toolchanger, it would work similarly allowing a user to extrude below the min_temp. So, IDEX support doesn’t bring new or change anything here. And while the problem is there, I’m afraid my PR isn’t the right place to implement any safety features for that functionality. At least, I suppose nobody would try to enter a bunch of commands manually, but use some macros or gcode in the slicer, so they could easily avoid problems.

I am glad that it will not affect your pull request.

I have done all the testing I could think to do and tried to break it in all the ways I could think of.
It has worked properly in every situation. I doubt that I will have any other issues to report.

Although you deleted your post, did you see:

I would say you have to query both carriages for the inactive status.

Currently trying to tell Cura what I want:
image

However my Python skills are getting better… now.

I neglected to use quotes around INACTIVE. Someone on discord set me straight shortly after I posted the question.

Let me know if you have success with adding that option. That is what I wanted to do, but it is way over my head.

I’ve been messing around with BCND’s Stratos Slicer. I tried adding my printer via all the definition files, but can’t enable the second toolhead for some reason. (and if you add a printer without two extruders, their IDEX plugin will crash).
It will let you change all the specs and name of a BCND printer until it matches yours though.
I still haven’t tried to set up M605 macros to work with it or print any gcode from it. Just looking at it to see how things are done. It’s more out of curiosity than anything.

I will stick with Cura.

1 Like

@dmbutyugin if this is ok for you I’ll share my Cura IDEX mode plugin here as it is built for your branch and might help it grow in popularity. :blush:

Otherwise I’ll delete it.

Hey, all.
I’m working on getting my custom cartesian IDEX printer to work with this. I can’t seem to get past homing. I had homing working on an older version of Klipper but that’s as far as I got since the printer wasn’t finish.

Now that it’s finish, I’ve switched to this branch and I can’t seem to keep the X axis as recognizing that it’s been homed even when it has.

I’m using Eddie the Engineer’s IDEX_HOME_X macro

[gcode_macro IDEX_HOME_X]
gcode:
    G28 X0
    ACTIVATE_EXTRUDER EXTRUDER=extruder1
    SET_DUAL_CARRIAGE CARRIAGE=1
    G1 X310 F5000
    T0

Once it gets to X310 it says: Must home axis first: 310.000 0.000 8.000 [0.000]

I had edited this macro before to be a complete homing operation since I don’t know how to do homing overrides(yet).

Any idea what I might be missing here?

I have three other printers running Klipper so I wouldn’t say I’m new to this but I’m absolutely no expert.