Decision Matrix: Picking Your 2026 Pi Build
Not every project justifies the cost of a Pi 5. Use this decision path to determine if the Edge-AI Sorter is the right build for your bench, or if you should pivot to a simpler microcontroller.
| Project Concept | Compute Need | Hardware AI/NPU Required? | Verdict & Hardware Pick |
|---|---|---|---|
| Smart Mirror / Dashboard | Low (Web rendering) | No | Skip. Use a Pi 4 or Pi Zero 2 W. |
| Home Assistant Server | Medium (Database I/O) | No | Good, but use an NVMe SSD via PCIe. Standard Pi 5 4GB. |
| MQTT Sensor Gateway | Low (Serial/I2C polling) | No | Overkill. Use an ESP32-S3 or Pi Pico W. |
| Edge-AI Defect Sorter | High (Vision + Inference) | Yes (Tensor ops) | DEFAULT PICK: Pi 5 8GB + Hailo-8L M.2 Kit. |
Exact Parts List & Spec Sheet
To replicate this build exactly, you need the specific board variants listed below. Substituting a Pi 4 will bottleneck the camera pipeline, and using third-party camera clones will break the libcamera hardware ISP routing.
| Component | Exact Variant / SKU | 2026 Est. Price | Why This Specific Part? |
|---|---|---|---|
| Compute Board | Raspberry Pi 5 (8GB RAM) | $80.00 | 8GB is mandatory for loading AI model weights into RAM without swapping. |
| AI Accelerator | Raspberry Pi AI Kit (Hailo-8L M.2 HAT+) | $70.00 | Plugs directly into the Pi 5 PCIe FFC connector. 13 TOPS performance. |
| Camera Module | Pi Camera Module 3 (Global Shutter) | $50.00 | Global shutter prevents motion blur on moving conveyor parts. |
| Servo Driver | Adafruit 16-Channel PCA9685 (I2C) | $17.50 | Offloads PWM timing from the Pi's CPU via hardware I2C. |
| Actuator | TowerPro MG996R Digital Servo | $14.00 | High torque (13kg/cm) required to snap a physical sorting gate shut. |
| Power Supply | Official Pi 5 27W USB-C PD PSU | $12.00 | Required to negotiate 5V/5A for PCIe and USB peripherals. |
Hardware Wiring & Pin Mapping
The Pi 5 introduced some changes to the GPIO header's I2C pull-up resistors (they are now 1.8kΩ instead of the older 10kΩ). This means the bus is stiffer, which is great for noise immunity but requires careful wiring when mixing 5V servo drivers with 3.3V logic.
Pin Mapping Table
| Pi 5 GPIO / Pin | Function | PCA9685 / Camera Target | Wire Color (Recommended) |
|---|---|---|---|
| Pin 1 (3.3V) | Logic Power | PCA9685 VCC (Top Left) | Orange |
| Pin 3 (GPIO 2 / SDA1) | I2C Data | PCA9685 SDA | Blue |
| Pin 5 (GPIO 3 / SCL1) | I2C Clock | PCA9685 SCL | Yellow |
| Pin 9 (GND) | Common Ground | PCA9685 GND (Logic side) | Black |
| CAM1 CSI Port | MIPI CSI-2 Data | Pi Camera Module 3 Ribbon | Flat Flex Cable |
| PCIe FFC Port | PCIe Gen 2 x1 | Hailo-8L M.2 HAT+ Ribbon | Flat Flex Cable |
Numbered Assembly Steps
- Seat the Hailo M.2 HAT+: Connect the PCIe FFC cable to the Pi 5. Ensure the copper contacts face inward. Secure with the provided M2.5 standoffs. Do not overtighten; the Pi 5 PCB flexes easily.
- Wire the PCA9685 Logic: Connect Pi Pin 1 (3.3V) to PCA9685 VCC. Connect Pi Pin 3 (SDA) to SDA, Pin 5 (SCL) to SCL, and Pin 9 (GND) to GND.
- Jumper the OE Pin: On the PCA9685 green terminal block, place a jumper wire between the
OE(Output Enable) pin and theGNDpin. If you skip this, the servo outputs will remain in a high-impedance state and twitch randomly. - Wire Servo Power: Connect a separate 5V/3A bench power supply to the PCA9685 V+ (red) and GND (black) high-power terminal block. Crucial: Run a common ground wire from this bench supply's GND to the Pi 5's GND (Pin 6).
- Connect the Camera: Lift the black plastic collar on the Pi 5 CAM1 port. Insert the Camera Module 3 ribbon cable with the blue tape facing the Ethernet/USB ports. Push the collar down to lock.
Python Control Code (Pi 5 + PCA9685)
This code targets the Raspberry Pi 5 (8GB) running Raspberry Pi OS Bookworm 64-bit. It uses the modern picamera2 library (not the deprecated legacy picamera stack) and the Adafruit CircuitPython PCA9685 library for servo actuation.
Install dependencies via terminal before running:
sudo apt install python3-picamera2 python3-libcamera
pip3 install adafruit-circuitpython-servokit
import time
import sys
from adafruit_servokit import ServoKit
from picamera2 import Picamera2, Preview
# --- PIN & CHANNEL DEFINITIONS ---
# I2C Pins: SDA = GPIO 2 (Pin 3), SCL = GPIO 3 (Pin 5)
# PCA9685 I2C Address: 0x40 (Default)
SERVO_CHANNEL = 0
GATE_OPEN_ANGLE = 110 # Degrees for MG996R to clear the conveyor
GATE_CLOSE_ANGLE = 20 # Degrees for MG996R to block the conveyor
def init_hardware():
"""Initialize Servo Driver and Camera with explicit error handling."""
# 1. Initialize PCA9685 Servo Kit
try:
# Address 0x40 is default. Channels=16 for standard Adafruit board.
kit = ServoKit(channels=16, address=0x40)
kit.servo[SERVO_CHANNEL].set_pulse_width_range(500, 2500)
kit.servo[SERVO_CHANNEL].angle = GATE_CLOSE_ANGLE
print("[OK] PCA9685 initialized on I2C bus 1, address 0x40.")
except ValueError as e:
print(f"[FATAL] I2C Address/Config Error: {e}")
sys.exit(1)
except OSError as e:
print(f"[FATAL] I2C Bus Error: {e}. Check wiring and raspi-config.")
sys.exit(1)
# 2. Initialize Pi Camera Module 3
try:
cam = Picamera2()
# Create a lightweight config for fast inference framerates
cam_config = cam.create_preview_configuration(main={"size": (640, 480)})
cam.configure(cam_config)
cam.start()
time.sleep(2) # Allow camera AGC (Auto Gain) to settle
print("[OK] Pi Camera Module 3 started (640x480).")
except RuntimeError as e:
print(f"[FATAL] Camera Initialization Error: {e}")
print("Verify CSI ribbon cable seating and libcamera installation.")
sys.exit(1)
return kit, cam
def mock_ai_inference(frame):
"""
Placeholder for Hailo-8L NPU inference pipeline.
In production, replace this with hailo-python post-processing.
Returns True if 'defect' is detected in the frame.
"""
# Simulate processing delay and random detection for testing servo
time.sleep(0.05)
return hash(frame.tobytes()) % 20 == 0
def main_loop():
kit, cam = init_hardware()
print("Starting Edge-AI Sorter Loop. Press Ctrl+C to stop.")
try:
while True:
# Capture frame as numpy array
frame = cam.capture_array()
# Run inference (Hailo NPU pipeline goes here)
target_detected = mock_ai_inference(frame)
if target_detected:
print("[!] Target detected: Actuating sorting gate.")
kit.servo[SERVO_CHANNEL].angle = GATE_OPEN_ANGLE
time.sleep(0.6) # Hold gate open for part to fall through
kit.servo[SERVO_CHANNEL].angle = GATE_CLOSE_ANGLE
except KeyboardInterrupt:
print("\n[INFO] Halting sorter. Returning servo to home position.")
kit.servo[SERVO_CHANNEL].angle = GATE_CLOSE_ANGLE
cam.stop()
sys.exit(0)
if __name__ == "__main__":
main_loop()
Debugging: "OSError: [Errno 121] Remote I/O error"
When working with I2C on the Pi 5, the most common showstopper is the OSError: [Errno 121] Remote I/O error. This exact error string means the Pi's I2C controller sent a clock pulse, but the PCA9685 failed to acknowledge (NAK) or pulled the SDA line low indefinitely, causing a bus timeout.
First Three Things to Check
- Run
i2cdetect -y 1: If the output grid shows dashes instead of40, the Pi cannot physically see the chip. If it showsUU, another driver (like a rogue kernel module) has claimed the address. - Check the OE (Output Enable) Jumper: On the PCA9685 terminal block, if the OE pin is left floating, the internal logic can enter an undefined state, occasionally locking the I2C state machine. Jumper OE to GND.
- Verify Common Ground: If you are using a separate 5V bench supply for the servo power (V+), ensure its GND is tied to the Pi 5's GND. Without a common ground reference, the I2C SDA/SCL signals will float outside the PCA9685's logic threshold, resulting in Errno 121.
Ranked Causes for Persistent I2C Failures
| Rank | Cause | Fix / Measurement Threshold |
|---|---|---|
| 1 | Bus Capacitance Overload | Long ribbon cables add parasitic capacitance. Keep I2C wires under 30cm. Measure SCL rise time with a scope; it must be <300ns. |
| 2 | 5V Backfeed on Logic Pins | You accidentally wired Pi 5V to PCA9685 VCC. Measure voltage between PCA9685 VCC and GND. It must read 3.3V, not 5.0V. |
| 3 | Pi 5 Pull-Up Stiffness | The Pi 5 uses 1.8kΩ pull-ups. If your PCA9685 board also has 10kΩ pull-ups, the parallel resistance drops, increasing current sink. Ensure the PCA9685 pull-up jumper is cut if bus noise persists. |
Extending or Simplifying the Build
Once the baseline rig is sorting parts reliably, you will inevitably want to scale it. Here is how to modify the architecture based on your production needs.
How to Simplify (Lower Cost / Footprint)
If you only need to sort slow-moving items (like 3D printed parts on a manual belt) and don't need high-speed defect detection, drop the Hailo-8L AI Kit and the Pi 5. Switch to a Raspberry Pi Zero 2 W running a lightweight MobileNet V1 model via TensorFlow Lite. Replace the MG996R servo with a micro 9g SG90 servo powered directly from the Pi Zero's 5V rail. This cuts the BOM cost from ~$230 down to ~$45, though inference latency will jump from 15ms to ~350ms.
How to Extend (Industrial / High-Speed)
To push this from a bench project to a 24/7 production cell:
- Optoisolate the I2C Bus: Insert an ISO1540 bidirectional I2C isolator between the Pi 5 and the PCA9685. This protects the Pi from inductive voltage spikes generated by the MG996R servo motor braking.
- Add MQTT Telemetry: Integrate the
paho-mqttPython library to publishsorter/metrics/parts_rejectedpayloads to a local Mosquitto broker. This allows you to track defect rates over time on a Grafana dashboard. - Upgrade the Actuator: Servos wear out after ~50,000 cycles. Swap the MG996R for a 24V pneumatic solenoid valve (e.g., K25DH-08). You will need to replace the PCA9685 with a 24V relay board or an industrial PLC, but the Pi 5 vision pipeline and Hailo inference code remain exactly the same.






