RisalDash RisalDash

Проект · ESP32-CAM · Time-lapse

Time-lapse камера из платы за $7

Стройка, растущее растение, небо в облаках — time-lapse сжимает часы в секунды, и ESP32-CAM делает всю работу: снимает JPEG по расписанию, пишет на MicroSD и отдаёт живой дашборд, где со смартфона видно, как растёт счётчик кадров и заполняется карта.

ПроектESP32-CAMTime-lapseMicroSD
Проект time-lapse камеры на ESP32-CAM: JPEG на MicroSD по расписанию с живым дашбордом

Снимок → SD, весь цикл

OV2640 сжимает JPEG аппаратно, так что кадр — это grab → write → return. Нумерованные имена (/0001.jpg…) делают шаг с ffmpeg тривиальным. Два правила стабильности: всегда возвращайте буфер esp_camera_fb_return() и монтируйте карту как SD_MMC.begin("/sdcard", true) — 1-битный режим освобождает пин LED-вспышки:

void capture(const char* why) {
  camera_fb_t* fb = esp_camera_fb_get();           // grab a JPEG frame
  if (!fb) { if (evlog) evlog->print("Capture FAILED"); return; }
  char name[16];
  snprintf(name, sizeof(name), "/%04u.jpg", (unsigned)++shotNo);
  File f = SD_MMC.open(name, FILE_WRITE);
  if (f) { f.write(fb->buf, fb->len); f.close(); shots = shotNo; }
  esp_camera_fb_return(fb);                        // ALWAYS return the frame buffer
  if (evlog) evlog->print(String(why) + " -> " + name);
}

// loop(): a shot every CAPTURE_EVERY_S seconds
if (millis() - lastShot > CAPTURE_EVERY_S * 1000UL) { lastShot = millis(); capture("Timer"); }

Дашборд — видно, что работает

Слепая камера в корпусе нервирует. Пять виджетов решают: счётчик фото, шкала SD, статус карты, ручная кнопка «Снять» и журнал кадров:

dash.layout("Trap", RICON_MOTION);
dash.stat("Photos", &shots, "");
dash.gauge("SD used", &sdUsedPct, 0, 100, "%").variant("bar");
dash.led("SD ready", &sdOk);
dash.button("Shoot", "Capture now", []() { capture("Manual"); });
evlog = &dash.log("Captures", 6);
dash.beginAP("RisalDash-CamTrap", "12345678");

sdOk = SD_MMC.begin("/sdcard", true);   // 1-bit mode frees the flash-LED pin

Готовый скетч — examples/06_Projects/CamTrap с MODE_TIMELAPSE 1; та же сборка одним define превращается в PIR-фотоловушку.

Выбор параметров

ПараметрВыборПочему
РазрешениеSVGA 800×600достаточно резко, ~40–80 КБ/кадр — см. гайд по настройкам
JPEG quality10золотая середина размер/детали
Интервал30 с (облака) · 5 мин (растения) · 15 мин (стройка)под скорость сюжета
ВремяNTP при Wi-FiDS3231 RTC — только для полного офлайна

Карта на 32 ГБ в SVGA вмещает порядка полумиллиона кадров — батарея сядет сильно раньше хранилища. Для многонедельных съёмок питайте от розетки или свяжите крупную ячейку LiFePO4 с deep sleep между кадрами.

Кадры → видео

ffmpeg -framerate 30 -i %04d.jpg -c:v libx264 -pix_fmt yuv420p timelapse.mp4

30 fps значит: каждая секунда видео съедает 900 кадров при интервале 30 с — 7.5 часов реального времени. Вокруг этого соотношения и планируйте.

Та же плата, тот же скетч — один define делает из неё фотоловушку по движению.