Assemblage du changeur d’outils Starlex : un parcours de programmation avec Klipper

Que se passe-t-il lorsque vous décidez de construire une imprimante 3D à 12 outils et que le matériel ne cesse d’évoluer sous vos yeux ? Vous écrivez de nombreuses macros Klipper. Voici le récit des défis de programmation que nous avons relevés en cours de route, à quoi ressemble le système actuel et où nous allons maintenant que le matériel s’est enfin stabilisé.

Qu’est-ce que le changeur d’outils Starlex ?

Le STC — le changeur d’outils Starlex de Swiss3dc — est un système de changement d’outils « léger » destiné aux imprimantes 3D basées sur Klipper. Ce terme « léger » constitue la principale différence par rapport à un changeur d’outils classique.

Dans un changeur d’outils complet (comme les architectures E3D ou Prusa XL), chaque outil est une tête d’impression complète et autonome : il dispose de son propre moteur pas à pas d’extrusion, de sa tête d’impression, de son élément chauffant, de sa thermistance et de son ventilateur de refroidissement. Changer d’outil revient donc à remplacer l’ensemble du système d’entraînement et de chauffage. Cela garantit une indépendance maximale entre les outils, mais alourdit considérablement chacun d’entre eux et augmente leur coût ainsi que leur complexité mécanique.

Le Starlex adopte une approche différente. Chaque outil n’est qu’un ensemble de hotend — un bloc chauffant, une thermistance, une buse et un ventilateur de refroidissement. Il n’y a pas de moteur pas à pas d’extrudeuse par outil. À la place, un seul moteur pas à pas d’extrudeuse partagé est monté sur le chariot (sur la carte de tête d’outil EBB36), et le mécanisme à came le couple physiquement à l’outil actuellement enclenché. Lorsque le chariot saisit un outil, l’accouplement s’engage dans le chemin du filament ; lorsqu’il repose l’outil sur le support, l’accouplement se désengage. Le moteur d’extrusion reste toujours sur le chariot.

Cela permet de réduire la masse et le coût des outils — ce sont les hotends que l’on range, et non les têtes d’impression — tout en garantissant une véritable isolation thermique par matériau, l’absence de contamination croisée entre les matériaux et des décalages Z indépendants pour chaque outil. En contrepartie, l’alignement entre le dispositif d’accouplement et le chemin du filament doit fonctionner de manière fiable sur les 12 emplacements, ce qui constitue le principal défi technique.

Notre système gère 12 outils. Ce nombre a guidé la quasi-totalité de nos choix logiciels.

La pile matérielle

Avant d’aborder la programmation, il est utile de comprendre avec quoi le logiciel doit communiquer. La machine repose sur un BIGTREETECH Manta M8P V2.0 comme microcontrôleur principal, exécutant le firmware Klipper sur un hôte Raspberry Pi. Un portique CoreXY gère les mouvements XY ; trois vis Z indépendantes assurent le nivellement du plateau. Le porte-outils est situé à l’avant gauche du volume d’impression et est actionné par un mécanisme à came monté sur un moteur pas à pas à réducteur planétaire : la rotation de la came soulève ou abaisse une barre d’accouplement qui verrouille ou déverrouille la tête d’outil sur le chariot.

Raspberry Pi Klipper · Moonraker · KlipperScreen USB / UART Manta M8P V2.0 · STM32H723 X / Y / Z₀ / Z₁ / Z₂ steppers · Bed heater · Tool rack cam stepper Y endstop · BDsensor Z probe (virtual endstop) CAN bus USB USB EBB36 GEN2 STM32G0B1 · CAN bus ▸ BDsensor (I²C on PA6/PA7) ▸ Shared extruder stepper ▸ X endstop ▸ Carriage cooling fan ▸ Filament path (all tools) ReHeat A0 · Board 0 RP2354B · Tools T0 – T5 ▸ 6 heater outputs (GPIO 0–5) ▸ 6 fan outputs (GPIO 6–11) ▸ 6 thermistor inputs (GPIO 40–45) ▸ 6 park detection endstops ▸ 6 filament runout sensors ReHeat A0 · Board 1 RP2354B · Tools T6 – T11 ▸ 6 heater outputs (GPIO 0–5) ▸ 6 fan outputs (GPIO 6–11) ▸ 6 thermistor inputs (GPIO 40–45) ▸ 6 park detection endstops ▸ 6 filament runout sensors

