ESP32とCAMERAを使用して人感センサーが動きを検知した時にキャプチャしてWIFI経由でサーバーに送信する

ESP32-CAM Wi-Fi Controlled Motion Detection Security Camera

 

この記事は、ESP32 CAMモジュール、FTDIプログラマ、PIRセンサーで構成されています。ESP32 CAMは画像をキャプチャし、WiFi経由で送信するために使用されます。FTDIプログラマはESP32 CAMのプログラミングに使用され、PIRセンサーは動き検出に使用されます。ESP32 CAMは、動きを検知すると画像をキャプチャし、分析のためにサーバーに送信するようにプログラムされています。

 

 

コンポーネントリスト

 

 

ESP32 CAM

  • 説明 : カメラモジュールを統合したマイクロコントローラ。
  • ピン : 5V、GND、GPIO12、GPIO13、GPIO15、GPIO14、GPIO2、GPIO4、3.3V、GPIO16、GPIO0、3.3V / 5V / P_OUT、GPIO3 / RX、GPIO1 / TX

 

FTDI PROGRAMMER

  • 説明 : ESP32 CAM のプログラミングに使用される USB-シリアル アダプター。
  • ピン : DTR、RX、TX、VCC、CTS、GND

 

PIRセンサー

  • 説明 : 動きを検出するために使用されるセンサー。
  • ピン : VDD、SIG、GND

 

 

配線の詳細

 

ESP32 CAM

  • 5V : FTDIプログラマVCCに接続
  • GND : FTDIプログラマGNDとPIRセンサーGNDに接続
  • GPIO13 : PIRセンサーSIGに接続
  • 3.3V / 5V / P_OUT : PIRセンサーVDDに接続
  • GPIO3 / RX : FTDIプログラマTXに接続
  • GPIO1 / TX : FTDIプログラマRXに接続

 

FTDI PROGRAMMER

 

  • VCC : ESP32 CAM 5Vに接続
  • GND : ESP32 CAM GNDに接続
  • TX : ESP32 CAM GPIO3 / RXに接続
  • RX : ESP32 CAM GPIO1 / TXに接続

 

PIRセンサー

 

  • VDD : ESP32 CAM 3.3V / 5V / P_OUTに接続
  • SIG : ESP32 CAM GPIO13に接続
  • GND : ESP32 CAM GNDに接続

 

 

コード

 

ESP32 CAMのコードはArduinoで記述されており、WiFi、HTTP、カメラ制御、WebSocket用のライブラリが含まれています。主な機能は、カメラとWiFiの初期化、PIRセンサーによる動きの検知、画像のキャプチャ、そして分析用サーバーへの送信です。

 

初期化処理

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <esp_camera.h>
#include <base64.h>
#include <ArduinoJson.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <WebSocketsClient.h>

// WiFi Configuration
#define WIFI_SSID "Gagan A Ayi"
#define WIFI_PASSWORD "29842984"
#define WEBSOCKET_SERVER "ws://localhost:12345"
#define SERVER_URL "http://localhost/fras/api"

// ESP32-CAM Pin Configuration
#define 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

// Sensor Configurations
#define PIR_SENSOR_PIN 13
#define LED_INDICATOR_PIN 4

// System Configuration
#define CONFIDENCE_THRESHOLD 0.7
#define NO_MOTION_TIMEOUT 5000  // 5 seconds to confirm no motion

// Global Variables
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");
WebSocketsClient webSocket;

String currentClassroom = "";
String currentSubject = "";
String assignedTeacher = "";
unsigned long lastMotionTime = 0;
bool isCameraActive = false;

 

関数プロトタイプ

bool initializeCamera();
bool initializeWiFi();
void captureAndSendFrame();
bool noHumansInFrame();
void syncClassroomContext();

 

セットアップ機能

void setup() {
  Serial.begin(115200);
  
  // Initialize Pins
  pinMode(PIR_SENSOR_PIN, INPUT);
  pinMode(LED_INDICATOR_PIN, OUTPUT);
  
  // Initialize Components
  if (!initializeCamera()) {
    Serial.println("Camera initialization failed!");
    return;
  }
  
  if (!initializeWiFi()) {
    Serial.println("WiFi connection failed!");
    return;
  }
  
  // Initialize Time Client
  timeClient.begin();
  timeClient.setTimeOffset(19800);  // Indian Standard Time

  // Initialize WebSocket
  String host = "localhost";
  uint16_t port = 12345;
  String url = "/";
  String protocol = "arduino";
  webSocket.begin(host, port, url, protocol);
}

 

ループ機能

void loop() {
  // Periodically sync classroom context
  static unsigned long lastContextSync = 0;
  if (millis() - lastContextSync > 300000) {  // Every 5 minutes
    syncClassroomContext();
    lastContextSync = millis();
  }
  
  // Motion Detection
  if (!isCameraActive && digitalRead(PIR_SENSOR_PIN) == HIGH) {
    // Turn on the camera and LED indicator
    lastMotionTime = millis();
    digitalWrite(LED_INDICATOR_PIN, HIGH);
    isCameraActive = true;
    captureAndSendFrame();
  }
  
  // Check for turning off the camera and LED indicator
  if (isCameraActive && millis() - lastMotionTime > NO_MOTION_TIMEOUT) {
    if (noHumansInFrame()) {
      digitalWrite(LED_INDICATOR_PIN, LOW);
      isCameraActive = false;
      Serial.println("No humans detected, turning off camera and LED");
    } else {
      lastMotionTime = millis();  // Reset the timer if a human is detected
    }
  }
  
  webSocket.loop();
}

 

カメラ機能の初期化

bool initializeCamera() {
  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_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_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;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  
  return esp_camera_init(&config) == ESP_OK;
}

 

WiFi機能の初期化

bool initializeWiFi() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  
  return WiFi.status() == WL_CONNECTED;
}

 

フレームキャプチャおよび送信機能

void captureAndSendFrame() {
  camera_fb_t* fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }
  
  // Base64 encode image
  String encodedImage = base64::encode(fb->buf, fb->len);
  
  // Send to server
  webSocket.sendTXT(encodedImage);
  
  esp_camera_fb_return(fb);
}

 

フレーム機能に人間がいない場合の処理

bool noHumansInFrame() {
  camera_fb_t* fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return false;
  }
  
  // Base64 encode image
  String encodedImage = base64::encode(fb->buf, fb->len);
  esp_camera_fb_return(fb);

  // Send to server for analysis
  HTTPClient http;
  http.begin(SERVER_URL + String("/analyze"));
  http.addHeader("Content-Type", "application/json");

  DynamicJsonDocument payload(512);
  payload["image"] = encodedImage;

 

 

以上

 

 

 

タグ