Building an AI-Powered Pothole Detection Dash Cam with Raspberry Pi Zero

 

                                                          actual images from my colab

Building an AI-Powered Pothole Detection Dash Cam with Raspberry Pi Zero

Turn your car into a smart road condition monitor with computer vision and edge AI


Introduction

Potholes are more than just a nuisance—they cause billions of dollars in vehicle damage annually and pose serious safety risks to drivers. What if your daily commute could help map and document road conditions automatically? In this project, I'll show you how to build an intelligent dash cam using a Raspberry Pi Zero that detects potholes in real-time using computer vision.

This isn't just a hobbyist project. The system we're building could contribute to civic infrastructure monitoring, help municipalities prioritize road repairs, or simply alert you to hazards ahead during your drive.

What We're Building

An autonomous pothole detection system that:

  • Runs entirely on a Raspberry Pi Zero (no cloud required)
  • Detects potholes from dash cam footage in real-time
  • Saves images of detected potholes with timestamps
  • Can optionally log GPS coordinates for mapping
  • Costs under $50 in hardware

Why Raspberry Pi Zero?

The Raspberry Pi Zero W is the perfect platform for this project:

  • Compact: Fits anywhere on your dashboard
  • Affordable: Around $15-20
  • Low Power: Can run off a USB power bank
  • WiFi Built-in: Easy to access and configure
  • GPIO Support: Can interface with GPS modules and other sensors

While it's not the fastest computer, modern AI model optimization techniques make real-time inference possible even on this tiny device.

Hardware Requirements

Here's everything you'll need:

Essential Components

  • Raspberry Pi Zero W or WH ($15-20)
  • Raspberry Pi Camera Module or USB webcam ($10-25)
  • MicroSD Card (16GB minimum, 32GB recommended) ($8-15)
  • 5V 2.5A Power Supply or car USB adapter ($8-12)
  • Dash Cam Mount (optional but recommended) ($5-15)

Optional Enhancements

  • GPS Module (for location tracking) ($15-30)
  • Real-Time Clock (RTC) Module (for accurate timestamps) ($5-10)
  • Larger Power Bank (for extended operation) ($20-40)

Total Cost: $45-80 (basic setup)

The AI Model: YOLOv8 Nano

For pothole detection, we're using YOLOv8 Nano, the smallest and fastest variant of the popular YOLO (You Only Look Once) object detection model. Here's why:

  • Lightweight: Only ~6MB model size
  • Fast: Can achieve 1-3 FPS on Raspberry Pi Zero
  • Accurate: Trained on thousands of pothole images
  • Edge-Ready: Designed for deployment on resource-constrained devices

The model was trained on the Potholes Detection Dataset from Kaggle, which contains diverse road conditions, lighting scenarios, and pothole types.

Software Architecture

The system follows a simple but effective architecture:

Camera → Frame Capture → YOLOv8 Inference → Detection Logic → Save/Alert

Key Software Components:

  1. MotionEyeOS: Provides camera streaming and management
  2. Python 3: Main programming language
  3. Ultralytics YOLOv8: AI inference engine
  4. OpenCV: Image processing and camera interface

Training the Model

I trained the YOLOv8 Nano model on Kaggle's free GPU environment (Tesla T4). The training process involved:

  • Dataset: 600+ labeled pothole images (train/validation/test split)
  • Image Size: 416x416 pixels (optimized for speed)
  • Training Time: ~30 minutes on Tesla T4
  • Performance: 85%+ mAP@50 (mean Average Precision)

The model was specifically tuned for dash cam scenarios:

  • Various lighting conditions (day/night)
  • Different road surfaces (asphalt, concrete)
  • Multiple pothole sizes and shapes
  • Various viewing angles

Setting Up Your Raspberry Pi Zero

Now let's get to the practical part. After training the model, here's how to deploy it on your Raspberry Pi Zero.

Step 1: Install MotionEyeOS

MotionEyeOS is a lightweight Linux distribution designed for video surveillance. It's perfect for our dash cam application.

  1. Download MotionEyeOS for Raspberry Pi Zero from the official GitHub releases

  2. Flash to MicroSD Card:

  3. Enable SSH (for remote access):

    • Mount the SD card on your computer
    • Create an empty file named ssh in the boot partition
  4. Boot Your Pi:

    • Insert the SD card into your Raspberry Pi Zero
    • Connect the camera module
    • Power it up
    • Wait 2-3 minutes for first boot
  5. Access Web Interface:

    • Find your Pi's IP address (check your router or use a network scanner)
    • Open browser: http://<pi-ip>:8765
    • Default username: admin (no password)

Step 2: Install Dependencies

SSH into your Raspberry Pi:

