More Raspberry Pi Projects

Project 8 — Machine Learning at the Edge with the Pi AI Kit

What you will build A real-time object detection system — identifying people, animals, and vehicles in a live camera feed, running entirely on your Pi
Difficulty Intermediate-Advanced — the concepts are deep but the tooling has improved greatly. Following the steps carefully gets you there.
Time to complete 2 – 4 hours for the AI Kit path; 1 – 2 hours for software-only on Pi 4/5
Practical project A wildlife / doorbell camera that saves clips and sends notifications only when a person, cat, or specific animal is detected

Edge AI — Why It Matters

Most AI services work by sending data to a remote server — your photo goes to the cloud, a neural network analyses it, and the result comes back. That's fine for many uses, but it has real drawbacks: latency, cost, privacy concerns, and a dependency on internet connectivity.

Edge AI runs neural networks directly on the device — no cloud, no subscription, no data leaving your home. The Raspberry Pi has always been capable of some on-device ML, but the Pi AI Kit changes the game by adding a dedicated Neural Processing Unit (NPU) that handles AI inference 13× faster than the Pi 5's CPU alone, while drawing minimal power.

Hardware Options

Software-only — no extra hardware Raspberry Pi 5 (CPU only) Runs YOLOv8n (nano) using the Pi 5's ARM CPU at 8–12 FPS — usable for low-frame-rate detection. Suitable for still-image analysis or slow-motion applications. No extra hardware required. Free add-on — just software
Software-only — older hardware Raspberry Pi 4 (CPU only) Runs YOLOv8n at 2–4 FPS on CPU. Better suited to periodic snapshot analysis than live video. Use a lighter model (MobileNet SSD) for more responsive results. Free add-on — significantly slower

What You Will Need

🍓 Raspberry Pi 5 (for AI Kit) The AI Kit requires a Pi 5 — it uses the PCIe M.2 HAT+ connector that only exists on the Pi 5. Pi 4 users can follow the software-only path.
🧩 Pi AI Kit or AI HAT+ Available from the Raspberry Pi store and most Pi resellers. Comes with the PCIe flat flex cable. Fits any Pi 5 — no soldering required.
📷 Pi Camera Module Camera Module 3 (~£25) is the current recommended choice — 12MP, autofocus, good low-light performance. Camera Module 2 also works. Or use a USB webcam for a simpler setup.
🐧 Raspberry Pi OS (64-bit Bookworm) The Hailo driver requires the 64-bit version of Raspberry Pi OS 12 (Bookworm) or later. Check with uname -m — should return aarch64.
🔌 Good power supply Use the official Raspberry Pi 27W USB-C power supply. The Pi 5 with AI Kit and camera under load can draw 5A — underpowered supplies cause throttling and instability.
💾 Fast microSD or SSD A fast card or SSD makes a noticeable difference when loading large model files. A Pi 5 with an NVMe SSD via the PCIe slot (without the AI Kit) starts models in seconds rather than tens of seconds.

How the AI Pipeline Works

Object detection pipeline — from camera to result
CameraPi Camera 3
──►
libcameracapture frames
──►
Hailo NPUneural inference
──►
YOLOv8detect objects
──►
Outputlabels + boxes

Each frame: captured → pre-processed → sent to Hailo NPU → detected objects returned with labels and confidence scores → displayed or acted upon

The key insight with the Hailo NPU is that the neural network runs on dedicated silicon — the CPU remains largely free to do other work (run a web server, save video clips, send notifications) while the NPU handles inference at full speed.

Step 1 — Fit the AI Kit (hardware)

Power off and unplug your Raspberry Pi 5 completely before fitting the AI Kit. The PCIe bus does not support hot-plugging.
  • Remove any existing HAT from your Pi 5 if fitted
  • Connect the flat flex cable to the Pi 5's M.2 HAT+ connector (the slot closest to the USB ports) — the cable inserts with the blue tab facing up, and the retaining clip snaps closed
  • Connect the other end of the cable to the AI Kit's M.2 connector — same orientation
  • Fit the AI Kit onto the Pi 5's GPIO header and secure with the supplied spacers and screws
  • Connect a Pi Camera to either of the Pi 5's two MIPI camera connectors using a camera cable
The PCIe flat flex cable is fragile. Insert it straight without twisting. If you hear crackling or the clip doesn't close smoothly, remove the cable and try again rather than forcing it.

Step 2 — Install the Hailo Software Stack

pi@raspberrypi:~$ sudo apt update
pi@raspberrypi:~$ sudo apt install -y hailo-all

