I run a small print farm: two P1S with an AMS each, an A1 Combo, and an A1 mini. Three of those four printers already have an automatic filament system. I'm building another one anyway. The reason is a line near the top of its design docs: there's no official way to put 30 spools on a shelf and let any of them feed any of my printers.
What the stock units can't do
An AMS holds four spools. A P1S can take up to four AMS units through an AMS Hub, which gets one printer to 16. The A1 series takes one AMS lite, or up to four full AMS units through its own hub.
Sixteen is a lot of colours. The bigger limit for a farm is that every spool belongs to one printer. A spool in one P1S's AMS can't feed the other P1S, even when that printer is idle and the first one doesn't need it. The hub doesn't change that. It merges up to four AMS units into one printer's inlet and has no way to send filament the other direction. Two printers that run the same colour need two spools of it, loaded in two places.
What I want is closer to a switchboard: a bank of spools that any printer can draw from, with no fixed count. That's the long-term goal for AMS-X, and it's a long way off. The roadmap calls routing filament between printers a hard, separate problem and puts it last.
Decision one: leave the firmware alone
Every Bambu printer already knows how to do a manual filament change. Set the change-filament gcode to a pause, slice a multi-colour model, and the printer stops at each change, unloads, and waits for someone to push the next filament in. Then it loads, purges, wipes and carries on.
AMS-X doesn't fork firmware, emulate Bambu's AMS protocol, or write hotend gcode. It replaces the person standing at the printer. The printer keeps everything that depends on the nozzle and the material: temperature, retracting out of the melt zone, loading, purging. AMS-X keeps the logistics: which spool is next, pulling the old filament clear, and pushing the new one in until the printer's own filament sensor sees it.
The reason is calibration. Purge length and retraction are per-nozzle, per-material numbers, and the printer already has them right. If I wrote my own, I'd own that problem on every model I run. The cost is that I can only drive what the printer exposes on its local network, so the printers run in LAN mode and every swap goes at the printer's pace. Driving a Bambu Lab printer over MQTT covers that interface and which parts of it I've confirmed.
That decision also set the order of the work. Everything depended on the printer's unload, resume and filament sensor being reachable over MQTT, so the roadmap tests that first, from a laptop, with no hardware. The next step builds the whole loop with a human standing in for the motor: the server parses the sliced file, uploads it, starts the print, catches each pause, asks a person to swap, and resumes when the sensor trips. A motorized module plugs into the same interface later, and the orchestrator doesn't change.
Decision two: one motor at a time
Each spool sits in a module: a NEMA 17 stepper on a TMC2209 driver, pushing filament through a Bowden-style extruder. An ESP32 runs a cluster of modules and talks to the server over MQTT. The early docs planned one ESP32 per roughly 16 modules. The firmware settled on eight.
The rule that keeps the board simple is that only one module moves at a time. A filament change only needs one spool moving, so there's no reason to run two motors at once. That lets every driver in the cluster share the same STEP and DIR lines, with a separate enable pin per driver. Picking a spool means enabling one driver. Eight modules cost two shared pins plus eight enables, ten in total, against sixteen if each driver had its own STEP and DIR.
The enable is held only for the length of a move. Exactly one spool is ever energised, and that's guaranteed by the wiring rather than by the code getting it right. It keeps power small too: with one motor moving at a time, a 24 V, 5 A supply covers a cluster.
Pin numbers aren't compiled in either. The pin map arrives over MQTT, and the board refuses pins that would take it down, like the ones wired to its own flash, and reports a fault instead.
Where it actually is
- Server: the full loop runs. It parses the sliced 3MF, uploads over FTPS, starts the print, catches each pause, prompts a person to swap, and resumes when the printer's sensor trips. The printer side is confirmed on my A1 mini and P1S. It also tracks spools in Spoolman and runs against a built-in printer simulator, with 130+ tests.
- Firmware: about 900 lines of C++, on the bench with four motors, not eight. Loading works. Unloading doesn't: the module's own filament sensor isn't read yet, so an unload thinks it's already finished and the motor never turns.
- Not built: the motorized module on the server side, and the hub that merges modules into one printer.
- X1: untested. I don't have one.
- Sharing spools between printers: the goal, not something that runs.
What's next
Fixing unload comes first, because nothing swaps on its own until a module can pull filament back. After that, four spools swapping with no hand on them, then eight. Until then, AMS-X is a server that tells me when to swap spools.
The code is on GitHub under MIT: server and firmware. The firmware is covered in One ESP32, eight spools, two legs per filament move.
Top comments (0)