IoT ve Yapay Zekâ

Cihaz Üzerinde Yapay Zeka ve MQTT Uyarılarıyla ESP32-CAM İnsan Tespiti

Küçük bir insan tespiti modelini doğrudan ESP32-CAM üzerinde çalıştırın, güven skorunu ve debounce edilmiş uyarıları MQTT ile yayınlayın; görüntüleri gerçekten gerekmedikçe cihazda tutun.

Bir insanı tanıyan ve telefondaki gösterge paneline MQTT uyarısı gönderen küçük kamera kartıyla ESP32-CAM insan tespiti illüstrasyonu
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

ESP32-CAM insan tespiti, aşağı yukarı bir sandviç fiyatına mal olan bir karta küçük bir sinir ağı yerleştirir ve onu MQTT uyarıları yayınlayan bir varlık sensörüne dönüştürür. Bu eğitimde TensorFlow Lite Micro insan tespiti modelini bir AI-Thinker ESP32-CAM üzerinde çalıştıracak, güven skorunu ve debounce edilmiş uyarıları broker.connectmq.com'a yayınlayacak ve ilk denemelerin çoğunu tökezleten bellek ve zamanlama tuzaklarını öğreneceksiniz.

Kartın Yapabildikleri ve Yapamadıkları

ESP32-CAM, çift çekirdekli bir ESP32'yi OV2640 kamera ve çoğu kartta 4 MB PSRAM ile birleştirir. Bu, özenle tasarlanmış bir TinyML modeli için yeterlidir, ancak genel amaçlı bir nesne algılayıcı için yeterli değildir.

Yetenek ESP32-CAM Kameralı Raspberry Pi NVIDIA Jetson
Model türü İkili sınıflandırıcı (insan var / yok) Küçük algılayıcılar, sınıflandırıcılar YOLO gibi tam algılayıcılar
Girdi boyutu 96 x 96 gri tonlamalı 224 ila 640 piksel 640 piksel ve üzeri
Sınırlayıcı kutular Hayır Evet Evet
Tipik kullanım Varlık algılama, uyandırma tetikleyicisi Sayım, bölgeler Çok sınıflı, çok kameralı
Güç Uyku moduyla pil dostu Şebeke Şebeke

Burada kullanılan ve TensorFlow Lite Micro örneklerinden gelen model, her kare için tek bir soruyu yanıtlar: bu resimde bir insan var mı? Nerede olduğunu ya da kaç kişi olduğunu söylemez. Bunun için daha büyük bir modele bir olay yayınlayın veya MQTT üzerinden YOLO nesne algılama yazısına göz atın.

Parçalar ve Yazılım

  • PSRAM'li AI-Thinker ESP32-CAM ile birlikte bir USB-seri dönüştürücü veya ESP32-CAM-MB programlayıcı kartı
  • En az 500 mA verebilen kararlı bir 5 V güç kaynağı (voltaj düşmeleri bir numaralı sorundur)
  • Espressif'in esp32 kart paketi yüklü Arduino IDE 2, kart olarak "AI Thinker ESP32-CAM"
  • Kütüphaneler: PubSubClient ve TensorFlowLite_ESP32 (Library Manager)
  • TensorFlowLite_ESP32 person_detection örneğinden: person_detect_model_data.h ve person_detect_model_data.cpp dosyalarını sketch klasörünüze kopyalayın

Daha önce hiç bir ESP32'yi MQTT'ye bağlamadıysanız, ESP32 MQTT eğitimi temelleri, MQTT ile ESP32-CAM ise JPEG anlık görüntülerin yayınlanmasını anlatıyor.

İşlem Hattı Nasıl Çalışır

  1. Kamera doğrudan 96 x 96 gri tonlamalı bir kare yakalar, dolayısıyla yeniden boyutlandırma gerekmez.
  2. Pikseller, işaretsiz 0-255 aralığından nicemlenmiş (quantized) modelin beklediği işaretli int8 aralığına dönüştürülür.
  3. Yorumlayıcı modeli çalıştırır ve iki skor döndürür: "insan yok" ve "insan".
  4. Sketch insan skorunu periyodik olarak yayınlar ve yalnızca skor birkaç kare boyunca eşiğin üzerinde kaldığında uyarı üretir.
  5. Bekleme süresi (cooldown), görüş alanında duran tek bir kişinin her saniye uyarı üretmesini engeller.

Sketch'in Tamamı

