Project Overview
This project creates a wildlife camera trigger system that captures photos or videos when animals are detected. A PIR sensor detects animal movement and triggers a camera (GoPro, DSLR, or USB camera) to capture images. It’s perfect for observing wildlife in your backyard, garden, or remote locations.
Difficulty: Intermediate
Estimated time: 2-3 hours
Estimated cost: $30-50 (plus camera)
How It Works
A PIR sensor detects warm, moving animals. When motion is detected, the ESP32 triggers the camera via a shutter control cable (for DSLR) or by activating a USB camera. Images are stored on an SD card or transmitted via Wi-Fi. The system includes a real-time clock to timestamp images and can be powered by batteries for remote deployment.
Materials Needed
- ESP32-CAM or Arduino + camera module (1)
- HC-SR501 PIR sensor (1) – with adjustable sensitivity
- SD card (for image storage)
- Battery pack (18650 lithium cells, 3.7V) or 5V USB power bank
- TP4056 charging module (if using rechargeable batteries)
- Weatherproof enclosure (IP65 or better)
- Jumper wires
- Optional: IR LED array (for night vision)
Circuit Diagram
Connection Table (ESP32-CAM + PIR)
| Component |
Pin |
ESP32-CAM Pin |
PIR Sensor |
VCC
| 5V
| PIR Sensor |
GND
| GND
| PIR Sensor |
OUT
| GPIO 13
| IR LED Array |
Positive
| GPIO 4 (through transistor)
| IR LED Array |
Negative
| GND
|
表
ESP32-CAM Code
// Wildlife Camera Trigger with ESP32-CAM
#include "esp_camera.h"
#include <FS.h>
#include <SD_MMC.h>
#include <time.h>
// Pin definitions
#define PIR_PIN 13
#define LED_PIN 4
#define FLASH_LED_PIN 4 // Built-in flash
// Camera pins for AI-Thinker ESP32-CAM
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// RTC time
const char* ntpServer = "pool.ntp.org";
const long gmtOffset = 0;
const int daylightOffset = 0;
unsigned long lastTriggerTime = 0;
const unsigned long triggerCooldown = 10000; // 10 seconds between shots
int imageCount = 0;
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Initialize camera
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_SVGA; // 800x600
config.jpeg_quality = 12;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed: 0x%x", err);
return;
}
// Initialize SD card
if (!SD_MMC.begin()) {
Serial.println("SD Card mount failed");
return;
}
// Initialize RTC
configTime(gmtOffset, daylightOffset, ntpServer);
Serial.println("Wildlife Camera Ready");
delay(30000); // Short PIR warm-up for wildlife
}
String getTimestamp() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "00000000_000000";
}
char buffer[20];
strftime(buffer, sizeof(buffer), "%Y%m%d_%H%M%S", &timeinfo);
return String(buffer);
}
void captureImage() {
if (millis() - lastTriggerTime < triggerCooldown) return;
lastTriggerTime = millis();
// Turn on LED briefly (for night shots)
digitalWrite(LED_PIN, HIGH);
delay(100);
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
digitalWrite(LED_PIN, LOW);
return;
}
String filename = "/IMG_" + getTimestamp() + ".jpg";
File file = SD_MMC.open(filename, FILE_WRITE);
if (file) {
file.write(fb->buf, fb->len);
file.close();
imageCount++;
Serial.print("Image saved: ");
Serial.println(filename);
} else {
Serial.println("Failed to save image");
}
esp_camera_fb_return(fb);
digitalWrite(LED_PIN, LOW);
}
void loop() {
bool motion = digitalRead(PIR_PIN) == HIGH;
if (motion) {
Serial.println("Motion detected - capturing image");
captureImage();
delay(2000); // Wait for animal to possibly move into better frame
captureImage(); // Take second shot
}
delay(100);
}
DSLR Trigger Version (External Camera)
For high-quality images, trigger a DSLR using a shutter release cable:
// DSLR Trigger via optocoupler
const int shutterPin = 12;
const int focusPin = 14;
void triggerCamera() {
// Focus first
digitalWrite(focusPin, HIGH);
delay(200);
// Then trigger shutter
digitalWrite(shutterPin, HIGH);
delay(100);
digitalWrite(shutterPin, LOW);
delay(200);
digitalWrite(focusPin, LOW);
}
Enclosure Design
- Use weatherproof enclosure (IP65 or IP67).
- Cut a window for the camera lens and PIR sensor.
- Use clear acrylic or glass for the lens window (glass may block IR).
- Add desiccant packs to prevent condensation.
- Mount camera securely inside enclosure.
Installation Steps
- Assemble electronics: Test camera and PIR indoors.
- Program ESP32-CAM: Upload code and verify image capture.
- Mount in enclosure: Secure components inside weatherproof box.
- Position in field: Place near animal trails, water sources, or feeding areas.
- Adjust PIR sensitivity: Set to detect animals of appropriate size.
- Power up: Connect battery pack (use solar panel for long-term deployment).
- Test: Walk in front to verify camera triggers.
Project Extensions
- Night vision: Add IR LED array and remove IR filter from camera.
- Live streaming: Add cellular module for remote image transmission.
- Video recording: Record short video clips instead of still images.
- Animal classification: Add machine learning to identify species (TensorFlow Lite).
- Solar power: Add solar panel for indefinite operation.
- Wi-Fi upload: Upload images to cloud when in range.
PIR Sensitivity for Wildlife
Different animals emit different amounts of heat. Adjust sensitivity:
- Large animals (deer, bear): Lower sensitivity (detect at distance)
- Small animals (rabbits, squirrels): Higher sensitivity
- Birds: Highest sensitivity (smaller heat signature)
Troubleshooting
- No images saved: Check SD card formatting (FAT32). Verify SD_MMC initialization.
- Camera not triggering: Check PIR wiring. Adjust sensitivity.
- Blurry images: Increase JPEG quality. Ensure camera is focused.
- False triggers from sunlight: Position sensor in shade. Add sun shield.
- False triggers from vegetation: Adjust sensitivity. Aim sensor away from moving plants.
Conclusion
This wildlife camera trigger lets you observe animals in their natural habitat without disturbing them. With proper placement, you can capture amazing photos of local wildlife.