Figure 1 — Hiérarchie de communication du matériel. Le Manta M8P est le microcontrôleur central ; la carte de la tête d’outil EBB36 communique via CAN, tandis que deux cartes d’extension ReHeat A0 se connectent par USB et gèrent collectivement les 12 éléments chauffants, ventilateurs, thermistances et capteurs des outils.

Chaque outil dispose de manière indépendante d’un élément chauffant, d’une thermistance, d’un ventilateur de refroidissement, d’une butée de détection de position de repos et d’un capteur de fin de filament. Cela représente au total 60 signaux indépendants répartis sur les 12 outils, ce qui explique l’existence même des cartes d’extension ReHeat A0 — et pourquoi elles méritent d’être présentées.

La ReHeat A0 est une carte prototype que nous avons développée en collaboration avec Intelligent Agent, la société norvégienne à l’origine de la carte de contrôle de l’imprimante 3D Recore. Le problème que nous leur avons soumis concernait spécifiquement le changement rapide d’outils : lorsque chaque outil n’est qu’un ensemble de hotend plutôt qu’une tête d’impression complète, il est en réalité possible d’utiliser bien plus d’outils que ce pour quoi n’importe quel matériel d’extension existant a été conçu. Les cartes de tête d’impression standard partent du principe d’une carte par outil. Nous avions besoin d’une carte pour six outils. La ReHeat A0 — six sorties de chauffage, six sorties de ventilateur, six entrées de thermistance, douze entrées de butée, le tout sur un microcontrôleur RP2354B avec USB-C et prise en charge native de Klipper — a été conçue à partir de zéro pour combler cette lacune. C’est le résultat direct des possibilités offertes par ce type d’architecture de changement d’outils allégée.

Début ad hoc : pourquoi des macros personnalisées en premier lieu

Au début de ce projet, nous disposions de deux outils. Puis quatre. Puis douze. La conception du mécanisme à cames a évolué. L’emplacement de l’électronique des éléments chauffants a changé — passant de la carte principale à la carte de la tête d’outil, puis à des cartes d’extension dédiées. Nous mettions au point le couplage mécanique, la géométrie du chemin du filament et l’espacement des fentes tout en écrivant le code de configuration.

Le langage de macros et de configuration de Klipper est étonnamment expressif pour un fichier de configuration : templates Jinja2 complets, accès au dictionnaire complet de l’état de l’imprimante, variables nommées, exécution différée du G-code et enchaînement arbitraire de commandes G-code. Il permet de construire un changeur d’outils fonctionnel à partir de zéro sans toucher au C++ — et, plus important encore, de le modifier à nouveau dès demain si le matériel se comporte de manière inattendue.

Nous avons donc tout écrit sur mesure : macros T-command, suivi de l’état des outils, contrôle du rack, gestion des ventilateurs, persistance des décalages… tout. C’était le bon choix. Mais avant d’expliquer pourquoi, voyons ce que nous devions réellement résoudre.


1 Le conflit de broches du BDsensor

Le BDsensor est un palpeur Z capacitif qui communique via I²C. L’emplacement logique pour le connecter sur l’EBB36 était lePROBEport — broche PB8. Cela a failli fonctionner. Le problème : ce port comporte un optocoupleur placé sur la ligne SDA, initialement destinée aux signaux de fin de course traditionnels, et cet optocoupleur limite le signal SDA d’une manière qui perturbe la communication I²C. Le capteur s’initialisait, mais renvoyait des mesures erronées.

La solution a consisté à trouver un véritable bus I²C sur l’EBB36. Les broches PA6 et PA7 sont reliées à un périphérique I²C matériel sans optocoupleur sur le chemin du signal :

# Don't use aliases for the board pins — use the raw I²C port
[BDsensor]
sda_pin: ^EBB36:PA6
scl_pin: EBB36:PA7
delay: 10
homing_cmd: G990028  # required when G28 is redefined

Lahoming_cmd: G990028ligne est une exigence moins évidente : lorsque vous redéfinissezG28 avec rename_existing, la séquence d’auto-étalonnage interne du capteur BD doit savoir quel G-code appeler pour le retour à l’origine. Sans cela, l’étalonnage déclenche la macro d’encapsulation et non la commande de base G28.1, ce qui provoque une boucle.


