Maker tech hub — AI · 3D print · Pi · ESP32 · plus the classic tech archive.

Free ESP32 kit · AI tools directory · Books · Archive

Project · Advanced · Raspberry Pi

Simple Print Failure Hints with a Pi Camera

Baseline frames, not full ML — catch spaghetti early.

Written by

Avery J. Parker

IT veteran, maker educator, and author of Network Ninja, 3D Printing Mastery, and AI Workflow Mastery. Business IT: Diversified Tech Solutions.

Project template

  • Goal & materials
  • Steps / firmware
  • Troubleshooting
  • AI assist notes
  • Related gear & books

You do not need a machine learning model to catch many 3D print failures. A Raspberry Pi, a camera, and some simple image comparison can flag the big ones: spaghetti, a part knocked off the bed, or a print that stopped growing. This guide explains a baseline-frame approach, shows a starting script, and covers how to act on alerts without pausing good prints.

The idea

A healthy print changes in a predictable way: slowly, mostly in the area where the part is. Failures look different.

  • Spaghetti: large, messy changes spreading outside the part area.
  • Detached part: a sudden big change in the part area, often with the part moving.
  • Clog or stopped extrusion: almost no change over a long period while the printer reports it is printing.

By comparing each new frame with recent frames and watching how much changes and where, you can flag these cases with simple rules.

Hardware and setup

  • A Raspberry Pi 4 or 5 (a Pi Zero 2 W can capture, but image processing is slow).
  • A Raspberry Pi camera module, mounted rigidly so it does not move with the frame vibration.
  • Steady lighting. A small LED strip near the bed makes frame comparison far more reliable than room light that changes through the day.
  • Software: sudo apt install python3-picamera2 python3-opencv on Raspberry Pi OS.

Test the camera first with rpicam-still -o test.jpg (named libcamera-still on older OS releases).

A starting script

import time
import cv2
from picamera2 import Picamera2

INTERVAL_S = 10           # seconds between frames
CHANGE_THRESHOLD = 25     # per-pixel difference that counts as change
ALERT_FRACTION = 0.15     # fraction of pixels changed that triggers an alert
ROI = (200, 150, 880, 570)  # x1, y1, x2, y2 of the bed area in the image

cam = Picamera2()
cam.configure(cam.create_still_configuration(
    main={"size": (1280, 720), "format": "RGB888"}))
cam.start()
time.sleep(2)  # let exposure settle

def grab_gray():
    frame = cam.capture_array()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    return cv2.GaussianBlur(gray, (5, 5), 0)

previous = grab_gray()
while True:
    time.sleep(INTERVAL_S)
    current = grab_gray()
    x1, y1, x2, y2 = ROI
    diff = cv2.absdiff(current, previous)
    _, mask = cv2.threshold(diff, CHANGE_THRESHOLD, 255, cv2.THRESH_BINARY)
    changed = cv2.countNonZero(mask) / mask.size
    print(f"changed={changed:.3f}")
    if changed > ALERT_FRACTION:
        cv2.imwrite(f"alert_{int(time.time())}.jpg", current)
        print("ALERT: large change, check the printer")
    previous = current

The thresholds are starting values to tune. Log changed for a few good prints and set the alert level comfortably above what normal printing produces.

Making it smarter without ML

  • Two zones. Compare change inside the expected part area with change elsewhere on the bed. Lots of change outside the part area is a strong spaghetti signal.
  • Require persistence. Alert only when several consecutive frames exceed the threshold, to ignore a hand reaching in or the toolhead passing close to the camera.
  • Watch for no change. If the printer is printing and nothing has changed for many minutes, extrusion may have stopped.
  • Ignore the toolhead. The moving head creates change in every frame. Capturing at the same point in each layer (for example by triggering from a layer-change macro) removes most of that noise.

Acting on alerts

Start with notifications only: send the alert image to your phone through whatever you use (Home Assistant, a chat webhook, or email). Once you trust it, you can pause automatically:

  • Klipper with Moonraker: send an HTTP POST to /printer/print/pause on the Moonraker host.
  • OctoPrint: use its REST API job command with an API key.

Pausing is safer than cancelling. A false alarm costs a few minutes, not a print.

Limits to be honest about

  • This catches large, visible failures. Subtle problems like layer shifts, warping corners, or under-extrusion are hard to see with frame differencing.
  • Changing light causes false alarms. Fix the lighting before tuning thresholds.
  • It is a helper, not a fire safety system. Thermal runaway protection, smoke detection, and not leaving printers unattended for long periods still matter.

If you want ML-based detection, established projects such as Obico (formerly The Spaghetti Detective) exist and can run self-hosted.

Troubleshooting

SymptomLikely causeFix
Constant alertsThreshold too low, flickering light, camera vibrationTune thresholds, steady the light, stiffen the mount
Never alertsROI misses the bed, threshold too highSave a frame, check ROI coordinates, log values during a test failure
Camera not detectedRibbon cable orientation or wrong connectorReseat the cable; check with rpicam-hello --list-cameras

Summary

Frame differencing on a fixed camera with steady lighting can flag spaghetti, detached parts, and stalled prints. Restrict comparison to the bed, require several bad frames in a row, start with notifications, and only then let it pause the printer.

Related