【ESP32-CAM】タイムラプス用のカメラを自作してみた。

ESP32-CAMでタイムラプス タイムラプス

Twitterを見てたら、タイムラプスの映像があったので、やってみようかと・・・
動画の再生スピードを上げる手法もあるんだろうけど、長時間の撮影には向かないよねえかm

[PR]

機材を考えてみた

専用のカメラなら確実に映像が撮れるのだろうが、意外と高い。
耐久性もあって,4Kで撮れるのは捨てがたい。

 

次に、古いスマホの利用を検討してみた。
使用しているスマホを使うと、撮影中は使用できないため却下。古いスマホにアプリをインストールして使用する方法もあり。

20210223090947.png

参考:タイムラプス用アプリ

しかし、スマホも消費電力が大きいので長時間の撮影には少し無理があるような気がする。

いずれにしても、消費電力は大きく1日程度の撮影なら可能だろうが、それ以上は難しいだろう。低コストでコンパクトかつ省電力のものというとなかなか見つからない。

[PR]

ESP32-CAMを使ってみた

ESP32-CAMはカメラ機能のほかにWIFIモジュールやSDカードスロットも装備されており、電源をつなげば単体で稼働可能。しかも超軽量で超コンパクト。

楽天だと少し高いが、ほかならもう少し安く買うことができる。なぜか値段が大きく上がった?ちなみに所有しているモジュールはこんなに高くなかった。

ESP32-CAMのスペック

    • デュアルコア Tensilica LX6 マイクロプロセッサ
    • 最大クロック 240MHz
    • 520KB RAM
    • 4MB Flash メモリ
    • 802.11 b/g/n Wi-Fi
    • デュアルモード Bluetooth (classic and BLE)
    • ハードウェアアクセラレーションによる暗号化 (AES, SHA2, ECC, RSA-4096)
  • CP2104 USB-UART変換ドライバ
  • OV2640 カメラセンサー
    • 出力フォーマット(8-bit):
      • YUV(422/420)/YCbCr422
      • RGB565/555
      • 8-bit 圧縮データ
      • 8/10-bit RAW RGB データ
    • 最大画像転送レート
      • UXGA/SXGA: 15fps
      • SVGA: 30fps
      • CIF: 60fps
    • スキャンモード: Progressive
  • カメラ スペック
    • 視野 : 65 度
  • 最大解像度: 200万画素(メモリの都合上、本ユニットは最大800 * 600 pixels JPEG)
  • サイズ: 20.5 × 46.5 × 11.5mm
[PR]

タイムラプスのプログラムを書いてみた

以前に作ったWEBカメラのコードを使う。前回は取得したデータをWifiで転送する方法だったが、それをSDカードに書き込むように変更する。

とりあえず書きなぐったコードはこちら

#include "SD.h"
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "FS.h"
#include "SD.h"

//SD Card Pins
#define sd_sck 14
#define sd_mosi 15
#define sd_ss 13
#define sd_miso 2

// read and write from flash memory
#include <EEPROM.h>

// define the number of bytes you want to access
#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;
int mySN = 0;
char myFname1[4];
char myFname2[4];

void setup()
{
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

Serial.begin(115200);
delay(10);

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;

config.frame_size = FRAMESIZE_VGA; // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
config.jpeg_quality = 10;
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);
delay(1000);
ESP.restart();
}

// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
EEPROM.write(0, pictureNumber);
EEPROM.commit();

// LED Pin Mode
pinMode(33, OUTPUT);

}

void loop() {
digitalWrite(33,LOW);
delay (1000);
saveCapturedImage();

digitalWrite(33,HIGH);

delay(180*1000); //待機間隔 秒
}

void saveCapturedImage() {

camera_fb_t * fb = NULL;

// Take Picture with Camera
Serial.println(" ");
Serial.println("Take Picture ");
fb = esp_camera_fb_get(); 

// Path where new picture will be saved in SD Card
Serial.println("Save SD Card");

// Get File Name
if (mySN == 999){

EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
EEPROM.write(0, pictureNumber);
EEPROM.commit();

mySN = 1;
}else{
mySN = mySN + 1;
}

sprintf(myFname1, "%03d",pictureNumber);
sprintf(myFname2, "%03d",mySN);

String path = "/p" + String(myFname1)+"_"+ String(myFname2) +".jpg";

Serial.printf("Picture file name: %s\n", path.c_str());

SPI.begin(sd_sck, sd_miso, sd_mosi, sd_ss);
SD.begin(sd_ss);

File file = SD.open(path.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);

file.close();

esp_camera_fb_return(fb); 
Serial.println("complete");
}

SDカードの書き込みでハマる

SDカードのライブラリが2種類あってかなりハマったw
sd.hとsd_MMC.h どうもSD_MMCの場合、GPIO4がカメラのフラッシュと重なっているようで、アクセスするたびにLEDが点灯する。
対策が面倒だったので、素直にsd.hを使ってみた。おおまかな違いは、sd.hだと書き込み速度が遅いこととファイル名が8文字+拡張子3文字に制限されるようです。

ファイル名について

普通に変数を書いたら電源をオンオフするたびにファイル名が1から始まってしまうので、ひと工夫してみた。
EPROM()関数を使って、電源が落ちてもESP32-CAMに実装されているロムにファイル情報を書き込んでみた。256バイトまで使えるみたい。
これにより0〜255までの256通りの数字を保持できる。255以上の数字を記録したいのであれば、アドレスを分けて10進数で計算させてやればできると思う。
今回はそこまで必要がないのでパス。

とりあえずタイムラプス用カメラが完成

loop()に放り込んで、deray()で撮影時間を調整しているが、これだと待機電力が無駄になっているので、何か別な方法を考えてみたい。

超軽量、コンパクトサイズのタイムラプスカメラが完成した。
20210223120132.jpg

まあまあの出来だった。
ただし、delay()で待機時間を制御しているため、待機中の電力消費が気になるところかな。

クリック(タップ)するとスタートします。
20210223103913.gif

100円ショップでミニ三脚を買ってこよう。

追記

スリープモードで更に省電力できました。

【自作タイムラプス】ESP32-CAMをDeepSleepモードで省電力化してみた【Time Lapse】

設定方法やwebストレージに保存する方法はこちら

コメント

タイトルとURLをコピーしました