2 Le mécanisme à came du porte-outils

Le porte-outils est une barre linéaire qui traverse l’avant de la machine. Chaque outil se range dans son emplacement ; lorsque le chariot s’approche d’un emplacement et que la came tourne, une barre d’accouplement soulève et verrouille l’outil sur le chariot (ou l’abaisse et le relâche vers le porte-outils).

La came est entraînée par un moteur pas à pas équipé d’un réducteur planétaire 5:1, configuré dans Klipper en tant que manual_stepper« moteur pas à pas manuel » : cela signifie que Klipper n’inclut pas cet axe dans la planification normale des mouvements — nous le pilotons explicitement à l’aide deMANUAL_STEPPERcommandes :

[manual_stepper tool_rack]
step_pin: PG9
dir_pin: PD7
enable_pin: !PG11
rotation_distance: 2      # 1 full cam rotation = 2mm virtual travel
gear_ratio: 5:1
microsteps: 4
velocity: 5
accel: 100
endstop_pin: ^!PF3

Ce qui est intéressant, c’est la manière dont nous synchronisons la came avec le moteur de l’extrudeuse lors de la prise en charge. Le mécanisme d’accouplement fonctionne mieux lorsque l’extrudeuse tourne également légèrement au moment où la came s’enclenche — cela aide à aligner le trajet du filament. Nous avons utilisé le paramètre non standardGCODE_AXIS=R de Klipper sur le moteur pas à pas manuel pour mapper temporairement la came à crémaillère à un axe « R » virtuel, puis nous avons émis des mouvements G1 multiaxes qui actionnaient simultanément les axes X (oscillation), E (amorçage de l’extrudeuse) et R (rotation de la came) :

# Temporarily expose cam as R axis so G1 can move all three in sync
MANUAL_STEPPER STEPPER=tool_rack GCODE_AXIS=R LIMIT_VELOCITY=20 LIMIT_ACCEL=100
G1 X0.1  E0.667 R0.667 F100   # jiggle right, prime, cam rotate down
G1 X-0.2 E0.333 R0.333 F100
G1 X0.1  E0.500 R-0.5  F100   # jiggle back, cam back up
G1       E0.500 R0.5   F100
G1       E0.180 R0.18  F100
MANUAL_STEPPER STEPPER=tool_rack GCODE_AXIS=   # detach R axis

Cette « séquence de vibration » a été mise au point de manière empirique au fil de nombreuses tentatives d’accouplement. La légère oscillation de l’axe X facilite la mise en place correcte de l’accouplement mécanique tandis que l’extrudeuse précharge le chemin du filament. L’astuce de l’axe R ne modifie en rien la couche définie par KlipperToolGcodeTransform, ce qui s’avère important dès lors que l’on ajoute des décalages d’outils à l’équation.


3 Douze éléments chauffants dans un seul langage de configuration

La configuration de Klipper n’est pas un langage de programmation. En revanche, les modèles Jinja2 intégrés aux macros G-code constituent un langage de programmation, et la frontière entre les deux crée des frictions lorsque l’on doit effectuer des opérations de manière dynamique.

Le défi fondamental : l’outil 0 utilise le[extruder] réchauffeur (une section Klipper spéciale dotée de son propre espace de noms), tandis que les outils 1 à 11 utilisent[heater_generic toolN_heater]des sections. Il est impossible d’écrire une expression unique qui gère les deux de manière transparente sans connaître au préalable le numéro de l’outil.

Dans les macros, Klipper expose l’état du chauffage via leprinter dictionnaire.printer.extruder.temperature fonctionne pour T0. Pour T1 à T11, nous avions besoin d’une recherche par clé de type chaîne de caractères :

# Dynamic heater name construction in Jinja2
{% set hname = "heater_generic tool" ~ tool_num ~ "_heater" %}
{% set temp   = printer[hname].temperature | default(0) %}
{% set target = printer[hname].target     | default(0) %}

Le| default(0)filtre est essentiel. Si une section « heater » n’est pas définie (parce que nous n’avons pas encore câblé T5, par exemple),printer["heater_generic tool5_heater"]la fonction renvoie un dictionnaire vide plutôt que de lever une erreur. Le filtre par défaut lui permet de renvoyer zéro en toute sécurité au lieu de provoquer le plantage de la macro.

Ce modèle apparaît à trois endroits différents : les remplacements de routage M104/M109, la vérification du ventilateur du chariot et la logique de mise à jour du ventilateur en veille. Une erreur dans l’un d’entre eux entraînait soit un ventilateur qui restait éteint alors qu’il aurait dû être allumé, soit une erreur Klipper provoquant le plantage de la macro en cours d’impression.


4 Le problème de gestion des ventilateurs

Un changeur d’outils comporte deux types de ventilateurs distincts qui nécessitent une logique de contrôle totalement différente :

  • Ventilateur du chariot — refroidit la tête d’impression active. Doit être activé dès que le chauffage de l’outil actif dépasse 50 °C ou présente une valeur cible non nulle.
  • Ventilateurs de stockage — refroidissent les têtes d’outils rangées dans le rack. Ils doivent être activés lorsque le chauffage d’un outil stocké est chaud, mais PAS lorsque cet outil se trouve actuellement sur le chariot (car le ventilateur du chariot s’en charge et que la géométrie des ventilateurs de stockage n’atteint de toute façon pas la position active).

Douze outils, un ventilateur par paire de deux outils, ce qui fait 6 ventilateurs de stockage. La logique de mise en marche/arrêt de chaque ventilateur devient alors la suivante :

Le ventilateur T(N)+T(N+1) est activé si : (T(N) est chaud ET T(N) n’est pas l’outil actif) OU (T(N+1) est chaud ET T(N+1) n’est pas l’outil actif)

Nous avons implémenté cela sous la forme_UPDATE_PARKED_FANSde — une macro qui lit l’état des 12 réchauffeurs (à l’aide de la recherche dynamique décrite ci-dessus) et émetSET_FAN_SPEEDles commandes en conséquence. Celle-ci s’exécute une fois au démarrage, une fois après chaque changement d’outil, et dans une boucle temporisée de 2 secondes :

[delayed_gcode CARRIAGE_FAN_LOOP]
initial_duration: 2
gcode:
    _CARRIAGE_FAN_CHECK
    UPDATE_DELAYED_GCODE ID=CARRIAGE_FAN_LOOP DURATION=2

Une précision importante concernant la sécurité : tous les ventilateurs en veille sont déclarés avec shutdown_speed: 1. Si Klipper plante ou s’arrête dans un état d’erreur, les ventilateurs s’accélèrent automatiquement à pleine vitesse. Les têtes d’outils en veille qui étaient chaudes au moment du plantage de Klipper sont refroidies au lieu de surchauffer.


5 Décalages d’outils et persistance de l’état

Chaque outil présente une géométrie de buse légèrement différente, et les tolérances de montage font que chacun se trouve à une position X, Y et Z légèrement différente par rapport au point d’origine de la machine. Nous enregistrons les décalages propres à chaque outil que Klipper applique à toutes les coordonnées de déplacement ultérieures après un changement d’outil.

Les décalages sont stockés dans saved_variables.cfg, un fichier natif de Klipper qui persiste d’un redémarrage à l’autre :

[save_variables]
filename: ~/printer_data/config/saved_variables.cfg

# In the variables file:
[Variables]
tool_offset_t0 = [0.0, 0.0, 0.3]
tool_offset_t1 = [-1.0, -0.5, 0.1]
tool_offset_t2 = [-0.4, 0.0, 0.4]

Le processus de calibrage de l’axe Z est délibérément simple : une fois l’outil sélectionné, l’utilisateur abaisse l’axe Z par petits pas jusqu’à ce qu’un test sur papier donne un résultat satisfaisant, puis appelle la macro SAVE_TOOL_Z_OFFSET. Cette macro litprinter.gcode_move.gcode_position.z — la position actuelle dans l’espace G-code — et la réécrit dans le fichier de sauvegarde.

La persistance de l’état après les redémarrages était gérée par unRESTORE_TOOL_ON_BOOT G-code différé qui se déclenche 3 secondes après le démarrage de Klipper, lit le dernier numéro d’outil actif dans saved_variables.cfg, et réapplique ses décalages. Cela évite qu’en cas de redémarrage de la machine en cours d’impression, celle-ci perde la trace des décalages actifs.