ssh root@<your-pi-ip>
# Default password: blank (just press Enter)

Make the filesystem writable and update:

mount -o remount,rw /
mount -o remount,rw /boot

apt-get update
apt-get upgrade -y

Install Python and required libraries:

# Install system dependencies
apt-get install -y python3-pip python3-opencv libopencv-dev \
                   libatlas-base-dev libjpeg-dev libpng-dev

# Upgrade pip
pip3 install --upgrade pip

# Install Ultralytics and dependencies
pip3 install ultralytics opencv-python-headless pillow numpy --break-system-packages

Note: The --break-system-packages flag is required on newer Python versions.

Step 3: Transfer the Model

From your local machine, copy the trained model to your Pi:

scp best.pt root@<your-pi-ip>:/root/pothole_model.pt

Or use a USB drive:

  1. Copy best.pt to a USB drive
  2. Insert into Raspberry Pi
  3. Mount and copy: cp /media/usb/best.pt /root/pothole_model.pt

Step 4: Deploy the Detection Script

Create the pothole detection script on your Pi. Below is the complete implementation:

#!/usr/bin/env python3
"""
Pothole Detection Script for Raspberry Pi Zero with MotionEyeOS
This script captures frames from the camera and runs pothole detection.
"""

import cv2
import numpy as np
from ultralytics import YOLO
import time
import argparse
from datetime import datetime
import os

