In diesem Tutorial lernst du, wie du eine bewegungsaktivierte, batteriebetriebene ESP32-CAM (AI-Thinker) baust, die Bilder aufnimmt, sobald ein PIR-Sensor Bewegung erkennt. Wir besprechen verschiedene PIR-Sensoren, Optionen zur Batterieversorgung und worauf du achten solltest.
Dieses Projekt eignet sich perfekt für Überwachungs-, Sicherheits- oder sogar Wildtierbeobachtungsanwendungen. Wenn du statt einzelner Bilder Videos aufnehmen möchtest, schau dir unser Surveillance Camera with ESP32-CAM Tutorial an.
Benötigte Teile
Im Folgenden findest du die Komponenten, die du für das Projekt benötigst. Einige Teile wie USB-Kabel, microSD-Karte oder SD-Kartenleser hast du vielleicht schon. Diese musst du dann nicht extra kaufen, da sie nicht speziell für dieses Projekt sind. Die SD-Karte sollte nicht größer als 16 GB sein, kleinere (4GB oder 8GB) funktionieren aber problemlos.
Du benötigst entweder das USB-TTL Shield oder den FTDI USB-TTL Adapter, aber nicht beide. Während das ESP32-CAM Modul mit USB-TTL Shield geliefert wird, ist der FTDI USB-TTL Adapter zum Programmieren bequemer.
Ich habe zwei verschiedene Arten von Bewegungssensoren aufgelistet. Wenn du eine kleine Bauform möchtest, nimm den AM312. Möchtest du die Kamera nur nachts aktivieren, nimm den HC-SR501, da dieser leicht mit einem Lichtsensor ausgestattet werden kann.

ESP32-CAM mit USB-TTL Shield

FTDI USB-TTL Adapter

Dupont-Kabelsatz

AM312 PIR-Bewegungssensor

HC-SR501 PIR-Bewegungssensor

MicroSD-Karte 16GB

SD-Kartenleser

USB-Datenkabel

Arduino IDE
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Grundlagen der PIR-Bewegungssensoren
Es gibt viele verschiedene Methoden und Sensoren zur Bewegungserkennung, aber die gebräuchlichsten sind PIR (Passive InfraRed) Bewegungssensoren, die die Bewegung warmer Objekte erkennen. Ein typischer PIR-Sensor besteht aus zwei pyroelektrischen Sensorelementen und einer Fresnel-Linse.

Pyroelektrisches Element
Die pyroelektrischen Elemente erkennen Wärme und sind so angeordnet und verdrahtet, dass ein vorbeigehendes Objekt ein positives oder negatives Ausgangssignal erzeugt. Bei einem unbewegten Objekt heben sich die Signale der beiden pyroelektrischen Elemente gegenseitig auf.
Fresnel-Linse
Die Fresnel-Linse (weiße Kappe) bündelt die schwache Wärmestrahlung eines menschlichen Körpers und macht den Sensor empfindlicher. Du kannst einen PIR-Sensor auch ohne Fresnel-Linse verwenden, er ist dann aber weniger empfindlich und löst häufiger Fehlalarme aus.

Beachte, dass PIR-Elemente hinter Glas (Fenstern) nicht funktionieren und keine Objekte mit der gleichen Temperatur wie der Raum erkennen können, in dem sie betrieben werden. Montiere den Sensor außerdem waagerecht für maximale Empfindlichkeit. Für mehr Infos siehe here.
Kalibrierungszeit
PIR-Sensoren haben typischerweise eine Kalibrierungszeit, in der sie sich an die aktuelle Umgebungstemperatur anpassen. Diese kann bis zu 15 Sekunden dauern, während dieser Zeit können Fehlalarme auftreten. Vermeide Bewegung während der Kalibrierung, damit sich der Sensor einstellen kann.
Blockier- und Verzögerungszeit
Außerdem haben PIR-Sensoren eine Blockierzeit und eine Verzögerungszeit. Die Blockier- oder Sperrzeit ist der Zeitraum, in dem der Sensor nach einem ersten Auslösen keine weiteren Bewegungen erkennt. Das verhindert, dass der Sensor durch dauerhafte Bewegung ständig aktiviert wird, und ermöglicht ihm, sich zurückzusetzen und Fehlalarme zu vermeiden. Wenn die Blockierzeit z.B. auf 30 Sekunden eingestellt ist, erkennt der Sensor in diesem Zeitraum keine Bewegung, auch wenn sich etwas im Erfassungsbereich bewegt.
Verzögerungszeit ist der Zeitraum, den der Sensor nach Bewegungserkennung wartet, bevor er eine Aktion auslöst. Diese Verzögerung ist nützlich, wenn du z.B. eine Lampe erst nach einigen Sekunden Dauerbewegung einschalten möchtest. Ist die Verzögerungszeit z.B. 10 Sekunden, wartet der Sensor diese Zeit, bevor er ein angeschlossenes Gerät aktiviert oder ein Signal sendet.
Einige PIR-Sensormodule erlauben die Einstellung von Blockier- und Verzögerungszeit, andere haben feste Zeiten. Es gibt viele PIR-Sensormodule, die meisten basieren auf dem AS312 PIR-Sensor, den wir im nächsten Abschnitt besprechen.
AS312 PIR-Sensor
Das Bild unten zeigt den AS312 PIR-Sensor und eine Draufsicht mit markierten pyroelektrischen Elementen. Die Fresnel-Linse wurde entfernt.

Der AS312 arbeitet mit 2,7-3,3V und verbraucht nur sehr wenig Strom (15 μA). Er hat eine Blockier- und Verzögerungszeit von 2,3 Sekunden.
Der AS312 hat bereits viel Elektronik integriert (siehe Datasheet), benötigt aber eine stabile Versorgungsspannung (Spannungsregler) und einige weitere Bauteile, um ihn in einer Schaltung zu verwenden. Deshalb gibt es verschiedene PIR-Sensormodule, die diese Bauteile hinzufügen und zusätzliche Funktionen wie längere Verzögerungszeiten und Empfindlichkeitseinstellungen bieten.
Im nächsten Abschnitt schauen wir uns drei gängige PIR-Sensormodule an und ich gebe Empfehlungen, welche sich für die ESP32-CAM eignen.
AM312 PIR-Modul
Das AM312 PIR-Modul ist das einfachste und kleinste der drei hier besprochenen PIR-Module. Es hat eine feste Verzögerungs- und Blockierzeit von etwa 2 Sekunden und keine Empfindlichkeitseinstellung.

Es besteht nur aus dem AS312 PIR-Sensor, einem HT7530 Spannungsregler und einem Ausgangswiderstand (20K). Siehe internes Schaltbild unten. Beachte, dass keine Verpolungsschutz vorhanden ist und der Sensor leicht zerstört werden kann, wenn er falsch angeschlossen wird.

Das Modul hat drei Pins: positive Versorgung (VIN), Masse (GND) und Ausgang (OUT). Die Versorgungsspannung liegt zwischen 2,7 und 12 Volt, der Ausgang ist 3,3 Volt (TTL), wenn Bewegung erkannt wird. Die Erfassungsreichweite beträgt 3-5 m, der Erfassungswinkel ca. 100°.
Das ist der Sensor, den ich für die bewegungsaktivierte ESP32-CAM empfehle. Er hat kurze Verzögerungs- und Blockierzeiten (2 Sekunden), was uns erlaubt, etwa alle 4 Sekunden ein Bild zu machen. Er kann direkt an einen GPIO-Pin der ESP32-CAM angeschlossen werden und funktionierte in meinen Tests zuverlässig.
Wenn du jedoch eine größere Reichweite und eine Aktivierung nur nachts möchtest, empfehle ich den HC-SR501, den wir im nächsten Abschnitt besprechen.
HC-SR501 PIR-Modul
Der HC-SR501 ist der am häufigsten in Haushaltsanwendungen verwendete Bewegungssensor, z.B. für bewegungsaktivierte Nachtlichter. Er ist leicht an seiner großen Fresnel-Linse zu erkennen. Siehe Bild unten.

Schaltplan des HC-SR501
Der Schaltplan des HC-SR501 ist deutlich komplexer als der des AM312, da er eine einstellbare Empfindlichkeit (Reichweite) und Verzögerungszeit bietet. Er verwendet auch den RE200B PIR Sensor statt des AS312 PIR-Sensors. Siehe Schaltplan unten.

Die Verzögerungszeit kann von etwa 0,3 Sekunden bis 300 Sekunden eingestellt werden. Die Blockierzeit beträgt etwa 2,5 Sekunden. Der HC-SR501 erlaubt es, Bilder etwas häufiger aufzunehmen als der AS312 (3 Sekunden vs. 4 Sekunden).
Minimale Verzögerung einstellen
Da wir die Verzögerungszeit per Software steuern wollen, stellen wir die Hardware-Verzögerung auf das Minimum. Drehe dazu das linke Potentiometer gegen den Uhrzeigersinn auf die unten gezeigte Position. So erhältst du die minimale Verzögerungszeit von ca. 0,3 Sekunden.

Es ist am besten, das zuerst ohne ESP32-CAM auszuprobieren, um Komplikationen zu vermeiden. Schau dir unser Tutorial How to use HC-SR501 PIR Motion Sensor an. Es enthält eine einfache Beispielschaltung, die zeigt, wie eine LED eingeschaltet wird, wenn der Sensor Bewegung erkennt.
Das andere Potentiometer des HC-SR501-Moduls erlaubt die Einstellung der Erfassungsreichweite (Empfindlichkeit) von etwa 2 m bis maximal ca. 7 m. Der HC-SR501 hat außerdem einen Jumper zur Änderung des Auslösemodus. Mehr Details dazu findest du in unserem Tutorial How to use HC-SR501 PIR Motion Sensor oder diesem Datasheet of the HC-SR501.
Nachtaktivierung über LDR
Der größte Vorteil (neben der größeren Reichweite) des HC-SR501 gegenüber dem AM312 ist, dass du einen LDR (lichtabhängigen Widerstand) hinzufügen kannst, sodass der Sensor nur nachts aktiv wird. Das ist ideal für die Überwachung nachtaktiver Tiere. Diese Funktion ist nicht gut dokumentiert, aber wenn du die Fresnel-Linse abnimmst, siehst du zwei Durchgangsbohrungen mit der Bezeichnung RL und RT. Siehe Bild unten.