6 Acheminement des commandes M104 et M109 vers le chauffage de droite

M104Les logiciels de découpage émettent des commandes standardM104 T1 S215 (réglage de la température du chauffage, outil 1, 215 °C) etM109 T0 S210 (attente de la température). Ces commandes supposent un micrologiciel qui prend en charge nativement plusieurs indices d’extrudeuse. L’implémentationM109 de Klipper ne communique qu’avec la[extruder]section .

La solution consiste à intercepter ces commandes à l’aide du mécanisme derename_existing Klipper :

[gcode_macro M104]
rename_existing: M104.1
gcode:
    {% set s = params.S | default(0) | float %}
    {% set t = params.T | default(-1) | int %}
    {% if t == -1 or t == 0 %}
        M104.1 S{s}                               # route to [extruder]
    {% elif t >= 1 and t <= 11 %}
        SET_HEATER_TEMPERATURE HEATER={"tool" ~ t ~ "_heater"} TARGET={s}
    {% endif %}
    _CARRIAGE_FAN_CHECK
    _UPDATE_PARKED_FANS

Les vérifications du ventilateur sont appelées à l’intérieur de la commande M104 afin que l’état du ventilateur soit mis à jour immédiatement lorsqu’une température cible est définie — même si cela se produit pendant une attente de température qui bloque la file d’attente principale. Le même principe s’applique à notreSET_HEATER_TEMPERATURE surtension, de sorte que tout chemin modifiant la température cible d’un élément chauffant déclenche également une mise à jour du ventilateur.

La version M109 (attente bloquante) achemine le cas T=0 versM109.1 et le cas T=1–11 vers TEMPERATURE_WAIT SENSOR="heater_generic toolN_heater":

{% elif t >= 1 and t <= 11 %}
    SET_HEATER_TEMPERATURE HEATER={"tool" ~ t ~ "_heater"} TARGET={s}
    _CARRIAGE_FAN_CHECK
    _UPDATE_PARKED_FANS
    TEMPERATURE_WAIT SENSOR={"heater_generic tool" ~ t ~ "_heater"} MINIMUM={s - 2}

LeMINIMUM={s - 2} offre une marge d’arrivée de 2 °C, ce qui évite les attentes indéfinies dues à un léger dépassement du thermostat tout en garantissant que le chauffage ait effectivement atteint la température requise avant le début de l’impression.


7 Nivellement par inclinaison Z avec changeur d’outils

La machine utilise trois vis Z indépendantes etZ_TILT_ADJUST pour maintenir le plateau à niveau. La sonde BDsensor se trouve sur le chariot ; le nivellement nécessite donc de se déplacer sur le plateau et de sonder plusieurs points. Le problème : les décalages d’outil appliqués aux coordonnées G-code fausseraient les calculs de position de la sonde.

La solution consiste à toujours exécuterZ_TILT_ADJUST sans aucun décalage d’outil actif. Nous l’avons encapsulé :

[gcode_macro Z_TILT_ADJUST]
rename_existing: _Z_TILT_ADJUST
gcode:
    {% set saved_tool = printer["gcode_macro TOOL_VARS"].current_tool | int %}
    {% if saved_tool != -1 %}
        UNLOAD_TOOL                       # returns tool to rack, clears offsets
    {% endif %}
    _Z_TILT_ADJUST {rawparams}
    {% if saved_tool != -1 %}
        LOAD_TOOL TOOL={saved_tool}       # reloads from rack, reapplies offsets
    {% endif %}

En pratique,PRINT_START décharge explicitement l’outil avant d’appelerZ_TILT_ADJUST de toute façon. Mais cette fonction d’encapsulation offre une sécurité supplémentaire pour les opérations de mise à niveau manuelles depuis KlipperScreen, où un outil pourrait déjà être chargé.


8 Fin de filament dans un système multi-outils

Chaque outil dispose d’un capteur de fin de filament indépendant. Lapause_on_runout: Truefonction native de Klipper déclencherait une PAUSE pour tout capteur qui se déclenche — y compris les 11 outils stationnés qui ne comportent aucun filament. C’est manifestement une erreur.