class PotholeDetector:
    def __init__(self, model_path, camera_source=0, conf_threshold=0.25):
        """
        Initialize pothole detector
        
        Args:
            model_path: Path to YOLO model (.pt file)
            camera_source: Camera device index or RTSP stream URL
            conf_threshold: Confidence threshold for detections
        """
        print("Loading model...")
        self.model = YOLO(model_path)
        self.conf_threshold = conf_threshold
        self.camera_source = camera_source
        self.cap = None
        
        # Create output directory for detections
        self.output_dir = "/root/pothole_detections"
        os.makedirs(self.output_dir, exist_ok=True)
        
        print("Model loaded successfully!")
    
    def initialize_camera(self):
        """Initialize camera capture"""
        print(f"Initializing camera: {self.camera_source}")
        self.cap = cv2.VideoCapture(self.camera_source)
        
        if not self.cap.isOpened():
            raise RuntimeError("Failed to open camera")
        
        # Set camera properties for optimal performance on RPi Zero
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 416)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 416)
        self.cap.set(cv2.CAP_PROP_FPS, 10)
        
        print("Camera initialized!")
    
    def detect_potholes(self, frame):
        """
        Run pothole detection on a frame
        
        Args:
            frame: Input image frame
            
        Returns:
            annotated_frame: Frame with bounding boxes
            detections: List of detection dictionaries
        """
        results = self.model.predict(
            source=frame,
            imgsz=416,
            conf=self.conf_threshold,
            verbose=False
        )
        
        annotated_frame = results[0].plot()
        
        # Extract detection information
        detections = []
        boxes = results[0].boxes
        
        for box in boxes:
            x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
            conf = float(box.conf[0])
            cls = int(box.cls[0])
            
            detections.append({
                'bbox': [int(x1), int(y1), int(x2), int(y2)],
                'confidence': conf,
                'class': cls
            })
        
        return annotated_frame, detections
    
    def save_detection(self, frame, detections):
        """Save frame when pothole is detected"""
        if len(detections) > 0:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"pothole_{timestamp}.jpg"
            filepath = os.path.join(self.output_dir, filename)
            cv2.imwrite(filepath, frame)
            print(f"Pothole detected! Saved to {filepath}")
    
    def run(self, save_detections=True, display=False):
        """
        Main detection loop
        
        Args:
            save_detections: Whether to save images with detections
            display: Whether to display video (requires X server)
        """
        self.initialize_camera()
        
        fps_counter = []
        frame_count = 0
        
        print("Starting pothole detection...")
        print("Press Ctrl+C to stop")
        
        try:
            while True:
                ret, frame = self.cap.read()
                if not ret:
                    print("Failed to grab frame")
                    break
                
                start_time = time.time()
                
                # Run detection
                annotated_frame, detections = self.detect_potholes(frame)
                
                # Calculate FPS
                fps = 1 / (time.time() - start_time)
                fps_counter.append(fps)
                
                # Display FPS on frame
                cv2.putText(annotated_frame, f"FPS: {fps:.1f}", 
                           (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 
                           0.7, (0, 255, 0), 2)
                
                # Save detection if enabled
                if save_detections:
                    self.save_detection(annotated_frame, detections)
                
                # Display frame if enabled
                if display:
                    cv2.imshow('Pothole Detection', annotated_frame)
                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        break
                
                frame_count += 1
                
                # Print statistics every 30 frames
                if frame_count % 30 == 0:
                    avg_fps = np.mean(fps_counter[-30:])
                    print(f"Frame {frame_count} | Avg FPS: {avg_fps:.2f} | Detections: {len(detections)}")
        
        except KeyboardInterrupt:
            print("\nStopping detection...")
        
        finally:
            self.cleanup()
    
    def cleanup(self):
        """Release resources"""
        if self.cap is not None:
            self.cap.release()
        cv2.destroyAllWindows()
        print("Cleanup complete")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Pothole Detection for Raspberry Pi")
    parser.add_argument("--model", type=str, default="/root/pothole_model.pt",
                       help="Path to YOLO model")
    parser.add_argument("--camera", type=str, default="0",
                       help="Camera source (0 for USB cam, or RTSP URL for MotionEye stream)")
    parser.add_argument("--conf", type=float, default=0.25,
                       help="Confidence threshold")
    parser.add_argument("--no-save", action="store_true",
                       help="Don't save detected potholes")
    parser.add_argument("--display", action="store_true",
                       help="Display video feed (requires X server)")
    
    args = parser.parse_args()
    
    # Convert camera argument
    camera_source = int(args.camera) if args.camera.isdigit() else args.camera
    
    # Initialize and run detector
    detector = PotholeDetector(
        model_path=args.model,
        camera_source=camera_source,
        conf_threshold=args.conf
    )
    
    detector.run(
        save_detections=not args.no_save,
        display=args.display
    )

Save this script as /root/pothole_detection_rpi.py and make it executable:

chmod +x /root/pothole_detection_rpi.py

Step 5: Test the System

Run a test detection:

cd /root
python3 pothole_detection_rpi.py --model pothole_model.pt --camera 0

You should see output like:

Loading model...
Model loaded successfully!
Initializing camera: 0
Camera initialized!
Starting pothole detection...
Press Ctrl+C to stop
Frame 30 | Avg FPS: 2.1 | Detections: 0
Frame 60 | Avg FPS: 2.3 | Detections: 1
Pothole detected! Saved to /root/pothole_detections/pothole_20260131_143022.jpg

Step 6: Auto-Start on Boot (Optional)

To make the detector run automatically when your Pi boots, create a systemd service:

nano /etc/systemd/system/pothole-detector.service

Add this content:

[Unit]
Description=Pothole Detection Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root
ExecStart=/usr/bin/python3 /root/pothole_detection_rpi.py --model /root/pothole_model.pt --camera 0
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start the service:

systemctl daemon-reload
systemctl enable pothole-detector.service
systemctl start pothole-detector.service

# Check status
systemctl status pothole-detector.service

# View logs
journalctl -u pothole-detector.service -f

Performance Expectations

Based on testing, here's what you can expect:

Platform FPS Latency Power Usage
Raspberry Pi Zero 1-3 FPS ~500ms ~1.5W
Raspberry Pi 3 5-10 FPS ~150ms ~4W
Raspberry Pi 4 10-15 FPS ~80ms ~6W
With Coral USB Accelerator 20-30 FPS ~40ms +2W

Note: 1-3 FPS is sufficient for dash cam applications since your car typically covers only a few meters per second at city speeds.

Configuration Tips

Adjusting Confidence Threshold

The confidence threshold determines how certain the model must be before reporting a detection:

# More sensitive (more false positives)
python3 pothole_detection_rpi.py --conf 0.15

# Less sensitive (fewer false positives)
python3 pothole_detection_rpi.py --conf 0.40

Start with 0.25 and adjust based on your results.

Using MotionEye RTSP Stream

If you want to use MotionEye's camera stream:

python3 pothole_detection_rpi.py --camera "rtsp://localhost:8554/stream"

Reducing Storage Usage

Detected images can accumulate quickly. Set up automatic cleanup:

# Add to crontab
crontab -e

# Delete detections older than 7 days, run daily at 3 AM
0 3 * * * find /root/pothole_detections -name "*.jpg" -mtime +7 -delete

Adding GPS Logging (Optional Enhancement)

To create a pothole map, add GPS coordinates to your detections:

# Install GPS library
pip3 install gpsd-py3 --break-system-packages

# Connect GPS module to Pi GPIO
# Then modify the script to log coordinates

Example GPS integration snippet:

import gpsd

# Connect to GPS daemon
gpsd.connect()

# In save_detection method:
packet = gpsd.get_current()
if packet.mode >= 2:  # 2D or 3D fix
    lat = packet.lat
    lon = packet.lon
    # Save coordinates with image

Troubleshooting Common Issues

Camera Not Detected

# List video devices
ls -l /dev/video*

# Test camera
v4l2-ctl --list-devices

# If using CSI camera, enable it
raspi-config
# Interface Options → Camera → Enable

Low FPS / Sluggish Performance

  1. Reduce image size:

    • Change imgsz=416 to imgsz=320 in the script
    • Lower resolution = faster processing
  2. Increase confidence threshold:

    • Use --conf 0.35 to reduce processing overhead
  3. Skip frames:

    • Process every 2nd or 3rd frame instead of all frames
  4. Consider upgrading:

    • Raspberry Pi 3/4 offers 3-5x better performance
    • Coral USB Accelerator adds hardware AI acceleration

Out of Memory Errors

# Increase swap size
dphys-swapfile swapoff
nano /etc/dphys-swapfile
# Set: CONF_SWAPSIZE=1024
dphys-swapfile setup
dphys-swapfile swapon
reboot

Model Loading Errors

# Verify model file exists and has correct size
ls -lh /root/pothole_model.pt

# Should be ~6MB for YOLOv8 Nano
# If corrupted, re-transfer from source

Real-World Usage Tips

Mounting in Your Vehicle

  1. Position: Mount behind rearview mirror for unobstructed view
  2. Angle: Point slightly downward (15-30°) to capture road ahead
  3. Power: Use cigarette lighter USB adapter (2.5A minimum)
  4. Stability: Use adhesive mount or suction cup for vibration dampening

Best Practices

  • Clean the lens regularly: Dust and rain spots reduce accuracy
  • Test in various conditions: Day, night, rain, shadows
  • Review detections weekly: Adjust confidence threshold as needed
  • Backup regularly: Copy detection images to cloud storage
  • Share with authorities: Report severe potholes with GPS coordinates

Data Collection for Community Mapping

If you want to contribute to community pothole mapping:

  1. Enable GPS logging (see optional enhancement above)
  2. Export detections with coordinates
  3. Upload to platforms like:
    • OpenStreetMap (with appropriate tags)
    • SeeClickFix (report infrastructure issues)
    • Local municipality reporting portals

Cost-Benefit Analysis

Total Investment: $45-80 Annual Pothole Damage Average: $300-500 per driver (AAA estimate) ROI: If this system helps you avoid just 1-2 serious pothole hits, it pays for itself!

Additional Benefits:

  • Contributes to civic infrastructure data
  • Educational project for learning AI/computer vision
  • Can be adapted for other detection tasks
  • Reusable hardware for future projects

Limitations and Future Improvements

Current Limitations

  1. Speed: 1-3 FPS on Pi Zero means some potholes might be missed at highway speeds
  2. Night Performance: Accuracy drops in low-light conditions
  3. Weather: Heavy rain or snow affects detection reliability
  4. False Positives: Shadows, road markings, or debris may be misidentified

Future Enhancements

  1. Multi-Class Detection: Detect cracks, manholes, and other road hazards
  2. Speed Integration: Adjust detection sensitivity based on vehicle speed
  3. Cloud Sync: Automatic upload of detections with GPS coordinates
  4. Real-Time Alerts: Audio/visual warning when approaching detected pothole
  5. Model Improvement: Continuous training with your collected data
  6. Edge TPU Integration: 10x faster inference with Google Coral

Conclusion

Building an AI-powered pothole detection dash cam is a practical application of edge computing and computer vision. While the Raspberry Pi Zero has limitations, it proves that sophisticated AI can run on affordable, compact hardware.

This project demonstrates:

  • Edge AI is accessible: You don't need expensive hardware or cloud services
  • Computer vision has practical applications: Beyond facial recognition and self-driving cars
  • DIY can make a difference: Individual data collection can contribute to community infrastructure

Whether you're a hobbyist exploring AI, a civic tech enthusiast, or someone tired of pothole damage, this project offers a hands-on way to engage with cutting-edge technology while potentially making your daily commute safer.

Resources and Links

Acknowledgments

  • Ultralytics for the amazing YOLOv8 framework
  • Kaggle for free GPU training resources and datasets
  • Raspberry Pi Foundation for affordable computing hardware
  • MotionEye Project for excellent camera software

Links

https://github.com/dhirajpatra/jupyter_notebooks/blob/main/DataScienceProjects/yolo/Pothole_Detection_from_Dash_Cam.ipynb

https://github.com/dhirajpatra/jupyter_notebooks/blob/main/DataScienceProjects/kaggle/pothole-detection-from-dash-cam.ipynb

Have you built this project or have improvements to suggest? Share your experience in the comments below!

Last updated: January 2026

Comments

Popular posts from this blog

Self-contained Raspberry Pi surveillance System Without Continue Internet

COBOT with GenAI and Federated Learning

AI in Education: Embracing Change for Future-Ready Learning