Toolchange (StealthChanger)¶
What happens between T1 in the GCode and the printer extruding from
the new tool, plus how the NFC-loaded metadata flows in.
The mechanics¶
sequenceDiagram
autonumber
participant G as GCode (T1)
participant K as Klipper
participant TC as klipper-toolchanger
participant T0 as T0 (active)
participant T1 as T1 (next)
G->>K: T1
K->>TC: tool change requested
TC->>TC: PRE_TOOL_CHANGE hook (user macro)
TC->>T0: park sequence:<br/>Z hop, dock approach, latch release
TC->>K: switch active extruder
TC->>T1: pickup sequence:<br/>dock approach, latch engage, leave dock
TC->>K: apply T1 offsets (X, Y, Z, rotation, PA)
TC->>K: restore Z, resume planned motion
TC->>TC: POST_TOOL_CHANGE hook (user macro)
K-->>G: ok (continue print)
The choreography itself is entirely viesturz/klipper-toolchanger; this site doesn't try to re-document it.
Where NFC metadata enters¶
Both pre- and post-change hooks read from save_variables so per-tool
filament settings travel with the toolchange. The fleet's canonical PA
applier (NFC_APPLY_PA + _PA_DEFAULTS) is documented verbatim in
save_variables → reading from macros.
For a toolchanger the same priority logic (spool-specific PA →
per-material fallback → universal default) applies once per tool. The
shape below extends NFC_APPLY_PA to per-tool keys — verify your
extruder naming (extruder / extruder1 / …) matches your config
before using:
Adapt to your config
The skeleton below uses the same three-tier priority as the
single-tool NFC_APPLY_PA. Pull the per-material defaults from
_PA_DEFAULTS (see reference),
swap the nfc_* reads for nfc_t{N}_*, and pass EXTRUDER=… to
SET_PRESSURE_ADVANCE. Real macros also need homing checks, error
paths, and slicer hand-off that aren't shown.
[gcode_macro NFC_APPLY_PA_TOOL]
description: Apply per-tool PA from NFC scan with material fallback
gcode:
{% set t = params.T|int %}
{% set svv = printer.save_variables.variables %}
{% set pa_stored = svv["nfc_t" + t|string + "_pressure_advance"] | default(-1.0) | float %}
{% set material = svv["nfc_t" + t|string + "_material"] | default("") | string | upper %}
{% set defaults = printer["gcode_macro _PA_DEFAULTS"] %}
{% set extruder = "extruder" if t == 0 else "extruder" + t|string %}
{% if pa_stored > 0 %}
SET_PRESSURE_ADVANCE EXTRUDER={extruder} ADVANCE={pa_stored}
{% else %}
{% if material == "PLA" %} {% set pa_fb = defaults.pla %}
{% elif material == "PETG" %} {% set pa_fb = defaults.petg %}
{% elif material in ["ASA", "ABS"] %} {% set pa_fb = defaults.asa %}
{% elif material == "TPU" %} {% set pa_fb = defaults.tpu %}
{% elif material == "PC" %} {% set pa_fb = defaults.pc %}
{% elif material in ["PA", "NYLON", "PA-CF"] %} {% set pa_fb = defaults.pa_nylon %}
{% else %} {% set pa_fb = defaults.default %}
{% endif %}
SET_PRESSURE_ADVANCE EXTRUDER={extruder} ADVANCE={pa_fb}
{% endif %}
Then call it from the toolchange and print-start hooks:
[gcode_macro POST_TOOL_CHANGE]
gcode:
{% set t = printer.toolhead.extruder|replace("extruder","")|default("0") %}
{% set t = (t or "0")|int %}
NFC_APPLY_PA_TOOL T={t}
[gcode_macro PRINT_START]
gcode:
# …homing, levelling, heat soak…
{% for t in range(5) %}
NFC_APPLY_PA_TOOL T={t}
{% endfor %}
# …prime line, first layer…
What can go wrong, and where the NFC stack helps¶
| Failure mode | Without NFC | With NFC stack |
|---|---|---|
| Tool 3 is loaded with PETG, you forget to update slicer | Underextrusion / blobs from wrong PA + temp | Last-scanned spool's PA/temp applied automatically; mismatch shows in Mainsail preset name |
| Re-running a print after physically swapping a spool | Slicer-baked temps used (potentially wrong) | If M109/M190 are removed from slicer start gcode and replaced by nfc_t{N}_*-driven equivalents in PRINT_START, the right temps follow the spool |
| Pressure advance tuned per spool in Spoolman | Operator has to remember to copy values around | Spoolman → daemon → nfc_t{N}_pressure_advance → POST_TOOL_CHANGE |
Known issue: Y clearance on close approach¶
Warning
With the current dock spacing, the close_y clearance in some
toolchange macro variants is too small — tools can clip adjacent
docks during the parking approach. Increase close_y in the
toolchanger config until clearance is comfortable, then re-tune
each tool's dock position. Pending fix in this fleet.