โปรเจค ESP32-CAM กล้องดักถ่ายภาพอัตโนมัติ ด้วย PIR Motion โดยโปรเจคนี้ สามารถประยุกต์เป็นกล้องดักถ่ายภาพเมื่อมีผู้บุกรุก หรือเป็นกล้องดักถ่ายภาพสัตว์ มีชื่อเรียกหลายชื่อได้แก่ Trail Cam, Scout Cam, Camera Trap โดยผู้ใช้งานโดยซ่อนไว้ใกล้บริเวณทางที่สัตว์เดินผ่าน หรือแหล่งน้ำและดินโป่งที่สัตว์ใช้ประจำเมื่อมีสัตว์เดินผ่านมาบริเวณที่ตัวเซ็นเซอร์จับการเคลื่อนไหวได้กล้องจะถ่ายภาพเองโดยอัตโนมัติ โดยจะเก็บไฟล์รูปภาพไว้ที่ SD Card
หลักการทำงานของโปรเจค
โดยเมื่อเริ่มทำงานเราจะให้ ESP32 อยู่โหมดการใช้งานแบบ Deep Sleep เพื่อเป็นการประหยัดพลังงาน แล้ว ปลุกให้ตื่นด้วยเซ็นเซอร์ PIR Motion เมื่อตรวจจับความเคลื่อนไหวได้ แล้วจึงสั่งให้กล้องจะถ่ายภาพ โดยเก็บไฟล์รูปภาพไว้ที่ SD Card จากนั้น ESP32 จะกลับเข้าสู่โหมดการใช้งานแบบ Deep Sleep เพื่อรอ การปลุกให้ตื่น ในครั้งต่อๆไป
### อุปกรณ์ที่ใช้ ###1.
ESP32-CAM ESP32 Development Board with Camera Module2.
CP2102 USB 2.0 to UART TTL 5PIN Connector Module3.
Jumper (M2M) 10cm Male to Male4.
Micro SD Card Class 10 16GB + Card Adapter5.
Keyestudio PIR Motion Sensor Module6.
2N3904 NPN General Purpose Transistor7.
รีซิสเตอร์ 10K Ohm8.
รีซิสเตอร์ 1K Ohm9.
Jumper (F2M) 20cm Female to Male
การทำงานมีขั้นตอนดังนี้1. ทดสอบการใช้งาน ESP32-CAMจากบทความ การใช้งาน ESP32-CAM กล้อง OV2640 เป็น Video Stream ภาพเคลื่อนไหว
http://esp32robot.blogspot.com/2019/07/esp32-cam-ov2640-video-stream.html
2. ฟอร์แมต Micro SD Card
Micro SD Card , Class 10 ความจุ 16GB + Card Adapter
ให้เสียบ Micro SD Card เข้าไปใน Card Adapter
Card Adapter ที่มี Micro SD Card อยู่ด้านใน
แล้วจึงเสียบ Card Adapter ที่บรรจุ Micro SD Card ใส่ในช่องซ็อกเก็ตของคอมพิวเตอร์ PC (ดันจนกระทั่งมีเสียงคลิก)
ไปที่ My Computer แล้วคลิกขวาที่ไดร์ของ Micro SD Card เลือกรูปแบบตามที่แสดงในภาพด้านล่าง
3. ทดสอบบันทึกรูปภาพลง SD Card
เสียบ Micro SD Card เข้าไปใน Slot Card
เปิดโปรแกรม Arduino (IDE) และ ก็อปปี้ โค้ดด้านล่างนี้ ไปวางไว้ในส่วนเขียนโปรแกรม
#include "esp_camera.h"
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "fd_forward.h"
#include "fr_forward.h"
#include "FS.h"
#include "SD_MMC.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "dl_lib.h"
#include "driver/rtc_io.h"
#include <EEPROM.h>
#define EEPROM_SIZE 1
#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
int pictureNumber = 0;
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
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_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
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 with error 0x%x", err);
return;
}
if(!SD_MMC.begin()){
Serial.println("SD Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD Card attached");
return;
}
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
String path = "/picture" + String(pictureNumber) +".jpg";
fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\n", path.c_str());
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
}
else {
file.write(fb->buf, fb->len);
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
delay(2000);
Serial.println("Going to sleep now");
delay(2000);
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
}
*** เมื่อต้องการ อัพโหลดโค้ดทุกครั้งให้เชื่อมต่อสาย ระหว่าง IO0 <-> GND ***
เชื่อมต่อ CP2102 USB เข้ากับคอมพิวเตอร์
ไปที่ Tools -> Board เลือก ESP32 Wrover Module
ไปที่ Tools -> Partition Scheme แล้วเลือก Huge APP(3MB No OTA)
ไปที่ Tools -> Port แล้วเลือกพอร์ตที่ปรากฏ (กรณีใช้เครื่องคอมพิวเตอร์ที่มี COM Port ให้เลือกตัวอื่นที่ไม่ใช่ COM1)
ในตัวอย่างเลือกเป็น "COM12"
กดปุ่ม
เพื่ออัพโหลด
หากสามารถอัพโหลดโปรแกรมลงบอร์ดได้สำเร็จ จะแสดงคำว่า Done uploading. ที่แถบด้านล่าง
### ถ้ามีปัญหาในการอัพโหลดไม่ได้ ให้กดปุ่ม RST ค้างไว้ในขณะอัพโหลด ###
ถอด Jumper ที่เชื่อมต่อระหว่าง IO0 <-> GND ออก
กดปุ่ม RST 1 ครั้ง ต่อ 1 รูปภาพ
ESP32-CAM จะถ่ายภาพ โดยจะเก็บไฟล์รูปภาพไว้ที่ SD Card
เมื่อถอด SD Card ไปดูที่คอมพิวเตอร์ จะพบไฟล์รูปภาพ ที่ ESP32-CAM ถ่ายภาพเอาไว้
credit : https://randomnerdtutorials.com/esp32-cam-take-photo-save-microsd-card/
4. อัพโหลดโค้ดของโปรเจค
เปิดโปรแกรม Arduino (IDE) อัพโหลดโค้ดด้านล่างนี้ ไปยัง ESP32-CAM
#include "esp_camera.h"
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "fd_forward.h"
#include "fr_forward.h"
#include "FS.h"
#include "SD_MMC.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "dl_lib.h"
#include "driver/rtc_io.h"
#include <EEPROM.h>
#define EEPROM_SIZE 1
RTC_DATA_ATTR int bootCount = 0;
#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
int pictureNumber = 0;
#define uS_TO_S_FACTOR 1000000
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
Serial.setDebugOutput(true);
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;
pinMode(4, INPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_dis(GPIO_NUM_4);
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
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 with error 0x%x", err);
return;
}
Serial.println("Starting SD Card");
delay(500);
if(!SD_MMC.begin()){
Serial.println("SD Card Mount Failed");
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD Card attached");
return;
}
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
String path = "/picture" + String(pictureNumber) +".jpg";
fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\n", path.c_str());
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
}
else {
file.write(fb->buf, fb->len);
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
delay(1000);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
Serial.println("Going to sleep now");
delay(1000);
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
}
5. เชื่อมต่ออุปกรณ์เพิ่มเติม
6. ทดสอบการทำงานของโปรเจค
credit : https://randomnerdtutorials.com/esp32-cam-pir-motion-detector-photo-capture/