Der RT-Anschluss (Resistor Temperature) erlaubt den Anschluss eines Thermistors, der Fehlalarme durch Temperaturschwankungen reduziert. Der RL-Anschluss (Resistor Light) erlaubt den Anschluss eines LDR, der sicherstellt, dass die Bewegungserkennung nur nachts aktiviert wird.
Welchen spezifischen Widerstandswert du für den LDR verwenden solltest, hängt davon ab, wie dunkel es sein soll, damit der Sensor aktiv wird. Das musst du durch Ausprobieren herausfinden. Hier ist ein Link zu einem LDR kit with various resistor values, den du ausprobieren könntest. Als grobe Orientierung hat der Spannungsteiler im oben gezeigten Schaltplan einen 1MΩWiderstand. Für den Anfang solltest du einen LDR in einem ähnlichen Bereich wählen.
Eingänge und Ausgänge
Die Ein- und Ausgänge des HC-SR501 sind im Wesentlichen die gleichen wie beim AM312. Du musst eine Versorgungsspannung an den VCC- und GND-Pins zwischen 4,5V und 20V anlegen, und der Ausgangspin geht auf 3,3V (high), wenn Bewegung erkannt wird. Das Bild unten zeigt die Pinbelegung.

Zusammenfassend: Wenn du einen kleinen, einfachen und günstigen PIR-Sensor möchtest, nimm den AM312. Er funktioniert gut. Für größere Reichweite und Bewegungserkennung nur nachts nimm den HC-SR501.
Im nächsten Abschnitt bespreche ich kurz den HC-SR505, der sich als ungeeignet erwiesen hat und für diese Anwendung nicht empfohlen wird.
HC-SR505 PIR-Modul
Das HC-SR505 PIR-Modul ist etwas länger als der AM312, verwendet aber denselben AS312 PIR-Sensor und hat dieselbe Pinbelegung. Siehe Bild unten.

Die Versorgungsspannung liegt zwischen 4,5V und 20V, der Ausgang ist TTL (3,3V). Die Erfassungsreichweite beträgt 3-4 Meter (9-12 Fuß) und die Verzögerungszeit ist fest auf etwa 8 Sekunden eingestellt.
Abgesehen von der langen Verzögerungszeit, die dich auf ein Bild alle 8 Sekunden beschränkt, hatte ich Probleme mit dem Sensor, als ich ihn mit einer 5V Powerbank versorgte. Ich testete mehrere HC-SR505 Sensoren, aber der Ausgang blieb immer high. Ich vermute, dass die hochfrequenten Störungen der Powerbank das Problem verursachten (mehr dazu später).
Der HC-SR501 und AM312 hatten mit dieser Powerbank keine Probleme, aber der HC-SR505 PIR-Modul funktionierte nicht richtig. Auch bei Betrieb mit einer 9V-Batterie oder einem Paar 18650-Akkus, die keine Störungen haben, funktionierte der HC-SR505 nicht und war immer an. Ich vermute, dass hochfrequente Störungen zwischen ESP32-CAM und HC-SR505 die Ursache sind.
Kurz gesagt: Das HC-SR505 PIR-Modul ist für bewegungsaktivierte Bildaufnahme mit der ESP32-CAM nicht geeignet. Beachte jedoch, dass ich den HC-SR505 in anderen Projekten ohne Probleme verwendet habe.
Kommen wir nun zum ESP32-CAM Modul selbst.
Vorstellung des AI-Thinker ESP32-CAM
Das AI-Thinker ESP32-CAM Entwicklungsboard ist ein kompaktes Modul, das einen ESP32-S Chip, eine Kamera, einen eingebauten Blitz und einen microSD-Kartensteckplatz kombiniert. Das Board hat integriertes Wi-Fi und Bluetooth und unterstützt eine OV2640 oder OV7670 Kamera mit bis zu 2 Megapixel Auflösung.


Mehr Details zum ESP32-CAM Board und insbesondere zum Hochladen von Code findest du in unserem Tutorial Programming the ESP32-CAM. Lies es unbedingt, da das Hochladen auf das ESP32-CAM Board knifflig ist. In diesem Tutorial konzentriere ich mich auf die Umsetzung der Bewegungsaktivierung für die ESP32-CAM.
Pinbelegung
Das folgende Bild zeigt die Pinbelegung des ESP32-CAM. Theoretisch kann die ESP32-CAM mit 3,3V betrieben werden, aber es wurde von instabilem Verhalten berichtet. Du kannst 5V bis 15V verwenden, aber ich würde nicht über 12V gehen, da der Spannungsregler sonst sehr heiß werden kann. Später sprechen wir ausführlicher über verschiedene Stromversorgungsoptionen.

Der P_OUT Pin ist auf manchen Boards als VCC beschriftet. Er ist ein Ausgangspin, der je nach solder pad 3,3V oder 5V ausgibt. Du kannst diesen Pin nicht zur Stromversorgung des Boards verwenden! Nutze dafür den 5V Pin.
Beachte, dass die meisten GPIO-Pins der ESP32-CAM bereits von der Kamera und dem SD-Kartenleser belegt sind. Außerdem solltest du GPIO1, GPIO3 und GPIO0 meiden, da sie für das Programmieren benötigt werden. GPIO0 ist mit dem Kamera-XCLK-Pin verbunden und sollte beim Betrieb der ESP32 frei bleiben (nicht verbunden).
Schließlich werden die GPIO-Pins 2, 4, 12, 13, 14 und 15 teilweise vom SD-Kartenleser verwendet. Wenn du den SD-Kartenleser nicht nutzt, sind sie als GPIO verfügbar. Mehr Details findest du in unserem More GPIO pins for ESP32-CAM Tutorial.
Im Folgenden verwenden wir GPIO 13 für die Bewegungsaktivierung. Wie man einen PIR-Bewegungssensor an die ESP32-CAM anschließt, wird im nächsten Abschnitt beschrieben.
Anschluss des PIR-Sensors an die ESP32-CAM
Der Anschluss des AM312 PIR-Sensormoduls an die ESP32-CAM ist sehr einfach. Verbinde eine Stromversorgung (Batterie) mit 5V (bis zu 12V) mit dem 5V- und GND-Pin der ESP32-CAM wie unten gezeigt (rote und blaue Kabel).

Du kannst auch mehr als 5V zur Stromversorgung des Boards verwenden. Keine Sorge, ein Spannungsregler am 5V-Pin reduziert die Eingangsspannung auf das benötigte Niveau. Aber gehe nicht über 12V, sonst wird der Spannungsregler zu heiß.
Verbinde ebenso das AM312 PIR-Sensormodul mit der Stromversorgung (rote und blaue Kabel). Achte auf die richtige Polung, da der AM312 keinen Verpolungsschutz hat. Verbinde dann den Ausgang S oder OUT des AM312 mit dem GPIO13-Pin der ESP32-CAM (grünes Kabel).
Schließe den AM312 nicht an den 3,3V-Pin zur Stromversorgung an. Theoretisch wäre das möglich, aber in der Praxis hatte ich Erkennungsprobleme bei 3,3V Betrieb. Wenn du stattdessen das HC-SR501 PIR-Sensormodul verwendest, schließe es genauso an (GND an GND, VCC an 5V-12V).
Sowohl der AM312 als auch der HC-SR501 können mit 5V bis 12V versorgt werden. Du kannst also die ESP32-CAM und den PIR-Sensor mit derselben Stromquelle (Batterie) und Spannung betreiben.
Transistorschaltung
Viele Tutorials schlagen eine Transistorschaltung vor, wenn man einen PIR-Sensor an die ESP32-CAM anschließt. Das ist NICHT nötig! Der Ausgang des PIR-Sensors (auch der schwache des AM312) kann problemlos den GPIO-Eingang treiben. Der direkte Anschluss des PIR-Sensors an die ESP32-CAM funktioniert gut und ist viel einfacher.
Code hochladen
Wenn du einen FTDI USB-TTL Adapter verwendest, kannst du den PIR-Sensor während des Hochladens und Testens angeschlossen lassen. Beim USB-TTL Shield musst du den PIR-Sensor jedes Mal ab- und wieder anschließen, was ziemlich lästig ist.
Ich empfehle daher dringend den FTDI USB-TTL Adapter. Das Bild unten zeigt, wie das aussieht. Du brauchst nicht mal ein Steckbrett, nur ein paar Dupont-Kabel.