La solution consiste en une macro de filtrage qui n’agit que sur les événements de fin de filament provenant de l’outil actuellement actif :

[filament_switch_sensor tool0_runout]
switch_pin: ^reheat0:GPIO24
pause_on_runout: False
runout_gcode: _FILAMENT_RUNOUT_GATE TOOL=0

[gcode_macro _FILAMENT_RUNOUT_GATE]
gcode:
    {% set sensor_tool = params.TOOL | int %}
    {% set active_tool = printer["gcode_macro TOOL_VARS"].current_tool | int %}
    {% if sensor_tool == active_tool %}
        PAUSE
    {% endif %}

Les 12 capteurs disposent depause_on_runout: False et appellent_FILAMENT_RUNOUT_GATE avec leur numéro d’outil. La macro compare cette valeur à celle de l’outil actif suivi et ne met en pause que lorsqu’elles correspondent.


La séquence de changement d’outil

Tous ces éléments s’assemblent pour former une séquence de changement d’outil chorégraphiée. ChaqueT{N}commande suit le même chemin :

T{N} command issued Pre-change Clear gcode offsets to zero · Z hop +5 mm (if tool mounted) Dropoff (only if a tool is currently mounted) ① Move carriage to slot X, approach Y · retract filament ② TOOL_RACK_DOWN — cam lowers, decouples tool from carriage ③ Move carriage to engage Y — push tool fully into rack slot ④ TOOL_RACK_UP — cam rises, tool is locked to rack ⑤ Retract to approach Y — carriage clears the rack Pickup ① Move carriage to new slot X, approach Y ② TOOL_RACK_UP — cam lifts coupling bar to receive tool ③ Move to engage Y — carriage docks with tool ④ Jiggle sequence — coordinated X ± 0.1 mm + E + R cam moves ⑤ TOOL_RACK_DOWN — cam lowers, locks tool onto carriage ⑥ Prime filament · retract to approach Y · carriage clears rack Post-change Z restore −5 mm · update all fans · apply new tool XYZ offsets Restore carriage to pre-change XY position Print resumes guarded by {% if tool %}

Figure 2 — Séquence de changement d’outil. Le saut en Z lors de l’étape préalable au changement est conditionné : il ne se déclenche que si un outil est actuellement monté, car lors de la toute première sélection d’outil au début de l’impression, il n’y a rien à franchir.

Architecture de la configuration actuelle

La configuration de travail est répartie sur plusieurs fichiers, chacun ayant des responsabilités clairement délimitées :

printer.cfg — MCU pins, stepper config, BDsensor, Z tilt points, printer kinematics includes: ebb36.cfg · macros.cfg · tools.cfg ebb36.cfg Extruder motor pins X endstop Carriage fan · TMC driver macros.cfg T0 – T11 gcode macros PRINT_START · PRINT_END M104 / M109 overrides Z_TILT_ADJUST wrapper MEASURE / SAVE offsets tools.cfg TOOL_VARS — state tracking macro Extruder heater / sensor (M8P pins) heater_generic tool1..11_heater Parked fans / carriage fan LOAD_TOOL / UNLOAD_TOOL HOME_TOOL_RACK · rack macros Fan update loops · runout gate saved_variables.cfg Current active tool number Per-tool X / Y / Z offsets (T0–T11) KlipperScreen.conf Custom tool-change menu (T0–T11 buttons) Load / Unload filament · Home · Reset tool state

Figure 3 — Architecture de configuration actuelle (« figée »). Le fichier saved_variables.cfg constitue la couche de persistance pour l’état des outils et les décalages ; tout le reste relève exclusivement de la configuration Klipper et des macros.


Pourquoi l’approche ad hoc était la bonne stratégie

Avec le recul, tout écrire à partir de zéro s’est avéré être la bonne approche pour cette phase du projet. Voici pourquoi.

Le matériel et le logiciel ont évolué de concert. À nos débuts, la caméra du rack d’outils avait une conception différente. L’électronique du système de chauffage a été déplacée de la carte mère vers l’EBB36, puis vers des cartes d’extension ReHeat dédiées. Le nombre d’outils est passé de 2 à 12. L’espacement des emplacements a changé. Tout framework adopté dès le départ aurait nécessité une réadaptation continue à mesure que la réalité physique évoluait — probablement à chaque révision. Les macros personnalisées sont faciles à modifier.

