Klipper-MMU splits the work between the Klipper host and the MMU's own microcontroller. The host chooses what to do; the MCU decides when, every millisecond, from its own sensors. You do not need this page to load filament, but it explains what the unit saw when it stopped, and why it behaves as it does.
The host (Klipper, OpenAMS and the klipper_mmu host module) chooses the lane, the spool and the tool, pauses the printer and hands off to it, keeps your calibration and restores it at every restart, and turns firmware events into messages you can act on.
The MCU (Klipper-MMU in the MMU board's firmware) decides whether an operation may start, owns every motor output and sensor reading, ramps the motors, follows the buffer, detects arrival, checks that its sensor readings are fresh, and stops everything on a fault or when the host goes silent.
The host can ask for an operation; it cannot move a motor directly. The MCU refuses what it cannot do: an operation that needs a sensor the unit does not have is refused, and a missing sensor is never assumed to have said something.
The add-on runs inside Klipper's own firmware. It uses Klipper's scheduler, transport and peripheral drivers, plus a few narrow driver extensions. One shared operation core, the same code in the tests and the simulator, runs every device:
While printing, the extruder pulls filament at whatever speed the print needs and does not tell the unit. The buffer between them reads from 0 (relaxed) to 1000 (fully compressed), and the unit keeps it near 500.
| Buffer | How the unit follows it |
|---|---|
| Switched (two switches) | Like a thermostat: one switch means feed, the other means stop, neither means keep doing the same. |
| Tension-only (one switch, QIDI Box) | The switch means feed; without it the reading is the middle. A missing compression switch is never assumed. |
| Analog (OpenAMS FPS, DiffA/DiffB) | Proportional: the further the reading is from 500, the more the feed speed changes, with a small deadband around the middle. |
Fully compressed while following means the toolhead stopped taking filament or the path is blocked: the unit stops and reports it, and does not push harder. On units with a filament encoder (ERCF), 10 mm of gear travel with no encoder click means a clog or a slip. The rule is distance, not time, so it works at any print speed.
During a load the tip reaches the extruder's gears, which are not turning yet, so the buffer compresses. Three readings in a row past 700 mean arrival; one reading could be a bump or noise. Once KLIPPER_MMU_CALIBRATE has measured the Bowden tube, arrival must also fall within a window around that length (±50 mm on BoxTurtle): earlier means an obstruction, later means slipping or a loose tube. Units without an analog buffer end the load on a toolhead switch wired to their own board.
A load is the one place the unit retries by plan: up to three attempts within a fixed time budget, each starting by backing off to a known point. If all three fail, it stops and reports each one.
The MCU may move motors only while the host keeps sending a heartbeat, and each one renews a lease. After 2 s without one, the lease expires and the MCU stops everything, mid-move if necessary. Silence usually means Klipper crashed, restarted or is overloaded, or a cable came out. Inside the MCU, the part that decides speeds must also check in with the part that queues steps every few milliseconds, or the motor outputs stop.
A driver error, an impossible switch reading, a fully compressed buffer, a missed deadline: the response is always the same. Motor outputs off, fault recorded, printer pause requested. The unit does not retry by itself or clear a fault after a timeout, because after a sudden stop nobody knows for certain where the filament is.
Acknowledging a fault (KLIPPER_MMU_ACK_FAULT) only records that you have seen it. It needs a fresh capture of the unit's state that matches the fault, and it does not clear the fault or give motion back. The unit moves again only after you state what is physically in the shared path with KLIPPER_MMU_RECONCILE_PATH. An emergency stop leaves the position uncertain, so it needs the same reconciliation. The recovery order lists the steps.
Selectors follow the same caution: a selector that lost its position, after startup, a fault or motors off, homes before its next selection, and it never moves with filament in the shared path.
The safe image has the same wiring, startup and sensors as the motion image and runs every check, but actuator START is refused: it advertises ACTUATION=0, so no setting or command can start a motor. Use it for the first power-on, and whenever you want to check wiring with nothing able to move.
Configuration is Klipper's own make menuconfig: pick the MCU first, enable the add-on, then choose a device profile and edit pins, polarity, pulls and optional features. A profile supplies defaults, not a board lock. Current sensing, an encoder and a LOAD switch are optional additions; without them, a configured motor current is never treated as a measurement, and no sensor change is invented. A screen on the device and BLDC motor control are not built yet.
The firmware runs in a whole-system simulation with the real Klipper and OpenAMS on top: loads, unloads, preloads, ejects, calibration and deliberately broken hardware. The simulator derives switch and buffer readings from simulated filament motion, and keeps synthetic data apart from measurements. It cannot tell how much torque your motor has at speed, whether it brakes without losing steps, how noisy your cables are, or how strong your buffer's magnet is.
Qualified means a person has watched it work on a real unit many times and measured how it stops. Until then, trust the logic, not the physics, and watch your first loads.