Details zum Anschluss des FTDI USB-TTL Adapters und zum Hochladen von Code findest du in unserem Tutorial Programming the ESP32-CAM. Im nächsten Abschnitt zeige ich dir den Code für die bewegungsaktivierte ESP32-CAM.
Code für die bewegungsaktivierte ESP32-CAM
Der folgende Code ist eine vollständige Implementierung für eine bewegungsaktivierte ESP32-CAM. Schau ihn dir zuerst kurz an, um einen Überblick zu bekommen, bevor wir ins Detail gehen.
Dieser Code versetzt die ESP32-CAM in den Tiefschlaf und wartet auf ein Signal an GPIO13, das anzeigt, dass der PIR-Sensor Bewegung erkannt hat. Bei Bewegung wacht die ESP32-CAM auf, macht ein Bild, speichert es mit einer fortlaufenden Nummer auf der SD-Karte und geht wieder schlafen.
// Motion activated ES32-CAM
// Makerguides.com
#include "esp_camera.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/rtc_io.h"
#include "SD_MMC.h"
#include "EEPROM.h"
// CAMERA_MODEL_AI_THINKER
#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
void configCamera() {
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_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
esp_err_t err = esp_camera_init(&config);
sensor_t* s = esp_camera_sensor_get();
s->set_brightness(s, 0);
s->set_contrast(s, 0);
s->set_saturation(s, 0);
s->set_special_effect(s, 0);
s->set_whitebal(s, 1);
s->set_awb_gain(s, 1);
s->set_wb_mode(s, 0);
s->set_exposure_ctrl(s, 1);
s->set_aec2(s, 0);
s->set_ae_level(s, 0);
s->set_aec_value(s, 300);
s->set_gain_ctrl(s, 1);
s->set_agc_gain(s, 0);
s->set_gainceiling(s, (gainceiling_t)0);
s->set_bpc(s, 0);
s->set_wpc(s, 1);
s->set_raw_gma(s, 1);
s->set_lenc(s, 1);
s->set_hmirror(s, 0);
s->set_vflip(s, 0);
s->set_dcw(s, 1);
s->set_colorbar(s, 0);
}
unsigned int incCounter() {
unsigned int cnt = 0;
EEPROM.get(0, cnt);
EEPROM.put(0, cnt + 1);
EEPROM.commit();
return cnt;
}
void enableFlash(bool enable) {
if (enable) {
rtc_gpio_hold_dis(GPIO_NUM_4);
} else {
pinMode(GPIO_NUM_4, OUTPUT);
digitalWrite(GPIO_NUM_4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
}
}
void skipPictures(int n) {
for(int i=0; i<n; i++) {
camera_fb_t* fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
}
}
void takePicture() {
camera_fb_t* fb = esp_camera_fb_get();
unsigned int cnt = incCounter();
String path = "/img" + String(cnt) + ".jpg";
File file = SD_MMC.open(path.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);
file.close();
esp_camera_fb_return(fb);
}
void deepSleep(int atleast) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
rtc_gpio_pulldown_en(GPIO_NUM_13);
rtc_gpio_pullup_dis(GPIO_NUM_13);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1);
delay(atleast);
esp_deep_sleep_start();
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
enableFlash(true);
EEPROM.begin(8);
SD_MMC.begin();
configCamera();
skipPictures(10);
takePicture();
enableFlash(false);
deepSleep(5000);
}
void loop() {
}
Lass uns den Code Schritt für Schritt durchgehen, um zu verstehen, wie die Kamera eingerichtet wird und der Bildaufnahmeprozess funktioniert.
Includes
Im ersten Teil binden wir die notwendigen Bibliotheken für die Steuerung der Kamera, der SD-Karte und des EEPROM ein. Außerdem brauchen wir einige Funktionen für die Echtzeituhr (RTC) während des Tiefschlafs.
#include "esp_camera.h" #include "soc/rtc_cntl_reg.h" #include "driver/rtc_io.h" #include "SD_MMC.h" #include "EEPROM.h"
Konstanten
Es gibt verschiedene Modelle von ESP32-CAM Boards. Dieser Code ist speziell für das AI-Thinker Modell, funktioniert aber auch mit den meisten anderen ESP32-basierten Kameraboards, sofern sie PSRAM haben (siehe model definitions here).
Im folgenden Codeabschnitt definieren wir die Pins, die für das AI-Thinker Modell spezifisch sind. Wenn du ein anderes ESP32-CAM Board hast, musst du diese Konstanten wahrscheinlich anpassen. Hier findest du die pin definitions für andere unterstützte Modelle.
// CAMERA_MODEL_AI_THINKER #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
Kamera-Konfiguration
Die configCamera() Funktion richtet die Kamera mit spezifischen Einstellungen ein, wie LEDC-Kanal, Pins für Datenleitungen, Taktsignale und Bildeinstellungen wie Format, Größe und Qualität. Wenn du mit der Bildqualität der ESP32-CAM nicht zufrieden bist, solltest du mit diesen Einstellungen experimentieren.
void configCamera() {
sensor_t* s = esp_camera_sensor_get();
s->set_brightness(s, 0);
s->set_contrast(s, 0);
...
s->set_colorbar(s, 0);
}
Zähler erhöhen
Die incCounter() Funktion liest einen im EEPROM gespeicherten Zähler aus und erhöht ihn. Dieser Zähler wird verwendet, um die aufgenommenen Bilder fortlaufend zu benennen. Jedes Mal, wenn die Funktion aufgerufen wird, wird der Zähler erhöht. Der Zähler muss in EEPROM gespeichert werden, damit er im Tiefschlaf nicht verloren geht.
unsigned int incCounter() {
unsigned int cnt = 0;
EEPROM.get(0, cnt);
EEPROM.put(0, cnt + 1);
EEPROM.commit();
return cnt;
}
Der Code ist sehr einfach. Zuerst lesen wir den aktuellen Zähler mit EEPROM.get(0, cnt) aus, speichern dann den inkrementierten Zähler mit EEPROM.put(0, cnt + 1 und bestätigen die Änderung mit EEPROM.commit(). Schließlich geben wir den aktuellen Zähler zurück. Beim nächsten Aufruf wird der gerade gespeicherte, erhöhte Zähler zurückgegeben und erneut erhöht.
Beachte, dass wir Speicherplatz für den Zähler im EEPROM reservieren müssen. Das geschieht später durch den Aufruf von EEPROM.begin(8) in der setup() Funktion. Der Zähler ist ein 4-Byte großer unsigned Integer. Ich reserviere vorsichtshalber 8 Bytes Speicher – für alle Fälle.
Ein 4-Byte großer unsigned Integer kann bis zu 4.294.967.295 zählen, bevor er überläuft. Das ist definitiv groß genug, um alle Bilder auf der SD-Karte eindeutig zu nummerieren.
Blitzsteuerung
Die enableFlash() Funktion schaltet den Blitz ein oder aus, abhängig vom enable Parameter. Das ist ein kniffliger Teil. Das Problem bei der ESP32-CAM ist, dass beim Schreiben auf die SD-Karte die Blitz-LED angeht und im Tiefschlaf die Blitz-LED an bleibt.
Einfaches Schreiben von LOW auf GPIO4, an dem die Blitz-LED angeschlossen ist, reicht nicht aus. Im Tiefschlaf geht dieser Ausgangszustand verloren. Um GPIO4 während des Tiefschlafs niedrig zu halten, muss man rtc_gpio_hold_en(GPIO_NUM_4) aufrufen, was dem ESP32 sagt, den Zustand von GPIO4 im Tiefschlaf zu erhalten.
Aber GPIO4 ist auch Teil der SD-Karten-Schnittstelle, daher können wir ihn nicht dauerhaft auf diesem Pegel halten. Wenn die ESP32-CAM aufwacht, deaktivieren wir das Halten von GPIO4 mit rtc_gpio_hold_dis(GPIO_NUM_4) und überlassen der ESP32-CAM die Steuerung für die Bildaufnahme und das Schreiben auf die SD-Karte.
Bevor wir die ESP32-CAM in den Tiefschlaf versetzen, rufen wir enableFlash(false) auf, das die Blitz-LED ausschaltet und diesen Zustand im Tiefschlaf erhält.
void enableFlash(bool enable) {
if (enable) {
rtc_gpio_hold_dis(GPIO_NUM_4);
} else {
pinMode(GPIO_NUM_4, OUTPUT);
digitalWrite(GPIO_NUM_4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
}
}
Bilder überspringen
Die SkipPictures(n) Funktion nimmt n Bilder auf und verwirft sie. Der Grund dafür ist folgender: Die Kamera hat mehrere automatische Funktionen, z.B. automatische Weißabgleichung, die einige Zeit und mehrere Bilder benötigen, um sich an die Umgebung anzupassen. Nach einem Neustart aus dem Tiefschlaf müssen wir der Kamera also etwas Zeit geben.
void skipPictures(int n) {
for(int i=0; i<n; i++) {
camera_fb_t* fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
}
}
Wenn du das erste Bild nach dem Neustart aufnimmst, ist die Qualität meist schlecht – oft mit starkem Blaustich oder zu dunkel/hell. Nach dem Überspringen der ersten Bilder erhältst du meist (aber nicht immer) gute Bildqualität.
Du könntest auch versuchen, automatische Weißabgleichung und andere automatische Funktionen in den Kameraeinstellungen zu deaktivieren, aber dann brauchst du eine recht stabile Umgebung, um die anderen Einstellungen zu optimieren. Sonst wird es schwer, gute Bilder zu bekommen.
Bild aufnehmen
Die takePicture() Funktion nimmt ein Bild mit der Kamera auf und speichert es auf der SD-Karte mit einem eindeutigen Dateinamen basierend auf dem Zählerwert. Zuerst erstellen wir einen Frame-Buffer fb durch Aufruf von esp_camera_fb_get(). Dann erzeugen wir einen eindeutigen Dateinamen (img{cnt}.jpg) und speichern den Frame-Buffer als JPG-Datei auf der SD-Karte. Schließlich geben wir den vom Frame-Buffer belegten Speicher mit esp_camera_fb_return wieder frei.
void takePicture() {
camera_fb_t* fb = esp_camera_fb_get();
unsigned int cnt = incCounter();
String path = "/img" + String(cnt) + ".jpg";
File file = SD_MMC.open(path.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);
file.close();
esp_camera_fb_return(fb);
}
Tiefschlaf
Die deepSleep() Funktion versetzt die ESP32 für eine bestimmte Dauer nach der Bildaufnahme in den Tiefschlaf. Das spart Energie, wenn das Gerät nicht aktiv Bilder macht.
Die drei Zeilen am Anfang (esp_sleep_pd_config, rtc_gpio_pulldown_en, rtc_gpio_pullup_dis) aktivieren den internen Pull-Down-Widerstand an GPIO13, an dem der PIR-Sensor angeschlossen ist. Der Code/ESP32-CAM funktioniert auch ohne internen Pull-Down, aber ich wollte hier auf Nummer sicher gehen.
Danach legen wir die Weckquelle mit esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1) fest. Das bedeutet, wenn GPIO13 auf high geht (1 = PIR-Sensor hat Bewegung erkannt), wecken wir die ESP32-CAM aus dem Tiefschlaf.
Bevor wir in den Tiefschlaf gehen, warten wir mit delay für ein paar Sekunden (atleast), um zu verhindern, dass zu häufig Bilder aufgenommen werden. Ich habe 5 Sekunden verwendet, schneller geht wegen der Blockier- und Verzögerungszeiten des PIR-Sensors nicht. Du kannst die Zeit aber auch verlängern, z.B. auf 10 oder 60 Sekunden, wenn du weniger Bilder machen möchtest.
void deepSleep(int atleast) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
rtc_gpio_pulldown_en(GPIO_NUM_13);
rtc_gpio_pullup_dis(GPIO_NUM_13);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1);
delay(atleast);
esp_deep_sleep_start();
}
Setup-Funktion
Die setup() Funktion verbindet alles miteinander. Zuerst rufen wir WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) auf, um die brownout Erkennung zu deaktivieren. Sollte die Stromversorgung instabil sein oder die ESP32-CAM beim Start von WiFi oder Schreiben auf die SD-Karte zu viel Strom ziehen, verhindert das einen automatischen Reset. Mehr Details dazu in diesem Blogpost Disabling the ESP32 Brownout detector.
Ich hatte keine Probleme mit Brownouts und du kannst die Zeile wahrscheinlich deaktivieren. Der Vorteil der Brownout-Erkennung ist, dass sie das Risiko von SD-Kartenbeschädigungen verringert. Der Nachteil ist, dass sie unerwünschte Resets verursachen kann. Es hängt von deiner Stromversorgung ab, was besser ist.
Nach der Brownout-Konfiguration aktivieren wir die Blitz-LED mit enableFlash(true). Dann reservieren wir 8 Bytes Speicher im EEPROM für den Dateizähler, initialisieren die SD-Karte mit SD_MMC.begin() und konfigurieren die Kamera.
Schließlich nehmen wir das Bild mit unserer takePicture() Funktion auf. Danach schalten wir die Blitz-LED aus und versetzen die ESP32-CAM in den Tiefschlaf (mindestens 5 Sekunden).
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
enableFlash(true);
EEPROM.begin(8);
SD_MMC.begin();
configCamera();
takePicture();
enableFlash(false);
deepSleep(5000);
}
Loop-Funktion
Die loop() Funktion ist in diesem Code leer, da die Hauptfunktionalität in der Setup-Funktion implementiert ist. Die ESP32 führt die Setup-Funktion aus, geht dann in den Tiefschlaf, wacht bei Bewegung auf und führt die Setup-Funktion erneut aus. Die Loop-Funktion läuft nie.
void loop() {
// Empty loop
}
Und das war’s. Hier hast du den kompletten Code für eine bewegungsaktivierte ESP32-CAM.
Beim Ausführen des Codes fällt dir vielleicht auf, dass der Dateizähler bei einer beliebigen Zahl startet und nicht bei Null. Du kannst den Zähler zurücksetzen, indem du den folgenden Code ausführst.
Dateizähler zurücksetzen
Das Hochladen und Ausführen des Codes unten setzt den im EEPROM an Adresse 0 gespeicherten Zähler auf Null zurück. Danach musst du den ursprünglichen Bildaufnahme-Code erneut hochladen.
#include "EEPROM.h"
void setup() {
EEPROM.begin(512);
unsigned int cnt = 0;
EEPROM.put(0, cnt);
EEPROM.commit();
}
void loop() {
}
Wir haben den Code, wir haben die Verkabelung – jetzt sprechen wir über die Stromversorgung des Projekts.
Batteriebetriebene ESP32-CAM
Oft möchte man eine bewegungsaktivierte ESP32-CAM batteriebetrieben betreiben, z.B. zur Wildtierbeobachtung. Die passende Stromquelle zu finden, ist gar nicht so einfach. Im Folgenden zeige ich dir vier Optionen, die ich ausprobiert habe.
USB Power Bank 1
Die erste Option ist eine gängige USB Power Bank. Jeder mit einem Handy hat so eine, um das Telefon im Notfall aufzuladen. Ich habe die unten abgebildete Power Bank ausprobiert.