The hailo-all meta-package installs:

  • hailofw — Hailo NPU firmware
  • hailo-tappas-core — GStreamer plugins for the Hailo pipeline
  • hailo-pyhailort — Python bindings for the Hailo Runtime
  • rpicam-apps — updated libcamera apps with Hailo integration
# Reboot is required for the PCIe driver to load
pi@raspberrypi:~$ sudo reboot

Verify the Hailo device is detected

pi@raspberrypi:~$ hailortcli fw-control identify
Executing on device: 0000:01:00.0
Identifying board
Control Protocol Version: 2
Firmware Version: 4.17.0 (release,app,extended context switch buffer)
Logger Version: 0
Board Name: Hailo-8L
Device Architecture: HAILO8L
Serial Number: ...
Part Number: HM21LB1C2LAE

You should see Hailo-8L (AI Kit) or Hailo-8 (AI HAT+). If the command is not found or the device isn't listed, see the troubleshooting section.

Step 3 — Run Your First Object Detection Demo

Raspberry Pi OS ships with ready-to-run object detection examples via rpicam-hello:

# Live object detection on a connected display (requires monitor)
pi@raspberrypi:~$ rpicam-hello -t 0 --post-process-file \
  /usr/share/rpi-camera-assets/hailo_yolov8_inference.json --lores-width 640 --lores-height 640

This opens a preview window with bounding boxes drawn around detected objects in real time. Try walking in front of the camera, placing objects on a table, or pointing it out of a window at passing cars.

The -t 0 flag runs indefinitely — press Ctrl+C to stop.

Available post-processing configs

pi@raspberrypi:~$ ls /usr/share/rpi-camera-assets/ | grep hailo
hailo_yolov5_personface.json      # detect people and faces
hailo_yolov6_inference.json       # YOLOv6 object detection
hailo_yolov8_inference.json       # YOLOv8 — 80 COCO object classes
hailo_yolov8_pose.json            # human pose estimation
hailo_yolox_inference.json        # YOLOX object detection

Step 4 — Python Object Detection Script

For real projects you'll want to capture frames programmatically, filter detections, and act on them. Here's a practical Python script that captures frames from the Pi Camera and runs YOLOv8 inference via the Hailo NPU:

pi@raspberrypi:~$ pip3 install --break-system-packages picamera2 opencv-python-headless
pi@raspberrypi:~$ nano ~/detect.py
from picamera2 import Picamera2
from picamera2.devices.hailo import Hailo
import cv2, time, datetime

# ── Configuration ───────────────────────────────────────────────
MODEL_PATH    = "/usr/share/hailo-models/yolov8s_h8l.hef"
LABELS_PATH   = "/usr/share/hailo-models/coco.txt"
CONFIDENCE    = 0.5           # minimum detection confidence (0–1)
WATCH_CLASSES = {"person", "cat", "dog", "bird"}  # trigger on these only
SAVE_DIR      = "/home/pi/detections"

# ── Load labels ─────────────────────────────────────────────────
with open(LABELS_PATH) as f:
    labels = [line.strip() for line in f]

# ── Setup ───────────────────────────────────────────────────────
cam   = Picamera2()
hailo = Hailo(MODEL_PATH)

model_h, model_w, _ = hailo.get_input_shape()
cam.configure(cam.create_video_configuration(
    main={"size": (1280, 960)},
    lores={"size": (model_w, model_h), "format": "RGB888"}
))
cam.start()
import os; os.makedirs(SAVE_DIR, exist_ok=True)

print("Detection running — press Ctrl+C to stop")

