Downloads · 30 days
0
engdarwish/drone-detection-yolov5
drone-detection-yolov5 is a object detection model from engdarwish. Use it when you need objects located in an image. The card lists the license as mit.
"Can a $35 computer see, think, and chase a drone — all at once?" That was the question. This is the answer.
Downloads · 30 days
0
Access
Public
Updated Apr 12, 2026
Repo size
44.3 MB
Likes
0
Public
Click a slice to open those files.
.onnx28.3 MB · 65%
From the Hugging Face model README
"Can a $35 computer see, think, and chase a drone — all at once?"
That was the question. This is the answer.
Drones are everywhere. Detecting them in real-time on powerful hardware is one thing — but what if you only have a Raspberry Pi 4? No GPU, no CUDA, no shortcuts.
The challenge was clear:
Most people would say it's not possible. We built it anyway.
| Metric | Score |
|---|---|
| Precision | 94.8% |
| Recall | 96.2% |
| [email protected] | 99.0% 🔥 |
| [email protected]:0.95 | 70.6% |
| False Positives | ~1% ✅ |
| Inference on Pi | ~15-20 FPS |
We started simple. A single dataset, ~500 images, YOLOv5s with Transfer Learning. The first model came out at 95% mAP — impressive on paper.
But on the Raspberry Pi, reality hit hard.
The camera would lock onto a wooden tray and call it a drone. A chair. A lamp. The model was too eager — it had never truly learned what wasn't a drone.
We had a precision problem. And we knew exactly why: not enough negative images.
The original dataset had only 5 background images out of 503 total. Five. The model had barely seen what the world looks like without a drone in it.
So we went hunting for data.
Instead of spending weeks manually collecting and labeling images, we combined 3 of the largest drone datasets on Roboflow Universe:
| Dataset | Images | Source |
|---|---|---|
| DroneDetectionPITT | 34,000 | Roboflow Universe |
| Drone Detection (YOLO) | 1,094 | Roboflow Universe |
| Drone Detection (drones-lfobz) | 5,079 | Roboflow Universe |
| Positive (auto-labeled) | 321 | Original dataset |
| Negative (background) | 155 | COCO Dataset |
| Total | 40,529 | — |
But combining datasets isn't just copy-paste. Each dataset has its own format, resolution, and labeling style. We built a custom pipeline to:
It took engineering. It took iteration. But it worked.
With 40,000+ images ready, we needed serious compute. We upgraded to an NVIDIA A100 40GB GPU on Google Colab and trained for 30 epochs with:
Model : YOLOv5s (Transfer Learning from COCO)
Image size: 416×416
Batch size: 256
Epochs : 30
GPU : NVIDIA A100 40GB
Time : ~45 minutes
The results were immediate. mAP jumped from 95% to 99%. False positives dropped from 100% to 1%. The model had finally learned the difference between a drone and everything else.
A great model means nothing if it can't run where it needs to. We exported to ONNX format and deployed on Raspberry Pi 4 using ONNXRuntime — no GPU, no PyTorch, just pure optimized inference.
Achieved: 15-20 FPS on a $35 computer. ✅
Detection alone wasn't enough. We built a complete pan-tilt tracking system:
Camera Feed → YOLOv5 Detection → PID Controller → Servo Motors
A 4-state machine manages the behavior:
SEARCHING → drone appears → TRACKING
TRACKING → drone lost → LOST
LOST → timeout → RETURNING
RETURNING → centered → SEARCHING
The PID controller computes servo movement based on the pixel error between the drone's center and the frame center:
Pan axis: Kp=0.055 Ki=0.0005 Kd=0.010
Tilt axis: Kp=0.045 Ki=0.0005 Kd=0.010
Deadzone : 10 pixels (prevents micro-jitter)
Hardware stack:
pip install onnxruntime opencv-python numpy
import cv2
import numpy as np
import onnxruntime as ort
session = ort.InferenceSession("best.onnx")
input_name = session.get_inputs()[0].name
def letterbox(frame, size=416):
h0, w0 = frame.shape[:2]
r = min(size/h0, size/w0)
nw, nh = int(round(w0*r)), int(round(h0*r))
dw, dh = (size-nw)/2, (size-nh)/2
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (nw, nh))
img = cv2.copyMakeBorder(img,
int(round(dh-.1)), int(round(dh+.1)),
int(round(dw-.1)), int(round(dw+.1)),
cv2.BORDER_CONSTANT, value=(114,114,114))
img = np.expand_dims(img.transpose(2,0,1), 0).astype(np.float32)/255.0
return img, r, dw, dh
def detect(image_path, conf_thres=0.45):
frame = cv2.imread(image_path)
h0, w0 = frame.shape[:2]
img, r, dw, dh = letterbox(frame)
preds = session.run(None, {input_name: img})[0][0]
mask = preds[:, 4] > conf_thres
preds = preds[mask]
results = []
for det in preds:
cx = int((det[0] - dw) / r)
cy = int((det[1] - dh) / r)
w = int(det[2] / r)
h = int(det[3] / r)
conf = float(det[4])
x1 = max(0, cx - w//2)
y1 = max(0, cy - h//2)
x2 = min(w0, cx + w//2)
y2 = min(h0, cy + h//2)
results.append({'bbox': [x1,y1,x2,y2], 'conf': conf})
cv2.rectangle(frame, (x1,y1), (x2,y2), (0,255,0), 2)
cv2.putText(frame, f"Drone {conf:.0%}", (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255,255,255), 2)
cv2.imwrite("output.jpg", frame)
print(f"Detected {len(results)} drone(s)")
return results
results = detect("your_image.jpg")
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret: break
img, r, dw, dh = letterbox(frame)
preds = session.run(None, {input_name: img})[0][0]
mask = preds[:, 4] > 0.45
for det in preds[mask]:
cx = int((det[0]-dw)/r); cy = int((det[1]-dh)/r)
w = int(det[2]/r); h = int(det[3]/r)
cv2.rectangle(frame, (cx-w//2, cy-h//2), (cx+w//2, cy+h//2), (0,255,0), 2)
cv2.imshow("Drone Detector", frame)
if cv2.waitKey(1) & 0xFF == ord('q'): break
cap.release()
| File | Description |
|---|---|
best.onnx | ONNX model — optimized for CPU & Raspberry Pi |
best.pt | PyTorch weights — for fine-tuning or retraining |
drone_enhanced.yaml | Dataset configuration used in training |
hyp_drone_enhanced.yaml | Hyperparameters used in training |
results.png | Training loss & metrics curves |
confusion_matrix.png | Confusion matrix |
Author: Ahmed Darwish
Deployment: Raspberry Pi 4
Training: Google Colab — NVIDIA A100 40GB GPU
Stack: Python · YOLOv5 · ONNXRuntime · OpenCV · PCA9685 · PID Control
Built from scratch. Trained at scale. Deployed on the edge. 🚀