Le débogage du matériel est plus simple sans les abstractions d’un framework. Lorsqu’un accouplement ne s’enclenche pas, qu’une thermistance affiche 400 °C ou que la came dépasse la limite, il faut voir exactement ce que le micrologiciel indique au matériel. Avec les macros personnalisées, vous pouvezaction_respond_info(), depuis n’importe où, ajouter un journalisation temporaire à n’importe quelle étape et modifier la séquence sans avoir à comprendre le fonctionnement interne d’un plugin. Cela s’est avéré inestimable pendant le développement mécanique.

L’étalonnage itératif exigeait un contrôle total. Trouver la bonne séquence de secousses, les bonnes positions X des fentes, la bonne vitesse de la came, la bonne distance de rétraction du filament — tout cela a été réglé empiriquement au fil de nombreuses tentatives de changement d’outil. Un langage de configuration où chaque paramètre est directement accessible dans le fichier de configuration (et non enfoui dans le code du plugin) a permis d’accélérer cette itération.

Cela a permis d’acquérir une compréhension approfondie. Chaque particularité du pipeline de transformation G-code de Klipper, de l’ordre d’exécution des macros et des conventions de nommage des éléments chauffants a été rencontrée, déboguée et comprise de première main. Cette compréhension guide désormais directement la manière dont nous mettons en œuvre la migration des plugins — et nous indique les cas limites à surveiller.

La configuration de référence figée (2026-06-02/config/) est exactement cela : un instantané validé de ce qui fonctionne à la pleine capacité du matériel. Elle sert de référence de référence à mesure que nous construisons la nouvelle architecture en parallèle.


La voie à suivre : le plugin klipper-toolchanger

Maintenant que le matériel s’est stabilisé — le mécanisme à came a fait ses preuves, la géométrie des fentes est fixée, les cartes ReHeat sont définies —, la charge de maintenance liée à l’approche personnalisée devient son principal inconvénient. Chaque utilisateur qui construit cette machine doit comprendre le système de macros à partir de zéro. Chaque mise à jour de Klipper risque de perturber subtilement le fonctionnement des macros T-command personnalisées. Le code est intrinsèquement spécifique à cette machine.

Le plugin klipper-toolchanger de Viesturz fournit un framework de changement d’outils spécialement conçu pour Klipper qui résout les mêmes problèmes que ceux que nous avons résolus manuellement, mais d’une manière que la communauté au sens large peut maintenir. Principales fonctionnalités répondant à nos besoins :

  • T0Définitions déclaratives des outils — chaque[tool T0] section, de à[tool T11] , comporte ses propres décalages, sa référence de chauffage, sa broche de détection et la position X de l’emplacement. Le plugin les enregistre automatiquement sousT11 forme de commandes G-code.
  • ToolGcodeTransform — le plugin gère le pipeline de décalages G-code. Le G-code de prise en charge et de dépose s’exécute dans un espace sans décalage (les coordonnées du rack sont donc toujours absolues), puis les décalages sont appliqués une fois le changement terminé.
  • save_current_tool: True — la restauration de l’état au démarrage est intégrée, remplaçant notreRESTORE_TOOL_ON_BOOT G-code différé.
  • initialize_on : home — le changeur d’outils s’initialise automatiquement sur G28, aucun appel séparé n’est nécessaire depuis PRINT_START.
  • t_command_restore_axis : XY — le plugin restaure automatiquement la position XY d’avant le changement après chaque changement d’outil ; il ne nous reste plus qu’à gérer l’axe Z nous-mêmes via les hooks « before » et « after ».

Nouvelle architecture