Das ist eine 30000mAh Power Bank, die die ESP32-CAM lange betreiben könnte. Allerdings hat diese Power Bank eine automatische Abschaltung. Wenn die Last am Ausgang sehr gering ist (<80mA), was passiert, wenn die ESP32-CAM im Tiefschlaf ist (6mA), schaltet sich die Power Bank ab.
Die ESP32-CAM lief etwa 10-15 Sekunden, machte ein paar Bilder und wachte dann nie wieder auf. Es hat mich viel Zeit gekostet, das herauszufinden, da ich dachte, mein Code oder die Verkabelung sei fehlerhaft : (
Lektion gelernt: Verwende keine Power Bank mit automatischer Abschaltung für dieses Projekt.
USB Power Bank 2
Ich hatte eine zweite Power Bank mit 10000mAh Kapazität, siehe Bild unten.

Diese Power Bank schaltet sich nicht automatisch ab, aber beim Test mit dem HC-SR505 PIR-Modul funktionierte der Sensor nicht richtig. Der Ausgang war immer high, selbst wenn das Modul isoliert (ohne ESP32-CAM) mit Strom und einer LED betrieben wurde.
Ein Oszilloskop zeigte, dass diese Power Bank auf ihrem 5V-Ausgang eine sichtbare Ripple mit etwa 160Hz und 88mV Amplitude hat. Ich vermute, das verursachte die Probleme mit dem HC-SR505, da dieser Sensor mit einer 9V-Batterie problemlos funktionierte.

Während die ESP32-CAM mit HC-SR501 oder AM312 PIR-Sensor mit dieser Power Bank gut funktionierte, war ich bezüglich des Langzeitverhaltens etwas besorgt. Würde das Setup über Tage oder Wochen zuverlässig laufen?

Ich denke, die bessere Option ist eine einfache, wiederaufladbare Batterie ohne interne Power-Boost-Schaltung wie bei USB Power Banks, die diese Ripple im Ausgang verursachen.
9V wiederaufladbare Batterie
Zur Stromversorgung der ESP32-CAM inklusive PIR-Sensor kannst du einfach eine 9V-Batterie verwenden. Ich habe eine wiederaufladbare 9V-Batterie mit 1000mAh Kapazität direkt an den 5V-Pin der ESP32-CAM und den VCC-Pin des PIR-Sensors angeschlossen.

Dieses Setup funktioniert gut, aber die Laufzeit ist nicht großartig. Während die ESP32-CAM im Tiefschlaf nur 6mA verbraucht, zieht sie im aktiven Zustand bis zu 240mA. Im Tiefschlaf könnten wir also 1000mAh / 6mA = 166,67 Stunden = 6,9 Tage laufen, was nicht schlecht ist. Bei häufigem Fotografieren wird die Laufzeit aber deutlich kürzer.
Das kurze Video unten zeigt, dass die ESP32-CAM mit einem AM312 PIR-Sensormodul mit einer 9V-Batterie betrieben werden kann.

Im nächsten Abschnitt schauen wir uns Batterien mit höherer Kapazität an, um die Laufzeit zu erhöhen.
18650 wiederaufladbarer Akku-Pack
Also nehmen wir eine größere Batterie. Ein 18650 Lithium-Ionen-Akku hat eine Nennspannung von 3,6V und Kapazitäten von 1800mAh bis 2800mAh. Zwei davon in Reihe ergeben 7,2V Ausgangsspannung, was gut für die ESP32-CAM ist und etwas Spannungsspielraum lässt.

Mit 2800mAh Kapazität können wir die Laufzeit fast verdreifachen (im Vergleich zur 1000mAh Batterie). Wenn mehr Kapazität benötigt wird, können wir einfach ein zweites Paar 18650-Akkus hinzufügen und die Laufzeit erneut verdoppeln.
Achte aber auf die richtige Polung beim Anschluss der Akkus. Die 18650 können hohe Ströme liefern, und ich habe einen meiner PIR-Sensoren durch falschen Anschluss zerstört.
Im nächsten Abschnitt versuche ich, eine bessere Abschätzung der Laufzeit zu geben.
Laufzeit
Ich habe den Tiefschlafstrom der ESP32-CAM mit angeschlossenem AM312 PIR-Sensor gemessen und 3,6mA im Tiefschlaf erhalten. Im aktiven Zustand beim Bildmachen lag der Stromverbrauch bei etwa 120mA.
Wenn wir die zwei 18650 lithium-ion batteries in Reihe mit einer Gesamtkapazität von 2800mAh verwenden, ergibt das 2800mAh / 3,6mA = 777,7 Stunden = 32 Tage Laufzeit im Tiefschlaf. Das ist ein Monat Laufzeit, ohne Bilder zu machen.
Nehmen wir an, wir machen während dieser Zeit 100 Bilder. Da die ESP32-CAM bei jedem Bild 5 Sekunden aktiv ist, ergibt das 100 * 120mA * 5 Sek / 3600 Sek = ca. 1000mAh Verbrauch.
Wenn wir diese 1000mAh von der Batteriekapazität von 2800mAh abziehen, bleiben 1800mAh für den Tiefschlaf übrig. Das ergibt 1800mAh / 3,6mA = 500 Stunden = 20 Tage Laufzeit. Fast drei Wochen, das ist ordentlich. Natürlich können niedrige Außentemperaturen oder viele Bilder die Laufzeit stark reduzieren. Andererseits ist das Hinzufügen eines zweiten 18650-Paars einfach und verdoppelt die Laufzeit.
Fazit
In diesem Tutorial haben wir erfolgreich eine bewegungsaktivierte ESP32-CAM mit einem PIR-Sensor gebaut. Wir haben die Grundlagen der PIR-Bewegungssensoren kennengelernt und wie man sie an die AI-Thinker ESP32-CAM anschließt. Mit dem bereitgestellten Code kann unsere ESP32-CAM nun Bilder aufnehmen, sobald Bewegung erkannt wird.
Wenn du benachrichtigt werden möchtest, sobald Bewegung erkannt wird, schau dir unser ESP32 send Telegram Message Tutorial an, das zeigt, wie du Nachrichten an die Telegram-App auf deinem Handy sendest.
Außerdem haben wir die Möglichkeit untersucht, die ESP32-CAM mit Batterien zu betreiben, um eine portablere Lösung zu schaffen. Dieses Projekt eröffnet viele Möglichkeiten für Überwachungssysteme, Wildtierkameras oder jede Anwendung, die Bewegungserkennung und Bildaufnahme benötigt.
Die wichtigsten Erkenntnisse sind, dass man bei der Auswahl der PIR-Bewegungssensoren und der Batterieversorgung vorsichtig sein muss. Die ESP32-CAM zum Laufen zu bringen ist nicht einfach, aber das Ergebnis lohnt sich.
Viel Spaß!
Häufig gestellte Fragen
Hier sind einige häufige Fragen und Lösungen zur Fehlerbehebung:
F: Gibt es bestimmte PIR-Sensoren, die am besten mit der ESP32-CAM funktionieren?
A: Ja, verwende den HC-SR501 oder AM312. Verwende nicht den HC-SR505, da seine Verzögerungszeit zu lang ist und er Probleme mit der ESP32-CAM hat.
F: Wie kann ich die Empfindlichkeit des PIR-Sensors einstellen?
A: Einige PIR-Sensoren (einschließlich HC-SR501) haben ein Potentiometer, mit dem du die Empfindlichkeit einstellen kannst. Durch Drehen des Potentiometers kannst du die Erfassungsreichweite feinjustieren.
F: Kann ich die ESP32-CAM mit einer Batterie betreiben?
A: Ja, du kannst die ESP32-CAM batteriebetrieben für eine portable Lösung verwenden. Wenn du eine USB Power Bank nutzt, achte darauf, dass sie keine automatische Abschaltung hat. Besser sind zwei 18650-Akkus oder eine andere Batterie mit stabiler Versorgung im Bereich von 5V bis 12V.
F: Muss ich den Code für verschiedene PIR-Sensoren anpassen?
A: Der in diesem Tutorial bereitgestellte Code ist generisch und sollte mit den meisten PIR-Sensoren funktionieren.
F: Wie groß ist die Reichweite eines PIR-Sensors zur Bewegungserkennung?
A: Das hängt vom Sensor und den Umgebungsbedingungen ab, typischerweise etwa 5 Meter. Beachte, dass der Sensor nicht hinter Glas platziert werden kann und keine Objekte mit der gleichen Temperatur wie die Umgebung erkennt.
F: Gibt es alternative Bewegungssensoren, die mit der ESP32-CAM verwendet werden können?
A: Ja, es gibt andere Bewegungssensoren wie Ultraschallsensoren, Lichtschranken oder Mikrowellensensoren, die ebenfalls mit der ESP32-CAM verwendet werden können.
F: Wie kann ich die Batterielaufzeit der ESP32-CAM verlängern?
A: Um die Batterielaufzeit zu verlängern, kannst du die Verzögerungszeit erhöhen. Außerdem verlängert eine Batterie mit höherer Kapazität die Laufzeit.
F: Warum haben die Bilder der ESP32-CAM nach einem Neustart einen Blaustich?
A: Die Kamera hat automatische Funktionen, z.B. automatischen Weißabgleich, die Zeit brauchen, um sich an die Umgebung anzupassen. Ohne diese Anpassung erhältst du blaustichige oder zu dunkle/helle Bilder. Eine einfache Lösung ist, nach dem Neustart mehrere Bilder aufzunehmen und zu ignorieren. Siehe die skipPictures() Funktion im Tutorial, die genau das macht.

