ESP32-CAM: фото и сохранение на MicroSD карту
Узнайте, как делать фотографии с помощью платы ESP32-CAM и сохранять их на карту microSD с помощью Arduino IDE. При нажатии кнопки RESET на ESP32-CAM плата просыпается, делает фото и сохраняет его на microSD карту.
Мы будем использовать плату ESP32-CAM с маркировкой AI-Thinker, но другие модули тоже должны работать при правильном назначении пинов в коде.
Плата ESP32-CAM стоит около $9 (или меньше) и объединяет чип ESP32-S, камеру OV2640, слот для microSD карты и несколько GPIO пинов.
Для знакомства с ESP32-CAM вы можете изучить следующие руководства:
ESP32-CAM: видеотрансляция и распознавание лиц с Arduino IDE
ESP32-CAM: веб-сервер видеотрансляции (работает с Home Assistant, Node-RED и т.д.)
Смотрите видеоурок
Чтобы узнать, как делать фотографии с помощью ESP32-CAM и сохранять их на microSD карту, вы можете посмотреть следующий видеоурок или продолжить чтение этой страницы для получения текстовых инструкций и всех необходимых ресурсов.
Необходимые компоненты
Для выполнения этого руководства вам понадобятся следующие компоненты:
ESP32-CAM с OV2640 – см. Лучшие платы ESP32-CAM
Источник питания 5V для ESP32-CAM или повербанк (опционально)
Обзор проекта
Вот краткий обзор того, как работает проект.
ESP32-CAM находится в режиме глубокого сна (deep sleep)
Нажмите кнопку RESET, чтобы разбудить плату
Камера делает фотографию
Фотография сохраняется на microSD карту с именем: pictureX.jpg, где X соответствует номеру снимка
Номер снимка сохраняется во флеш-памяти ESP32, чтобы он не стирался при RESET, и мы могли отслеживать количество сделанных фотографий.
Форматирование MicroSD карты
Первое, что мы рекомендуем сделать — отформатировать вашу microSD карту. Вы можете использовать стандартный инструмент форматирования Windows или любое другое ПО для форматирования microSD.
1. Вставьте microSD карту в компьютер. Перейдите в Мой компьютер и кликните правой кнопкой мыши по SD-карте. Выберите Форматировать, как показано на рисунке ниже.
2. Появится новое окно. Выберите FAT32, нажмите Начать, чтобы начать процесс форматирования, и следуйте инструкциям на экране.
Примечание: согласно спецификациям, ESP32-CAM должна поддерживать только SD-карты объёмом 4 ГБ. Однако мы протестировали с 16 ГБ SD-картой, и она работает нормально.
Установка дополнения ESP32
Мы будем программировать плату ESP32 с помощью Arduino IDE. Поэтому вам нужна установленная Arduino IDE, а также дополнение ESP32. Вы можете следовать следующему руководству для установки дополнения ESP32, если вы ещё этого не сделали:
Скетч для съёмки и сохранения фото
Скопируйте следующий код в вашу Arduino IDE.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-cam-take-photo-save-microsd-card
IMPORTANT!!!
- Select Board "AI Thinker ESP32-CAM"
- GPIO 0 must be connected to GND to upload a sketch
- After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory
// define the number of bytes you want to access
#define EEPROM_SIZE 1
// Pin definition for 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
int pictureNumber = 0;
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
//Serial.setDebugOutput(true);
//Serial.println();
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;
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
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");
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;
// Take Picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
// Path where new picture will be saved in SD Card
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); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
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() {
}
Код начинается с подключения необходимых библиотек для работы с камерой. Мы также подключаем библиотеки, необходимые для взаимодействия с microSD картой:
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory
И библиотеку EEPROM для сохранения постоянных данных во флеш-памяти.
#include <EEPROM.h>
Если вы хотите узнать больше о чтении и записи данных во флеш-память, вы можете изучить следующее руководство:
Определите количество байт, к которым вы хотите получить доступ во флеш-памяти. Здесь мы будем использовать только один байт, что позволит генерировать до 256 номеров фотографий.
#define EEPROM_SIZE 1
Затем определите пины для модуля камеры AI-THINKER.
// Pin definition for 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
Примечание: вам может потребоваться изменить определение пинов в зависимости от используемой платы. Неправильное назначение пинов приведёт к ошибке инициализации камеры.
Инициализируйте переменную int с именем pictureNumber, которая будет генерировать имя фотографии: picture1.jpg, picture2.jpg и так далее.
int pictureNumber = 0;
Весь наш код находится в setup(). Код выполняется только один раз, когда ESP32 просыпается (в данном случае при нажатии встроенной кнопки RESET).
Определите настройки камеры:
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;
Используйте следующие настройки для камеры с PSRAM (как та, которую мы используем в этом руководстве).
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
}
Если плата не имеет PSRAM, установите следующее:
else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
Инициализируйте камеру:
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
Инициализируйте microSD карту:
//Serial.println("Starting SD Card");
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;
}
Больше информации о работе с microSD картой можно найти в следующем проекте:
Следующие строки делают фотографию с камеры:
camera_fb_t * fb = NULL;
// Take Picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
После этого инициализируйте EEPROM с ранее определённым размером:
EEPROM.begin(EEPROM_SIZE);
Номер фотографии генерируется путём добавления 1 к текущему номеру, сохранённому во флеш-памяти.
pictureNumber = EEPROM.read(0) + 1;
Чтобы сохранить фото на microSD карту, создайте путь к файлу. Мы сохраняем фото в корневой каталог microSD карты, и имя файла будет (picture1.jpg, picture2.jpg, picture3.jpg и т.д…).
String path = "/picture" + String(pictureNumber) +".jpg";
Следующие строки сохраняют фотографию на microSD карту:
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); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
После сохранения фото мы записываем текущий номер снимка во флеш-память, чтобы отслеживать количество сделанных фотографий.
EEPROM.write(0, pictureNumber);
EEPROM.commit();
Когда ESP32-CAM делает фото, встроенный светодиод (вспышка) загорается. После съёмки светодиод остаётся включённым, поэтому мы отправляем инструкции для его выключения. Светодиод подключён к GPIO 4.
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);
Наконец, мы переводим ESP32 в режим глубокого сна (deep sleep).
esp_deep_sleep_start();
Поскольку мы не передаём никаких аргументов функции глубокого сна, плата ESP32 будет спать бесконечно до нажатия RESET.
Загрузка кода в ESP32-CAM
Чтобы загрузить код в плату ESP32-CAM, подключите её к компьютеру с помощью FTDI программатора. Следуйте следующей схеме подключения:
Многие FTDI программаторы имеют перемычку, позволяющую выбрать 3.3V или 5V. Убедитесь, что перемычка установлена в правильное положение для выбора 5V.
Важно: GPIO 0 должен быть подключён к GND, чтобы вы могли загрузить код.
ESP32-CAM |
FTDI Программатор |
|---|---|
GND |
GND |
5V |
VCC (5V) |
U0R |
TX |
U0T |
RX |
GPIO 0 |
GND |
Чтобы загрузить код, выполните следующие шаги:
Перейдите в Tools > Board и выберите AI-Thinker ESP32-CAM.
Перейдите в Tools > Port и выберите COM-порт, к которому подключён ESP32.
Затем нажмите кнопку загрузки, чтобы загрузить код.
Когда вы начнёте видеть точки в окне отладки, как показано ниже, нажмите встроенную кнопку RST на ESP32-CAM.
Через несколько секунд код должен быть успешно загружен на вашу плату.
Демонстрация
После загрузки кода удалите перемычку, соединяющую GPIO 0 с GND.
Откройте Serial Monitor на скорости 115200 бод. Нажмите кнопку сброса ESP32-CAM. Плата должна инициализироваться и сделать фотографию. При съёмке фото включается вспышка (GPIO 4).
Проверьте окно Serial Monitor в Arduino IDE, чтобы убедиться, что всё работает как ожидается. Как видите, фотография была успешно сохранена на microSD карту.
Примечание: если у вас возникли проблемы с ESP32-CAM, ознакомьтесь с нашим руководством по устранению неполадок: ESP32-CAM: руководство по устранению наиболее распространённых проблем
Убедившись, что всё работает как ожидается, вы можете отключить ESP32-CAM от FTDI программатора и запитать её от независимого источника питания.
Чтобы просмотреть сделанные фотографии, извлеките microSD карту из слота и вставьте её в компьютер. Вы должны увидеть все сохранённые фотографии.
Качество фотографий зависит от условий освещения. Слишком много света может испортить ваши фотографии, а тёмная обстановка приведёт к появлению множества чёрных пикселей.
Устранение неполадок
Если вы получаете какие-либо из следующих ошибок, прочитайте наше руководство по устранению наиболее распространённых проблем ESP32-CAM:
Failed to connect to ESP32: Timed out waiting for packet header
Camera init failed with error 0x20001 или аналогичная
Brownout detector или ошибка Guru meditation
Sketch too big error – выбрана неправильная схема разделов
Board at COMX is not available – COM-порт не выбран
Psram error: GPIO isr service is not installed
Слабый сигнал Wi-Fi
Нет IP-адреса в Serial Monitor Arduino IDE
Не удаётся открыть веб-сервер
Изображение отстаёт / показывает большую задержку
Заключение
Мы надеемся, что это руководство оказалось для вас полезным и вы сможете использовать его в своих проектах. Если у вас ещё нет платы ESP32-CAM, вы можете приобрести её здесь.
Как упоминалось ранее, у нас есть другие руководства по ESP32-CAM, которые могут вам понравиться: