I'm posting this here in the "Gcode meta commands" section because these files contain many of these type of commands which might serve as practical examples. But the files might also be useful for anyone setting up a tool changer.
I'm slowly getting to grips with meta commands and the object model but I've had a lot of help along the way from others on these forums and from DC42, so a big thank you to all who have helped me out.
I don't have a tool changer as such. That is to say, I do have multiple tools and print multiple filament types but with a 6 input, dual heat zone, single nozzle hot end. So switching between filaments means moving the print head over a "chute" and purging, wiping etc as well as changing temperatures and filament specific parameters for things like pressure advance, retraction settings, speed multipliers etc. There are a lot of other things going on such as when changing from a high temperature filament to a low temperature one, I need to purge out the high temperature filament with low temperature filament but before I change the temperature. Otherwise, the nozzle will still be full of high temperature filament which won't extrude at the new, lower, temperature setting. Then I need to do a second purge with the new filament at the correct temperature.
Anyway, here is what I have for tfree0 but you'll see that with the use of conditional statements and meta commands, it's a "universal" file. So I could wrap all the commands into a single macro called something like "toolfree" and use a one line M98 in every tfree file. Likewise tpre and tpost. The files are all annotated so shouldn't need any further explanation.
echo "Running tfree",state.currentTool,tools[state.currentTool].name
; in this case will print "Running tfree 0 PLA"
G10 ; retract
All this file does is to retract the filament but note the "universal" echo statement which uses the current tool number and current tool name.
Here is tpre
echo "Running tpre",state.currentTool,tools[state.currentTool].name
; check if axes homed and if so, move to purge position, if not, abort
if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed || !move.axes[3].homed || !move.axes[4].homed
abort "One or more axes not homed - aborting"
G1 X{global.left} U{global.left} Y{global.rear} V{global.rear} F18000; move to "bucket"
In tpre, I need to move both the print head (XY) and the extruder gantry (UV) to a position over the purge bucket (chute) which is defined by the global variables. So it's important that the printer has been homed before attempting the G1 moves. Hence the check which will either do the move or abort. Again I use a "universal" echo statement which will tell me which tpre file is being run as well as the tool name.
Here is tpost which has a bit more going on like additional purge but only if going from high temperature filament to low temperature, force cooling but only if going from a high temperature to a low temperature, waiting for temperatures to settle, wiping the nozzle etc.
echo "Running tpost",state.currentTool,tools[state.currentTool].name
;state.currentTool is the current tool number, so in this case will print "Running tpost 0 PLA"
; When switching from a high temperature filament to a low temperature filament
; it is necessary to purge out the old filament with the new filament
; at the high temperature. No tool is active at the start of tpre
; so I need to do the purge here in tpost.
; By doing it first, the hot end won't have had time to cool
; heat.heaters[1] is the nozzle heater
; tools[n] is the tool number
; active[0] is the nozzle active temperature
if heat.heaters[1].current >= tools[state.currentTool].active[0]-5; 5 degree tolerance - no point purging if both temps close to each other
echo "Purging out high temperature filament"
M98 P"0:/macros/SinglePurge.g" ; purge nozzle
;the following will force cool the nozzle to within 4 deg of the active temp if it's too hot
while (heat.heaters[1].current > heat.heaters[1].active+4)
echo "Force cooling nozzle now at ", sensors.analog[1].lastReading ; show current hot end temperature
M106 P2 S255; turn on force cooling fan
G4 S1 ; wait a sec
M106 P2 S0 ;turn fan off
; the following will wait for the nozzle only to heat to within 3 degrees of it's active temp if it's too cold
; it won't wait for the combining block temperature to change
while (heat.heaters[1].current < heat.heaters[1].active-3)
echo "Waiting for Tool",state.currentTool,"to reach temperature" ; will print "Waiting for Tool 0 the reach temperature"
echo "Now at",sensors.analog[1].lastReading
G4 S1
; load filament specific parameters from macros/Filaments
echo "Loading ",tools[state.currentTool].name," specific parameters" ; will print for example "Loading PLA specific parameter"
M98 P{"0:/macros/Filaments/"^tools[state.currentTool].name^".g"} ; will load the macro with the exact same name as the tool - so be careful!!
; in this case, it will load 0:/macros/filaments/PLA.g
echo "Purging Tool", state.currentTool,tools[state.currentTool].name ; will print "Purging Tool 0 PLA" in this case
M98 P"0:/macros/SinglePurge.g" ; purge nozzle
echo "Wiping nozzle"
M98 P"0:/macros/Nozzle wipe" ; wipe nozzle
M400 ; wait for moves to complete
G1 R2 X0 Y0 U0 V0 Z0 F18000 ; return gantries to whence they came prior to tool change
G11; unretract
The comments within the file should explain what's happening but if not, I'll happily answer any questions.
So hopefully you'll see that by using meta commands and conditional gcode, I've ended up with "universal" files that can be used with any tool. As stated earlier, the entire thing could be wrapped in another macro so each and every tpost file would simply have the same single M98 to call that macro. Without those meta commands, I would have specifically reference say the active temperature for the specific tool, so every tpost file would be slightly different. I have 9 tools defined so that's 27 separate tool change files which would otherwise need to have slight differences between them.
There is just one thing I still need to address which is this....
M98 P{"0:/macros/Filaments/"^tools[state.currentTool].name^".g"}
This will extract the current tool name and add it to the path for the macro. So for example with tool named "PLA" the macro must also be named "PLA.g". I need to add error checking to catch cases where the macro is incorrectly named or missing.
This was great help https://docs.duet3d.com/en/User_manual/Tuning/Tool_changing. Especially the section on tool change sequence. There is one thing I found slightly quirky which is that the old tool gets deselected after tfree, but the new tool isn't active until after tpre. So no tool is selected during tpre which means that if you want to do anything with extruders, you'd have to do something like pick up and save the active temperature of the previous or next tool in a variable, set the temperature to the correct value for the old tool, do what you need to do, then restore the correct active temperature.
Anyway, I hope the above may be of use or at least give you some ideas.