A local, offline edge-AI deterrent system:
- ESP32-CAM streams MJPEG over Wi‑Fi.
- A Python script on your laptop runs YOLOv8n (Ultralytics) to detect dogs.
- Option A (single‑board): when a dog is detected for a configurable duration, the script calls an HTTP endpoint on the same ESP32‑CAM (
/buzz) to drive a 23 kHz LEDC PWM on a GPIO. - Option B (two‑board): the script sends
buzz_on/buzz_offover serial to a separate Arduino/ESP32 that drives a 23 kHz ultrasonic transducer.
Works on Windows/macOS/Linux. No cloud APIs.
- ESP32‑CAM module (e.g., AI Thinker)
- USB‑serial programmer for ESP32‑CAM (FTDI/CP210x) if needed
- Optional (two‑board serial mode): Arduino Uno/Nano/Mega or an ESP32 board (as the buzzer driver)
- Piezo ultrasonic transducer (23 kHz). For higher power, use a transistor/MOSFET + suitable supply
- Jumper wires, breadboard
Single‑board HTTP mode wiring:
- Piezo + → ESP32‑CAM
BUZZ_GPIO_NUM(default GPIO15 in this repo) - Piezo − → GND
Safety note: Don’t drive high‑power transducers directly from MCU pins. Use a driver transistor and follow the transducer datasheet.
This repo includes a ready‑to‑flash CameraWebServer with an added /buzz endpoint.
- Install Arduino IDE + ESP32 board package.
- Open this repo folder:
CameraWebServer/CameraWebServer.ino. - In
board_config.h, select your camera model (e.g., uncommentCAMERA_MODEL_AI_THINKER). - In
CameraWebServer.ino, set your Wi‑Fissid/password. - (Optional) Buzzer pin: default
BUZZ_GPIO_NUMis 15. You can override per model incamera_pins.hor define inapp_httpd.cpp. On AI Thinker, you may also useGPIO4(flash LED pad), but avoid conflicts with the LED. - Board settings (typical):
- Board: AI Thinker ESP32‑CAM (or ESP32 Wrover Module)
- PSRAM: Enabled
- Upload speed: 115200 or higher
- Partition Scheme: Huge APP (3MB No OTA) recommended
- Upload and open Serial Monitor (115200) to find the IP.
- Stream URL:
http://<esp32-cam-ip>:81/stream(port 81) - Buzzer endpoint:
http://<esp32-cam-ip>/buzz?on=1|0(port 80)
Notes:
- This build uses
PIXFORMAT_RGB565+FRAMESIZE_QVGA. The server will re‑encode to JPEG for streaming. - If you previously got
0x106(JPEG not supported), RGB565 fixes it.
Upload ultrasonic_driver.ino to the board that will generate 23 kHz PWM.
- Arduino (Uno/Nano/Mega):
- Pin: D9 (default)
- Uses
tone()at 23 kHz
- ESP32:
- Pin: GPIO 25 (default)
- Uses LEDC hardware PWM at 23 kHz (50% duty)
Wiring (basic):
- Piezo + →
BUZZ_PIN(see sketch) - Piezo − → GND
For loud/high‑power piezos: Piezo + → supply via transistor/MOSFET; MCU pin drives the transistor gate/base; include resistor and flyback/driver as recommended.
Serial: The sketch listens at 115200 baud. Commands are ASCII lines:
buzz_on→ start tonebuzz_off→ stop tone
Requirements: Python 3.9+ recommended.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtPackages: ultralytics, opencv-python, pyserial, requests
Offline/air‑gapped friendly (avoids Ultralytics online checks):
export YOLO_OFFLINE=true YOLO_AUTOINSTALL=falseCopy the sample and edit it:
cp config.example.json config.jsonconfig.json keys:
camera_url: e.g.,http://192.168.1.123:81/streamserial_port:AUTOor a specific port- Windows:
COM3,COM5, … - macOS:
/dev/tty.usbserial-XXXX,/dev/tty.usbmodem-XXXX - Linux:
/dev/ttyUSB0,/dev/ttyACM0
- Windows:
baudrate: default 115200buzzer_mode:serial(default) orhttp(single‑board mode)control_base: base URL for control endpoints (optional; auto‑derived fromcamera_url, e.g.,http://<ip>)on_delay_s: require dog present for this long before buzzing (default 2.0 s)off_delay_s: require absence for this long before stopping (default 1.0 s)conf_threshold: YOLO confidence threshold (default 0.5)imgsz: short side resize for speed (default 480). Lower → faster, lower accuracydevice:auto|cpu|cuda|mpsshow_window: true/falsedraw_overlays: true/falsemirror: true/false (useful for some camera orientations)
You can also override via CLI flags or environment variables (see script).
Single‑board (HTTP buzzer on the same ESP32‑CAM):
python dog_detect.py --url http://<esp32-cam-ip>:81/stream --buzzer http- Press
qto quit. - Overlays show FPS, detection counter, and buzz state.
Tip: The script will call http://<esp32-cam-ip>/buzz?on=1|0 automatically. If needed, you can override with --control-base http://<esp32-cam-ip>.
Two‑board (serial) examples:
Examples:
# Explicit serial port and CUDA
python dog_detect.py --url http://192.168.1.123:81/stream --port COM5 --device cuda
# macOS Apple Silicon (MPS), smaller input for speed
python dog_detect.py --url http://192.168.1.123:81/stream --port AUTO --device mps --imgsz 416Tip: If OpenCV can’t read the URL directly, the script auto‑falls back to a manual MJPEG parser.
- Use
yolov8n.pt(default). Keepimgszaround 416–512 for ~10–20 FPS on modest CPUs. - GPU (CUDA) or Apple MPS can significantly increase FPS.
- Close other CPU‑heavy apps and ensure the ESP32‑CAM Wi‑Fi is strong.
- No video frame:
- Verify you can open
http://<esp32-cam-ip>/and start the stream. - Confirm the stream path (
:81/stream). - Same network as your laptop.
- Verify you can open
- "Nothing matches the given URI" when calling
/buzz:- Use port 80 for
/buzz. Port 81 serves only/stream.
- Use port 80 for
- Serial not found:
- Set
serial_portto the exact port. - Install drivers (CP210x/CH340/FTDI) if needed.
- Set
- Buzzer silent:
- Ensure
OK buzz_onappears in Serial Monitor when command is received. - Check wiring and that the transducer matches 23 kHz.
- For powerful buzzers, use a driver transistor and sufficient supply.
- Ensure
- Camera init error
0x105 (ESP_ERR_NOT_FOUND):- Wrong camera model. Set the correct model in
board_config.h(e.g.,CAMERA_MODEL_AI_THINKER). Reseat the camera ribbon.
- Wrong camera model. Set the correct model in
- Camera init error
0x106or "JPEG not supported":- This repo uses RGB565 + QVGA; keep it that way or switch from JPEG to RGB565.
- Network/Timeouts:
- Make sure the ESP32‑CAM IP is reachable. Use the Serial Monitor to get the IP and try
curl http://<ip>/status.
- Make sure the ESP32‑CAM IP is reachable. Use the Serial Monitor to get the IP and try
- ESP32‑CAM serves MJPEG.
- Python grabs frames, resizes to
imgsz, runs YOLOv8n (COCO) and filters classdog. - If a dog is detected for
on_delay_s, sendbuzz_ononce; otherwise, afteroff_delay_sof absence, sendbuzz_off. - Arduino/ESP32 generates a 23 kHz square wave via
tone()(AVR) or LEDC PWM (ESP32).
dog_detect.py– YOLOv8n inference, stream decoding, overlays, serial controlultrasonic_driver.ino– Serial command listener and 23 kHz PWM driverrequirements.txt– Python dependenciesconfig.example.json– Sample configuration (copy toconfig.json)CameraWebServer/*– Modified CameraWebServer with RGB565/QVGA defaults and a/buzzendpoint (port 80). Streaming at:81/stream.
Use responsibly. Ultrasound may disturb animals; ensure compliance with local laws and ethical use.