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:
- MotionEyeOS: Provides camera streaming and management
- Python 3: Main programming language
- Ultralytics YOLOv8: AI inference engine
- 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.
-
Download MotionEyeOS for Raspberry Pi Zero from the official GitHub releases
-
Flash to MicroSD Card:
- Use Raspberry Pi Imager or Etcher
- Select the MotionEyeOS image
- Choose your SD card
- Flash!
-
Enable SSH (for remote access):
- Mount the SD card on your computer
- Create an empty file named
sshin the boot partition
-
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
-
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:
- Copy
best.ptto a USB drive - Insert into Raspberry Pi
- 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
-
Reduce image size:
- Change
imgsz=416toimgsz=320in the script - Lower resolution = faster processing
- Change
-
Increase confidence threshold:
- Use
--conf 0.35to reduce processing overhead
- Use
-
Skip frames:
- Process every 2nd or 3rd frame instead of all frames
-
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
- Position: Mount behind rearview mirror for unobstructed view
- Angle: Point slightly downward (15-30°) to capture road ahead
- Power: Use cigarette lighter USB adapter (2.5A minimum)
- 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:
- Enable GPS logging (see optional enhancement above)
- Export detections with coordinates
- 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
- Speed: 1-3 FPS on Pi Zero means some potholes might be missed at highway speeds
- Night Performance: Accuracy drops in low-light conditions
- Weather: Heavy rain or snow affects detection reliability
- False Positives: Shadows, road markings, or debris may be misidentified
Future Enhancements
- Multi-Class Detection: Detect cracks, manholes, and other road hazards
- Speed Integration: Adjust detection sensitivity based on vehicle speed
- Cloud Sync: Automatic upload of detections with GPS coordinates
- Real-Time Alerts: Audio/visual warning when approaching detected pothole
- Model Improvement: Continuous training with your collected data
- 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
- Dataset: Kaggle Potholes Detection Dataset
- YOLOv8 Documentation: Ultralytics Docs
- MotionEyeOS: GitHub Repository
- Raspberry Pi Forums: raspberrypi.org/forums
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