Wi-Fi bilgilerini ve topic kimliğini değiştirin. broker.connectmq.com'un herkese açık alanı, boş olmayan herhangi bir client ID ile anonim bağlantıları kabul eder; ancak orada yayınlanan her şey başkaları tarafından okunabilir. Bu yüzden yalnızca skorları ve uyarıları yayınlayın, gerçek insanların görüntülerini asla yayınlamayın.

#include <WiFi.h>
#include <PubSubClient.h>
#include "esp_camera.h"
#include "esp_heap_caps.h"

#include <TensorFlowLite_ESP32.h>
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "person_detect_model_data.h"

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/pd-e51a/home/frontdoor/cam1";

const int PERSON_THRESHOLD = 60;   // yüzde
const int FRAMES_TO_RAISE = 3;
const unsigned long COOLDOWN_MS = 30000;
const unsigned long SCORE_EVERY_MS = 5000;

// AI-Thinker ESP32-CAM pin haritası
#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

WiFiClient net;
PubSubClient mqtt(net);
char clientId[32];

constexpr int kArenaSize = 100 * 1024;
uint8_t* tensorArena = nullptr;
tflite::MicroErrorReporter errorReporter;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;

int hits = 0;
unsigned long lastAlert = 0, lastScore = 0;

bool initCamera() {
  camera_config_t c = {};
  c.ledc_channel = LEDC_CHANNEL_0;
  c.ledc_timer = LEDC_TIMER_0;
  c.pin_d0 = Y2_GPIO_NUM; c.pin_d1 = Y3_GPIO_NUM; c.pin_d2 = Y4_GPIO_NUM;
  c.pin_d3 = Y5_GPIO_NUM; c.pin_d4 = Y6_GPIO_NUM; c.pin_d5 = Y7_GPIO_NUM;
  c.pin_d6 = Y8_GPIO_NUM; c.pin_d7 = Y9_GPIO_NUM;
  c.pin_xclk = XCLK_GPIO_NUM; c.pin_pclk = PCLK_GPIO_NUM;
  c.pin_vsync = VSYNC_GPIO_NUM; c.pin_href = HREF_GPIO_NUM;
  c.pin_sccb_sda = SIOD_GPIO_NUM; c.pin_sccb_scl = SIOC_GPIO_NUM;
  c.pin_pwdn = PWDN_GPIO_NUM; c.pin_reset = RESET_GPIO_NUM;
  c.xclk_freq_hz = 20000000;
  c.pixel_format = PIXFORMAT_GRAYSCALE;
  c.frame_size = FRAMESIZE_96X96;
  c.fb_count = 1;
  c.fb_location = CAMERA_FB_IN_PSRAM;
  c.grab_mode = CAMERA_GRAB_LATEST;
  return esp_camera_init(&c) == ESP_OK;
}

