Projects 3D Printing

PrintForge — Print Farm Automation

Software and hardware to run three 3D printers as a small farm: camera-based first-layer inspection, a job queue manager, and an auto-eject prototype for continuous printing.

Active since Oct 2025 #3d-printing#opencv#automation#raspberry-pi
3
Printers managed
94 %
First-layer detection accuracy
168
Jobs queued to date
45 s
Eject cycle time

Three printers sounds like one printer, three times. It isn’t. The moment I had more than one machine, the bottleneck stopped being print time and became me — starting jobs, checking first layers, pulling parts off beds. PrintForge exists to remove me from that loop.

Architecture

Each printer runs Klipper with Moonraker, and a Raspberry Pi 4 acts as the farm controller. A FastAPI service holds the job queue: you upload sliced G-code with metadata (material, bed size, estimated time), and the scheduler assigns it to the first idle printer whose bed fits the part. State flows back over Moonraker’s WebSocket API, so the dashboard shows all three machines without polling.

The scheduler is deliberately dumb — first-fit, no lookahead. I tried a smarter bin-packing pass early on and it saved about four minutes a day while doubling the code. Not worth it at three printers.

First-layer inspection

Each printer has a fixed overhead camera. Twenty seconds after the first layer finishes, the Pi grabs a frame, masks it against the expected part footprint (extracted from the G-code), and compares extruded area to expected area:

def first_layer_ok(frame: np.ndarray, footprint: np.ndarray) -> bool:
    mask = cv2.absdiff(frame, bed_reference)
    _, extruded = cv2.threshold(cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY),
                                THRESH, 255, cv2.THRESH_BINARY)
    coverage = np.sum(extruded & footprint) / np.sum(footprint)
    return coverage > 0.85

If coverage falls short, the printer pauses and I get a notification with the frame attached. Current accuracy is about 94% — the misses are mostly transparent PETG, which barely contrasts against the PEI sheet. Lesson learned: lighting matters more than the algorithm. Adding a fixed LED strip did more for accuracy than two weeks of tuning thresholds.

The eject mechanism

Continuous printing needs an empty bed. The prototype is a NEMA 17-driven sweep arm mounted behind one printer: the bed cools to 27 °C (parts release from PEI around there), the arm sweeps forward, and parts drop into a bin. The first arm design snapped its printed pivot on a well-adhered part — the fix was letting the bed cool longer, not making the arm stronger. A full eject cycle takes about 45 seconds, and the queue starts the next job automatically.

It only runs on one printer so far, and I still don’t trust it overnight with anything larger than a palm-sized part. That trust is the actual roadmap.

Development timeline

  1. 2025-10

    Queue manager

    First version scheduling jobs across two printers via the Moonraker API.

  2. 2025-12

    First-layer inspection

    OpenCV pipeline catching failed first layers from a fixed overhead camera.

  3. 2026-03

    Third printer online

    Added a printer with a different bed size, which forced real job-to-printer matching.

  4. 2026-06

    Auto-eject prototype

    Sweep arm cleared its first bed and queued the next print unattended.