klipper-toolchanger plugin T0–T11 commands · ToolGcodeTransform · save_current_tool · initialize_on: home printer.cfg MCU config · stepper pins · BDsensor · Z tilt · reheat0 / reheat1 MCU stubs includes: ebb36.cfg · toolchanger.cfg · macros.cfg · tools.cfg toolchanger.cfg ← NEW [toolchanger] motion params · before/after/pickup/dropoff gcode [tool T0] – [tool T11] offsets · detection_pin · slot X [heater_generic tool1..11_heater] on ReHeat boards [fan_generic parked_fan_t*] on ReHeat boards · shutdown_speed: 1 [filament_switch_sensor tool*_filament] on ReHeat boards T0 extruder heater/sensor → reheat0:GPIO0 / GPIO40 T6–T11 detection pins → reheat1:GPIO18–23 tools.cfg Extruder motor (EBB36) manual_stepper tool_rack HOME_TOOL_RACK TOOL_RACK_UP/DOWN _CARRIAGE_FAN_CHECK _UPDATE_PARKED_FANS SAVE_TOOL_Z_OFFSET macros.cfg PRINT_START/END M104 / M109 Z_TILT_ADJUST No T0–T11 macros (plugin registers them automatically) Tool offsets persisted by plugin SET_TOOL_PARAMETER + SAVE_TOOL_PARAMETER write to saved_variables.cfg · save_current_tool: True handles boot-time restore No separate RESTORE_TOOL_ON_BOOT delayed_gcode needed

Figure 4 — Nouvelle architecture avec le plugin klipper-toolchanger. Les macros T0–T11 disparaissent complètement ; le plugin enregistre ces commandes. Toolchanger.cfg est le nouveau centre de configuration pour toutes les données propres à chaque outil et les séquences de changement.

T0La principale différence structurelle réside dans la disparition des macros G-codeT11 personnalisées, de laTOOL_VARS macro de suivi d’état, LOAD_TOOL, UNLOAD_TOOL,RESET_TOOL_STATE , etRESTORE_TOOL_ON_BOOT . Le plugin fournit des fonctionnalités équivalentes dans un cadre maintenu et testé. Ce qui reste, ce sont les connaissances spécifiques à la machine : les positions des emplacements, la séquence de vibration, les vitesses des cames, les valeurs de décalage — toutes ces informations que nous connaissons déjà grâce à la phase ad hoc.

La migration est développée parallèlement à la configuration figée dans untest_config/répertoire. Rien n’est envoyé à la machine tant que cela n’a pas été validé par rapport à la référence connue pour être correcte.


L’intérêt de commencer par mal faire les choses

Nous avons construit ce système de manière ad hoc parce que nous y étions contraints. Le matériel était en constante évolution, le nombre d’outils était incertain et la conception mécanique faisait l’objet d’itérations en parallèle avec le micrologiciel. Aucun cadre existant n’aurait pu survivre intact à tout cela.

Mais la phase ad hoc n’a pas été un effort vain : c’était la phase de recherche. Chaque problème résolu ci-dessus représente une contrainte réelle pour toute implémentation de changeur d’outils : le pipeline de décalage doit être remis à zéro avant l’exécution du G-code de prélèvement ; la came nécessite un mouvement synchronisé de l’extrudeuse pour se positionner correctement ; la logique de ventilation au repos nécessite un état thermique propre à chaque outil, avec une exclusion des outils actifs ; la fin de filament nécessite une couche de fermeture ; la commande M104 doit être acheminée vers différents backends de chauffage en fonction de l’index de l’outil. Ce ne sont pas des opinions. Ce sont des contraintes que nous avons découvertes en testant le matériel.

Nous savons désormais exactement ce que le plugin doit faire, et pourquoi, car nous l’avons déjà fait nous-mêmes. C’est là tout l’intérêt de commencer par se tromper.

Prochaines étapes

  • Installer les deux cartes ReHeat A0 et y raccorder les éléments chauffants T0–T11, les ventilateurs, les thermistances et les butées de fin de course
  • Installer le plugin klipper-toolchanger et le validertest_config/par rapport à la référence figée
  • Mettre en service les outils T3 à T11 (dont les décalages sont actuellement tous à zéro), un par un
  • Calibrer la distance d’amorçage du filament pour chaque outil au fur et à mesure de l’attribution des types de matériaux
  • Lancer les tests d'impression multi-matériaux avec le rack complet de 12 outils équipé

L’objectif a toujours été de disposer d’une machine capable de changer de matériau en cours d’impression sans intervention de l’opérateur et sans contamination croisée. Le matériel est prêt. L’architecture logicielle est prête. Il est désormais temps de procéder à des impressions réelles avec les douze outils.

Suivez nous
Newest Art:
SHOPPING BAG 0
RECENTLY VIEWED 0