try:
    while True:
        frame, lores = cam.capture_arrays(["main", "lores"])

        # Run inference on the low-resolution frame (sent to Hailo NPU)
        results = hailo.run(lores)

        triggered = []
        for det in results:
            label = labels[int(det["class_id"])]
            conf  = det["confidence"]
            if conf >= CONFIDENCE and label in WATCH_CLASSES:
                triggered.append((label, conf))
                # Draw bounding box on the full-res frame
                x1, y1, x2, y2 = [int(v) for v in det["bbox"]]
                cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 200, 0), 2)
                cv2.putText(frame, f"{label} {conf:.0%}",
                            (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX,
                            0.55, (0, 200, 0), 2)

        if triggered:
            ts   = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
            objs = "_".join(sorted({l for l, _ in triggered}))
            path = f"{SAVE_DIR}/{ts}_{objs}.jpg"
            cv2.imwrite(path, cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
            print(f"[{ts}] Saved: {objs} ({', '.join(f'{l} {c:.0%}' for l,c in triggered)})")

        time.sleep(0.1)   # 10 FPS — reduce for less CPU use

except KeyboardInterrupt:
    print("Stopped.")
finally:
    cam.stop()
    hailo.close()
pi@raspberrypi:~$ python3 detect.py
Detection running — press Ctrl+C to stop
Example output — detected objects saved to ~/detections/
[20250611_143012]Saved:person 94%→ 20250611_143012_person.jpg
[20250611_143847]Saved:cat 87%→ 20250611_143847_cat.jpg
[20250611_151203]Saved:person 91%, dog 78%→ 20250611_151203_dog_person.jpg

Step 5 — Add Notifications

The detection script above saves images but doesn't alert you. Add a notification when a person is detected using Telegram (free and easy) or email.

Telegram notifications

pi@raspberrypi:~$ pip3 install --break-system-packages python-telegram-bot
  • In the Telegram app, search for @BotFather and start a chat
  • Send /newbot, give it a name and username — BotFather replies with a Bot Token
  • Search for your new bot in Telegram and send it any message to start a conversation
  • Find your Chat ID by visiting: https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates

Add this function to your detect.py script:

import asyncio
from telegram import Bot

BOT_TOKEN = "your_bot_token_here"
CHAT_ID   = "your_chat_id_here"

async def send_alert(image_path, detected_objects):
    bot = Bot(token=BOT_TOKEN)
    caption = "🚨 Detected: " + ", ".join(
        f"{label} ({conf:.0%})" for label, conf in detected_objects
    )
    with open(image_path, "rb") as photo:
        await bot.send_photo(chat_id=CHAT_ID, photo=photo, caption=caption)

# Call inside the detection loop when triggered:
if triggered:
    # ... save image as before ...
    asyncio.run(send_alert(path, triggered))

Step 6 — Run as a Service

Make the detection script start automatically on boot:

pi@raspberrypi:~$ sudo nano /etc/systemd/system/aidetect.service
[Unit]
Description=Pi AI Object Detection
After=multi-user.target

[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/detect.py
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
pi@raspberrypi:~$ sudo systemctl daemon-reload
pi@raspberrypi:~$ sudo systemctl enable --now aidetect
pi@raspberrypi:~$ sudo journalctl -u aidetect -f    # follow live output

Software-Only Path — Pi 4 or Pi 5 Without AI Kit

If you don't have the AI Kit, you can still run object detection using the CPU. Performance is significantly lower but perfectly usable for snapshot-based applications or low-frame-rate monitoring.

pi@raspberrypi:~$ pip3 install --break-system-packages ultralytics opencv-python-headless picamera2
from ultralytics import YOLO
from picamera2 import Picamera2
import cv2, datetime, os

MODEL      = YOLO("yolov8n.pt")    # nano model — smallest and fastest
CONFIDENCE = 0.5
SAVE_DIR   = "/home/pi/detections"
WATCH      = {"person", "cat", "dog"}

cam = Picamera2()
cam.configure(cam.create_still_configuration(main={"size": (1280, 960)}))
cam.start()
os.makedirs(SAVE_DIR, exist_ok=True)

import time
while True:
    frame   = cam.capture_array()
    results = MODEL(frame, conf=CONFIDENCE, verbose=False)[0]
    found   = {results.names[int(c)] for c in results.boxes.cls}
    hits    = found & WATCH
    if hits:
        ts   = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        path = f"{SAVE_DIR}/{ts}_{'_'.join(sorted(hits))}.jpg"
        cv2.imwrite(path, cv2.cvtColor(results.plot(), cv2.COLOR_RGB2BGR))
        print(f"Saved: {path}")
    time.sleep(2)   # 1 frame every 2 seconds on Pi 4
On first run, ultralytics downloads the yolov8n.pt model file (~6 MB) automatically. Use yolov8n.pt (nano) on a Pi 4 and yolov8s.pt (small) on a Pi 5 for better accuracy.

Project Ideas

🦡 Wildlife Camera Point the camera at a bird feeder, garden, or hedgerow. Detect birds, foxes, hedgehogs, and squirrels — save annotated images with timestamps. Build a timelapse gallery over months.
🔔 Smart Doorbell Mount the Pi Camera at your front door. Send a Telegram photo notification the moment a person is detected — before they ring the bell. Add a wide-angle lens for better coverage.
🚗 Driveway Monitor Detect cars and people entering your driveway. Combine with Home Assistant (Project 5 of Course 1) to automatically switch on outside lights when a person is detected after dark.
🐱 Pet Monitor Track when your cat comes and goes through a cat flap. Log detection times with confidence scores to see your pet's daily patterns. Combine with a cat-flap door lock to keep foxes out.
📊 Crowd Counter Count people in a scene — useful for a small shop, library, or event. Log counts over time to understand peak hours. Use the pose estimation model to distinguish sitting from standing.
🌿 Plant Health Monitor Train a custom model (using Roboflow or Google Teachable Machine) to classify plant health from leaf colour and shape. Point the camera at your vegetable patch and get daily reports.

Troubleshooting

⚠ hailortcli not found or "Device not found" after reboot
The Hailo PCIe driver may not have loaded. Check: lspci | grep Hailo — you should see a Hailo device. If not, the physical connection is the issue — power off, reseat the PCIe flat flex cable carefully, and try again. If lspci shows the device but hailortcli fails, check the driver is loaded: lsmod | grep hailo. If it's missing, reinstall: sudo apt install --reinstall hailo-all and reboot.
⚠ rpicam-hello fails — "No cameras available"
The Pi Camera isn't being detected. Check: (1) the camera cable is seated firmly in both the camera and Pi 5 connectors — these are easy to mis-seat; (2) the camera is enabled: run sudo raspi-config → Interface Options → Camera → Enable; (3) reboot after enabling; (4) test with libcamera-hello --list-cameras — if the camera appears here but not in rpicam-hello, there's a libcamera version mismatch from the hailo-all install. Run sudo apt upgrade to ensure everything is consistent.
⚠ Python script fails — "ImportError: No module named picamera2.devices.hailo"
The Hailo-aware version of picamera2 isn't installed. The hailo-all apt package installs a specific version of picamera2 that includes Hailo support. Check which version is installed: python3 -c "import picamera2; print(picamera2.__version__)". If you installed picamera2 separately via pip, it may have overwritten the apt version. Remove the pip version: pip3 uninstall picamera2, then reinstall via apt: sudo apt install python3-picamera2.
⚠ Detections are erratic — lots of false positives or misses
Adjust the confidence threshold: 0.5 is a good starting point, but scenes with challenging lighting may need 0.4 (more detections, more false positives) or 0.6 (fewer detections, higher precision). Also check: (1) is the camera steady? Motion blur at low light greatly affects accuracy; (2) is the camera resolution correct? The model expects 640×640 input — the picamera2 lores stream handles this automatically; (3) try a larger model (yolov8m instead of yolov8s) if you have the NPU headroom — it's significantly more accurate.
⚠ Pi 4 software-only path is too slow for practical use
On a Pi 4, YOLOv8n runs at ~2–4 FPS. For real-time video this is too slow, but for wildlife cameras and periodic checks it's fine. Options to speed things up: (1) reduce input resolution (640×480 instead of 1280×960); (2) use MobileNet SSD — much lighter than YOLO and runs at ~8–10 FPS on a Pi 4: pip3 install tflite-runtime and use the MobileNet SSD TFLite model; (3) increase the sleep interval and only capture a frame every 5 seconds for a motion-triggered use case.
⚠ Detection service starts but no images are being saved
Either no matching objects are being detected, or the save directory doesn't exist or isn't writable. Check: ls -la ~/detections/ — the directory should exist and be owned by your user. If running as a systemd service, confirm the User=pi line matches your actual username. View live service output with sudo journalctl -u aidetect -f — the script prints to stdout each time it saves, so silence there means nothing is being detected. Try lowering the CONFIDENCE threshold to 0.3 temporarily to confirm the pipeline is working.

Quick Reference

TaskCommand / Resource
Check Hailo device detectedhailortcli fw-control identify
List cameraslibcamera-hello --list-cameras
Live detection previewrpicam-hello -t 0 --post-process-file /usr/share/rpi-camera-assets/hailo_yolov8_inference.json --lores-width 640 --lores-height 640
List available post-process configsls /usr/share/rpi-camera-assets/ | grep hailo
List available Hailo modelsls /usr/share/hailo-models/
Check Hailo PCIe devicelspci | grep Hailo
Check Hailo driver loadedlsmod | grep hailo
Monitor detection servicesudo journalctl -u aidetect -f
Restart detection servicesudo systemctl restart aidetect
Hailo documentationhailo.ai/developer-zone
Raspberry Pi AI Kit docsraspberrypi.com — AI Kit docs
COCO class list (80 objects)cat /usr/share/hailo-models/coco.txt
Roboflow (custom model training)roboflow.com
Ultralytics YOLOv8 docsdocs.ultralytics.com