bool initModel() {
  tensorArena = (uint8_t*)heap_caps_malloc(kArenaSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
  if (!tensorArena) return false;
  const tflite::Model* model = tflite::GetModel(g_person_detect_model_data);
  static tflite::MicroMutableOpResolver<5> resolver;
  resolver.AddAveragePool2D();
  resolver.AddConv2D();
  resolver.AddDepthwiseConv2D();
  resolver.AddReshape();
  resolver.AddSoftmax();
  static tflite::MicroInterpreter staticInterpreter(
      model, resolver, tensorArena, kArenaSize, &errorReporter);
  interpreter = &staticInterpreter;
  if (interpreter->AllocateTensors() != kTfLiteOk) return false;
  input = interpreter->input(0);
  return true;
}

void connectMqtt() {
  while (!mqtt.connected()) {
    String status = String(PREFIX) + "/status";
    if (mqtt.connect(clientId, status.c_str(), 1, true, "offline")) {
      mqtt.publish(status.c_str(), "online", true);
    } else {
      Serial.printf("MQTT failed, state=%d\n", mqtt.state());
      delay(3000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  if (!initCamera()) { Serial.println("Camera init failed"); ESP.restart(); }
  if (!initModel()) { Serial.println("Model init failed, increase arena"); ESP.restart(); }

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(300);
  snprintf(clientId, sizeof(clientId), "esp32cam-%06lx", (unsigned long)(ESP.getEfuseMac() & 0xFFFFFF));
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setKeepAlive(30);
  connectMqtt();
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  camera_fb_t* fb = esp_camera_fb_get();
  if (!fb) return;
  for (size_t i = 0; i < input->bytes && i < fb->len; i++) {
    input->data.int8[i] = (int8_t)(fb->buf[i] - 128);
  }
  esp_camera_fb_return(fb);

  unsigned long t0 = millis();
  if (interpreter->Invoke() != kTfLiteOk) return;
  unsigned long inferMs = millis() - t0;

  TfLiteTensor* out = interpreter->output(0);
  int personPct = (out->data.int8[1] + 128) * 100 / 255;

  hits = personPct >= PERSON_THRESHOLD ? hits + 1 : 0;
  unsigned long now = millis();

  if (hits == FRAMES_TO_RAISE && now - lastAlert > COOLDOWN_MS) {
    lastAlert = now;
    char msg[96];
    snprintf(msg, sizeof(msg), "{\"event\":\"person\",\"score\":%d,\"uptimeMs\":%lu}", personPct, now);
    mqtt.publish((String(PREFIX) + "/alert").c_str(), msg);
    Serial.println(msg);
  }
  if (now - lastScore > SCORE_EVERY_MS) {
    lastScore = now;
    char msg[96];
    snprintf(msg, sizeof(msg), "{\"person\":%d,\"inferMs\":%lu,\"rssi\":%d}", personPct, inferMs, WiFi.RSSI());
    mqtt.publish((String(PREFIX) + "/score").c_str(), msg);
  }
}

Serial Monitor'ü 115200 baud hızında açın ve bilgisayarınızdan abone olun:

mosquitto_sub -h broker.connectmq.com -p 1883 -i pd-watch-e51a -t "connectmq/demo/pd-e51a/#" -v

Kameranın önüne geçtiğinizde birkaç kare sonra bir uyarı görünmelidir; skor topic'i her beş saniyede bir güncellenir.

ESP32-CAM İnsan Tespitinde İnce Ayar

  • Eşik. Yüzde 60 ile başlayın. Karenin kenarındaki insanlar kaçırılıyorsa düşürün, gölgeler veya posterler uyarı tetikliyorsa yükseltin.
  • Uyarı için gereken kare sayısı. Art arda üç kare, tek karelik aksaklıkların çoğunu filtreler; bedeli ise biraz daha geç gelen bir uyarıdır.
  • Bekleme süresi. Gerçekte ne sıklıkla bildirim almak istiyorsanız ona göre ayarlayın. Bir kapı girişi için 30 saniye yeterli olabilir; kısıtlı bir alanda her girişin bildirilmesi gerekebilir.
  • Aydınlatma. Model çeşitli görüntülerle eğitilmiştir ancak çok düşük ışıkta zorlanır. Kızılötesi destekli bir kamera modülü ve IR aydınlatma gece işe yarar.
  • Görüş alanı. Model yalnızca 96 x 96 piksel görür, bu yüzden bir kişinin karenin makul bir bölümünü doldurması gerekir. Kamerayı ilgilenilen alan yakında olacak şekilde monte edin.

Güç ve Konumlandırma

Bir kamerayı ve sinir ağını sürekli çalıştırmak ESP32'yi meşgul, Wi-Fi'yi de aktif tutar; bu nedenle bu tasarım şebeke gücü olan konumlara uygundur. Pille çalışma için kartı bir pasif kızılötesi (PIR) sensörle eşleştirin: ESP32'yi uyutun, PIR tetiklendiğinde uyandırın, hareketin bir evcil hayvan ya da perde değil bir insan olduğunu doğrulamak için birkaç kare üzerinde insan tespiti çalıştırın, sonucu yayınlayın ve tekrar uykuya geçin. MQTT payload'u aynı kalır; dolayısıyla aboneler kameranın hangi modda çalıştığıyla ilgilenmez.

Konumlandırma en az model kadar önemlidir. Kamerayı insanların karede dik ve makul büyüklükte göründüğü bir yüksekliğe ve açıya monte edin, güçlü arka ışığa neden olan pencerelere doğrultmaktan kaçının ve muhafaza buna uygun sınıfta değilse yağmurdan uzak tutun.

Uyarıların Üzerine İnşa Etmek

Uyarılar bir topic'e ulaşmaya başladığında MQTT konuşan her şey tepki verebilir: Home Assistant bir ışığı açabilir, Node-RED telefona bildirim gönderebilir, daha büyük bir algılayıcı çalıştıran bir Raspberry Pi anlık görüntü isteyip insanları düzgün biçimde sayabilir. Ortada ConnectMQ olduğunda bunların her biri yalnızca bir abone daha olur ve kameraya yeniden yazılım yüklemeden onları ekleyip çıkarabilirsiniz.

Sorun Giderme

  1. "Brownout detector was triggered" hatası ve yeniden başlatmalar. Daha iyi bir 5 V kaynak ve kısa, kalın bir kablo kullanın; kamera ve Wi-Fi birlikte ani akım sıçramaları çeker.
  2. Camera init failed. Kart seçiminin AI Thinker ESP32-CAM olduğunu ve PSRAM'in etkin olduğunu kontrol edin; şerit kablonun yerine oturduğunu da doğrulayın.
  3. Model init failed. Tensör arenası çok küçük veya dahili RAM parçalanmış durumda; kArenaSize değerini 10 KB'lık adımlarla artırın ve modeli Wi-Fi'den önce başlatın.
  4. TensorFlow başlık dosyalarında derleme hataları. Kütüphane sürümleri MicroInterpreter yapıcısında farklılık gösterir; include yollarını ve yapıcıyı, kurulu kütüphane sürümünüzle gelen örnekle eşleştirin.
  5. MQTT state -2 veya sürekli yeniden bağlanma. Wi-Fi zayıf ya da client ID yinelenmiş. Kartı erişim noktasına yaklaştırın ve başka hiçbir cihazın aynı client ID'yi kullanmadığından emin olun.

Gerçek Kullanım İçin Güvenli Hale Getirmek

Gerçek bir kapı girişini izleyen kamera, cihazdan yalnızca bir skor çıksa bile kişisel veri üretir. Testin ötesindeki her şey için TLS'li özel bir broker'a geçin: WiFiClient yerine WiFiClientSecure kullanın, 8883 portuna bağlanın ve mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", ...) ile kimlik doğrulayın. Test için herkese açık MQTT broker geliştirme için idealdir; ConnectMQ gibi bir tam yönetilen MQTT hizmeti ise her kameraya kendi kimlik bilgilerini verir ve trafiği şifreli tutar.

Model bir insan sınıflandırıcısı olduğundan, doğal bir genişletme onu tetikleyici olarak kullanmaktır: tetiklendiğinde ayrı bir topic'e anlık görüntü yayınlayın veya başka bir yerdeki daha yetenekli bir modeli uyandırın. Modelleri mikrodenetleyicilere sığdırma hakkında daha fazlası için ESP32 üzerinde TinyML ve daha kapsamlı yapay zeka ve IoT rehberi yazılarını okuyun.

ConnectMQ ile Başlayın

app.connectmq.com adresinde ücretsiz Serverless planında kredi kartı gerektirmeden özel bir broker oluşturun, ardından sketch'i TLS'e ve oluşturulan kimlik bilgilerine geçirin. Uyarıların gelişini portalın canlı topic gezgininde izleyebilir ve person skoru için bir eşik uyarı kuralı ekleyebilirsiniz.

Sık Sorulan Sorular

ESP32-CAM üzerinde insan tespiti ne kadar hızlıdır?

Kütüphane sürümüne ve optimize edilmiş çekirdeklerin etkin olup olmadığına bağlı olarak en fazla saniyede birkaç çıkarım bekleyin. Bu, varlık algılama için fazlasıyla yeterlidir ancak hareket takibi için yeterli değildir.

ESP32-CAM insanları sayabilir veya sınırlayıcı kutu çizebilir mi?

Bu modelle hayır; model yalnızca karenin tamamını insan var veya yok olarak sınıflandırır. Sayım ve kutular için olayları algılayıcı çalıştıran bir Raspberry Pi'ye veya Jetson'a gönderin.

İnsan tespiti için PSRAM gerekli mi?

Bu sketch'te kamera kare tamponu PSRAM'e yerleştirilir ve çoğu ESP32-CAM kartında PSRAM bulunur. Tensör arenasının kendisi ise daha hızlı olan dahili RAM'de ayrılır.

Herkese açık broker'a görüntü göndermek güvenli mi?

Hayır. Herkese açık alan herkes tarafından okunabilir; bu yüzden orada yalnızca skorları ve uyarıları yayınlayın, görüntüleri TLS ve kimlik bilgileri olan özel bir broker'da tutun.

İlgili yazılar

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.