Hepimiz öğrenci de olsak, işi gücü olan birisi de olsak hepimizin temel ihtiyacı yemek yemektir. Kimimiz kendi yemeğimizi kendimizin hazırlaması gerekirken kimimizin ise ailesi her zaman hazır yemekler ile bizi mutlu ederler ama yeri gelir bizim de hazırlamamız gerekir. Kendi hayatımda yaşadığım en büyük problemlerden bir tanesi de hazırladığım yemeğin başında beklemek zorunda oluşum. Acaba yandı mı, nasıl görünüyor, başına gitmem gerekir mi ? Sonrasında bir bakmışım yemeğim yanmış. Bugün bu soruna mühendisçe bir çözüm üretmek için ESP32-CAM modülüne nasıl yazılım yükleyebileceğimizi ve nasıl canlı yayın alabileceğimizi inceleyeceğiz.
İhtiyaç Listesi
ESP32-CAM Wifi Bluetooth Geliştirme Kartı ve OV2640 Kamera Modülü: https://www.robo90.com/esp32-cam-wifi-bluetooth-gelistirme-karti-ve-ov2640-kamera-modulu
40lı Ayrılabilen Dişi-Dişi Jumper Kablo – 20cm – Arduino Uyumlu: https://www.robo90.com/40li-ayrilabilen-disi-disi-jumper-kablo-20cm-arduino-uyum
FT232RL FTDI USB-TTL Dönüştürücü-Programlayıcı: https://www.robo90.com/ft232rl-ftdi-usb-ttl-donusturucu-programlayici
Donanım Kısmı
Yapmamız gereken ilk şey USB-TTL dönüştürücü ile ESP32-CAM modülünün bağlantılarını yapmaktır. Yukarıdan aşağıya doğru sırasıyla bağlamamız gereken pinler; ( Fotoğraf 1.0 )
USB-TTL→ ESP-CAM
- GND → GND
- Boş
- VCC → 5V
- TX → UOR
- RX → UOT
Bir diğer dikkat etmemiz gereken konu ise USB-TTL dönüştürücünün üzerindeki 5V pinini fotoğraftaki gibi bağlamamız gerekir. 3.3V pinine bağlı olup ttl dönüştürücüyü ESP32-CAM modülünün 5V pinine bağlayamazsınız.
Gerekli bağlantıları yaptıktan sonra USB-TTL dönüştürücümüzü bilgisayarımıza bağlamadan önce ESP32’ye ait gerekli kütüphaneleri indirmemiz gerekir. ESP32’ye Program Nasıl Yazılır? adlı blog yazımı okuyabilirsiniz. ESP32-CAM modülü ESP32’ye kamera eklenmiş hali gibi düşünebileceğimizden aynı kütüphaneyle çalışmaktadırlar.
Tüm gerekli kütüphaneleri indirdikten sonra ESP32-CAM modülümüzü bilgisayara doğru port ve doğru kartı seçmemiz gerekir. Doğru portu bazen Arduino IDE ile göremeye biliriz. Bu tarz durumlarda Aygıt yöneticisini açıp Ports kısmından doğru bağlantıyı görebiliriz. Eğer sizde her şeye rağmen cihazınızı göremiyorsanız kullandığınız USB-TTL dönüştürücünün Driver’larını indirmeniz gerekebilir. ( Fotoğraf 1.1 )
Eğer ESP32-CAM modülünün Driver’larının nasıl kurulacağını bilmiyorsanız aşağıdaki bloğumu inceleyebilirsiniz.
Sonrasında IDE programından cihazımızı seçmemiz gerekir. ( Fotoğraf 1.2 )
Tüm bu işlemleri doğru yaptıktan sonra Kartımızın bağlandığını görebiliriz; ( Fotoğraf 1.3 )
Gerekli Kodlar
Kodumuzun ilk kısmında ihtiyacımız olan kütüphaneler bulunmakta. Sadece ESP32’nin ilk başta kütüphanesini yüklemeniz gerekli. “Fazla kütüphane var bunları da indirmem gerekmez mi?” diye düşünebilirsiniz ancak zaten yüklü olacaktır.
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h" //disable brownout problems
#include "esp_http_server.h"
Daha sonrasında ise ESP32-CAM modülünü bağlayacağımız internet ismimizi ve şifremizi sırasıyla ssid ve password kısmına yazmamız gerek.
UYARI
ESP32-CAM sadece 2.4GHz internete bağlanabilir. 5GHz internetinize bağlanamaz. 5Ghz internetinize bağlamayı denerseniz ESP32-CAM modülü internete bağlanamayacaktır. Telefonunuzun mobil erişim noktasını paylaşıp ESP32-CAM modülünü bağlamayı deneyebilirsiniz ancak telefonunuzun da 2.4GHz internet Wi-Fi paylaşımı yaptığından emin olmanız gerek.
const char* ssid = "****************"; //İnternet İsminiz (Örnek Mahmut_2.4GHz)
const char* password = "****************"; //İnternet Şifreniz
Sonrasında ise ESP-CAM modülünün kamerası için gerekli pinleri tanımlamamız gerekir. Kullandığımız kameraya göre pinler değişiklik gösterebilir. Ben ilk denediğimde kameram çalışmamıştı. Sonra ESP32 kütüphanesinin içerisinde gelen CameraWebServer örnek kodundaki genel kamera pinlerini de denedim ancak çalışmamıştı. Eğer siz de aynı sorunla karşılaşırsanız aşağıdaki koddaki CAMERA_MODEL_WROVER_KIT’e ait kamera pin bağlantılarını kodunuza yapıştırabilir, kodunuzdaki hazır kamera pinleriyle yer değiştirebilirsiniz.
#define PART_BOUNDARY "123456789000000000000987654321"
#define BLYNK_TEMPLATE_ID "TMPL6Dn_JnPjn"
#define BLYNK_TEMPLATE_NAME "esp32cam"
#define BLYNK_AUTH_TOKEN "AXhKUN1qbCIsVzwIDjuSPf-yAHr4BDtB"
#define CAMERA_MODEL_AI_THINKER
//Deneyebilceğiniz kamera pini
#if defined(CAMERA_MODEL_WROVER_KIT)
#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
//
#elif defined(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
#else
#error "Camera model not selected"
#endif
Aşağıda ise kodumuzun tamamı mevcut. Kodun geri kalanında kamera, WebServer, Wi-Fi kurulum kodları ( Setup kısmında ) ve kameradan gelen canlı yayını WebServer’a veri ileten kodlar mevcut. Kodumuzun tamamını kopyalayıp gerekli kütüphaneleri indirdiğinizden emin olduktan sonra kodu yüklerken nelere dikkat etmemiz gerektiğini inceleyelim.
Kodun Tamamı
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h" //disable brownout problems
#include "esp_http_server.h"
const char* ssid = "****************"; //İnternet İsminiz (Örnek Mahmut_2.4GHz)
const char* password = "****************"; //İnternet Şifreniz
#define PART_BOUNDARY "123456789000000000000987654321"
#define BLYNK_TEMPLATE_ID "TMPL6Dn_JnPjn"
#define BLYNK_TEMPLATE_NAME "esp32cam"
#define BLYNK_AUTH_TOKEN "AXhKUN1qbCIsVzwIDjuSPf-yAHr4BDtB"
#define CAMERA_MODEL_AI_THINKER
#if defined(CAMERA_MODEL_WROVER_KIT)
#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
#elif defined(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
#else
#error "Camera model not selected"
#endif
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
httpd_handle_t stream_httpd = NULL;
static esp_err_t stream_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
while(true){
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
if(fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
//Serial.printf("MJPG: %uB\n",(uint32_t)(_jpg_buf_len));
}
return res;
}
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
//Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &index_uri);
}
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
Serial.setDebugOutput(false);
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;
if(psramFound()){
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 20;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_VGA;
config.jpeg_quality = 30;
config.fb_count = 1;
}
// Camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Wi-Fi connection
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("Camera Stream Ready! Go to: http://");
Serial.print(WiFi.localIP());
// Start streaming web server
startCameraServer();
}
void loop() {
delay(1);
}
UYARI
ESP32-CAM modülüne yazılım atarken IO0 pini GND’ye bağlanmalıdır. Bu sayede modül nasıl ESP32’ye yazılım yüklerken butona basıyorsak bu modülde de IO0 pini grounda bağlanmalıdır. Siz jumperlarla da bağlantıyı yapabilirsiniz.
UYARI
Eğer ESP32-CAM modülünüze program attığınız sırada IO0 ve GND pinlerini jumper ile birbirine bağlıyorsanız şu hatayı alma ihtimaliniz vardır:
A fatal error occurred: Invalid head of packet (0x65): Possible serial noise or corruption.
Bu hatanın anlamı jumper kablonuz çok uzun olduğundan çevre gürültülerini kapabiliyor. Bu hatanın kısa çözümü benim gibi kısa bağlantı şekilleri kullanabilirsiniz. Bu hatanın sebebi bazı ESP32 kartlarında bu hattın gürültü kapmaması için kapasitör konulur. Ancak bazı kartlarda konulmamış bir şekilde geliyor.
Sonrasında kodumuzu yüklemeye başlayabiliriz. Bir diğer dikkat etmemiz gereken kısım ise yükle butonuna tıkladığımızda önce kodumuz derlenecektir. Derlenme işleminin hemen sonrasında “ Connectting. . . ” yazısını göreceksiniz. Bu yazıyı gördüğünüz anda ESP32-CAM modülünün altındaki reset butonuna bir kere basıp çekmeniz gerekmektedir.,
Sonrasında ise kodumuz yüklenmeye başlayacaktır. Kodumuzun yüklenmesi tamamlandıktan sonra ise karşımıza şöyle bir ekranın çıkması gerekir.
Ve kodumuzu başarıyla yüklemeye başardık. Serial monitörü açmadan önce IO0 ve GND pinlerini birbirine bağlamamızı sağlayan, sadece kod atarken kullandığımız pimi veya jumper kablosunu çıkartmayı unutmamamız gerekir.
Daha sonra ESP32-CAM modülü USB ile bilgisayarımıza bağlıyken Serial Monitor’ü açtığımız zaman karşımıza şöyle bir ekran çıkması gerekir;
UYARI
Burada bilmemiz gereken diğer bir şey ise bu yayına sadece ama sadece ESP32-CAM ile aynı Wi-Fi ağına bağlıysanız ulaşabileceğinizdir. Eğer bilgisayarınız örnek vermek gerekirse Mahmut_5GHz ağına bağlıysa ve ESP32-CAM modülünüz sadece 2.4GHz ağlara bağlanabildiği için Mahmut_2.4GHz ağına bağlıysa aynı yayına katılamazsınız. Bilgisayarınızın da Mahmut_2.4GHz ağına bağlı olması gerekir.
Göründüğü gibi ESP32-CAM modülümüzle doğru bağlantı kurmayı başardık. Şimdi bize verilen http://192.168.1.53 linkini arama motorumuza yazarak kameramıza ulaşabiliriz.
Ve evet! Başardık. İstersek kamera modülünü gerekli güç kaynağıyla beraber yemeğimizi görebileceği bir yere koyarsak canlı yayında yemeklerimizin pişmesini yatağımızda yatarken izleyenbiliriz. Gördüğünüz gibi kamera hareketlerini takip edebiliyoruz. Tabii az önce de bahsettiğimiz gibi bu yayını sadece LAN’dan yani aynı Wi-Fi ağına bağlıysak görebilmekteyiz. Yani yemeklerinizi takip etmek istiyorsanız Wi-Fi’nizin kapsama alanı içerisinde olduğunuzdan emin olun. Peki ya yatağımızda uzanırken Wi-Fi miz çekmiyorsa o zaman ne yapacağız ? Tabi ki buna da mühendisçe bir çözüm üretip bir sonraki ESP32 ile LAN’dan WAN’a blog yazımı okuyabilirsiniz. Bu sayede ESP’nize internetin olduğu herhangi bir yerden istediğiniz an aynı yerel ağa bağlı olmak zorunda kalmadan ulaşabilirsiniz.