Hi,
I have been working recently on a code to permit a user to map dual_carriage(s) to the GCode axes with generic_cartesian kinematics, and also allow mapping the extruders to custom axes besides E. The code now is in a working state (can be found here), and I wanted to raise awareness of this feature and invite for testing. So, how can it be used? Let’s assume you have
[dual_carriage u]
primary_carriage: x
...
and optionally
[dual_carriage v]
primary_carriage: y
...
Now, the command like
SET_DUAL_CARRIAGE CARRIAGE=u MODE=DIRECT
is supported, which adds GCode axis U, and now the carriage u can be controlled independently:
G1 X150 Y200 U250 F6000
Of course, you can move u carriage alone without x:
G1 U200 Y250 F6000
The only requirement is that the name of the dual_carriage is a single letter that is not already used by some axis, e.g. manual_carriage, extruder, and not a special letter (F, N).
If you want to disable the direct dual_carriage control, you can switch it to a different mode, e.g.
SET_DUAL_CARRIAGE CARRIAGE=x MODE=PRIMARY ; disables dual_carriage
SET_DUAL_CARRIAGE CARRIAGE=u MODE=PRIMARY ; maps dual_carriage to 'X' axis and disables primary
If you have two dual_carriages, then these commands can be executed independently or together for these carriages (u and v in my example), e.g.
SET_DUAL_CARRIAGE CARRIAGE=u MODE=DIRECT
SET_DUAL_CARRIAGE CARRIAGE=v MODE=DIRECT
will add two new GCode axes U and V, but it is possible to activate only one carriage in DIRECT mode too.
One small but important note for the users with two dual_carriages: in general, Klipper must track the trajectory of the toolhead to compute maximum speed to pass the corners. When a single dual_carriage is activated in DIRECT mode, e.g. u, Klipper will simply track the second “toolhead” that is mapped to (U, Y, Z) coordinates and will compute the cornering speeds for it, no action is needed. However, if there are two dual_carriages, and they are both running in DIRECT mode, Klipper will only track (X, Y, Z) “toolhead” and (U, V, Z) “toolhead” for cornering by default. But some printers may have up to 4 toolheads in such setups, so in order to let Klipper know about other toolheads, I added a command
SET_TRACK_CARRIAGES_JUNCTION CARRIAGES=<carriage_list> [ENABLE=[0|1]]
which can be used to enable or disable tracking of these extra “toolheads”, e.g.
SET_TRACK_CARRIAGES_JUNCTION CARRIAGES=U,Y,Z
SET_TRACK_CARRIAGES_JUNCTION CARRIAGES=X,V,Z
SET_TRACK_CARRIAGES_JUNCTION CARRIAGES=U,V,Z ENABLE=0
As for the extruders, you can now map an extruder to a GCode axis and activate it via, e.g.
ACTIVATE_EXTRUDER EXTRUDER=extruder1 GCODE_AXIS=G
and then run commands like
G1 X150 Y200 U250 E3.1 G2.5 F6000
G1 E-1 G-1 F1200
G1 E1 G-1 F1200
Unmapping the extruder from the GCode axis can be done via
ACTIVATE_EXTRUDER EXTRUDER=extruder1 GCODE_AXIS=
Note that extruder will retain the previously specified GCode axis, so a subsequent call with a simple
ACTIVATE_EXTRUDER EXTRUDER=extruder1
will map it back to the latest specified GCode axis (‘E’ by default). To map the exturder back to ‘E’, you need to activate it for ‘E’ axis: ACTIVATE_EXTRUDER EXTRUDER=extruder1 GCODE_AXIS=E.
Other notable implemented functionality and some potential gotchas:
printer.toolhead.axis_minimumand `printer.toolhead.axis_maximum`will export the minimum and maximum range of travel for DIRECT mode dual_carriage(s)printer.toolhead.positionwill also report the components for DIRECT mode dual_carriage(s) and extruders that are mapped to other GCode axesGET_POSITIONandM114will report all GCode axes, and the former will also correctly compute kinematic position of the toolhead for all kinematic axesRESTORE_GCODE_STATEwill now restore the base positions and offsets for DIRECT mode dual_carriage(s) and mapped extruders- However, these are restored on a by-name basis and only for the axis that still exist since
SAVE_GCODE_STATEcommand invocation, so if the axes has changed, this may apply offsets to the ‘wrong’ axes, so ideallySAVE_GCODE_STATE/RESTORE_GCODE_STATEshould only be called without changing axes in between or at least restoring the same axes.
- However, these are restored on a by-name basis and only for the axis that still exist since
G92now supports setting a position for DIRECT mode dual_carriage(s) and mapped extrudersSET_GCODE_OFFSETcan now set an offset also for DIRECT mode dual_carriage(s)- Note that normally (for XYZ axes) the set offsets are preserved through homing. However, for dual_carriage axes (like
UandVin my example) the offsets are not going to be preserved that way after homing because DIRECT mode is disabled for them during homing (so in fact X and Y offsets will be applied if any). If you want to preserve offsets, you can do it viaSAVE_GCODE_STATE,G28,RESTORE_GCODE_STATE.
- Note that normally (for XYZ axes) the set offsets are preserved through homing. However, for dual_carriage axes (like
M221command now supportsTargument. Called without this argument, e.g.M221 S98still sets the extrude factor override percentage to 98% for the active extruder mapped toEaxis. ButM221 T0 S98will set this factor specifically for extruderextruder, andM221 T1 S101will set the factor to 101% for extruderextruder1, and so forth.- Note however that calling
ACTIVATE_EXTRUDERresets the extrude factor of the newly activated extruder back to 100% (this is Klipper current behavior), so in practiceM221 T{index} S{factor}will have an effect only for extruders that are already mapped to some GCode axis and are active.
- Note however that calling
printer.gcode_move.gcode_positionandprinter.gcode_move.positionwill report the position of all GCode axesprinter.gcode_move.extrude_factorswill report on a per-axis extrude factors of mapped extruders, e.g.printer.gcode_move.extrude_factors.e,printer.gcode_move.extrude_factors.g(based on the example above), etc.
So, what can these features be used for? I think at the moment due to lack of slicer support, primarily in various macros and manually generated GCode, for example for fast tool swaps on IDEX printers. As always, any feedback is appreciated.



