タイムラプスやるなら外で(その1)

前回、”タイムラプスをやってみる”の続きです。部屋の中から外の景色を撮るのも良いのですが、やっぱり外に持ち出したい所です。外に持ち出すにあたり、

  1. 撮影した映像を確認出来る様にする。
  2. スマホ等で撮影条件を設定出来るようにする。
  3. バッテリー駆動にする。

は最低限必要です。今回は、撮影した映像を確認出来るようにする事を目標にします。

最終的にはスマホで確認出来るようにしますが、今と取り敢えずPCのブラウザで確認する事にします。スケッチは非常に簡単です。

  • スタンダードモードでESP32CAMにHTTPサーバーを立ち上げる
  • HPの画面にはボタンが有り、ボタンを押すとHPの画面に撮影した画像が表示される。

#include "esp_camera.h"
#include "Arduino.h"
#include "SD.h"                          

// 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

#define sd_sck  14
#define sd_mosi 15
#define sd_ss   13
#define sd_miso  2

#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>

WebServer server(80);
const char *SSID = "Your SSID";
const char *PASSWORD = "Your PassWord";

// Take Picture with Camera
camera_fb_t * fb = NULL;

String index_Dt =
                  "<!DOCTYPE html>\n<html>\n<head>\n"
                  "<title>ESP32 Timelapse</title>\n"
                  "<style type='text/css'>\n"
                  "button.bt1 {background:#90ee90;font-size:50px;padding:10px;margin:20px;border-radius:30px;box-shadow:4px 4px #555;}\n"
                  "</style>\n</head>\n"
                  "<body>\n<center>\n"
                  "<div style='width:700px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31'>\n"
                  "<p style='font-size:70px'><b><i><u>Timelapse</u></i></b></p>\n"
                  "<img src='/data.jpg'>\n"
                  "<form method='get'>\n<button type='submit' name='1' class='bt1'>Take</button>\n</form><br><br>\n"
                  "</div>\n</center>\n</body>\n</html>";
                  
void setup() {
 
  Serial.begin(115200);
  delay(1000);

  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; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10;
  config.fb_count = 2;

  // Init Camera
  esp_camera_init(&config);

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

  Serial.println("Connecting to WiFi");
  WiFi.disconnect();
  WiFi.softAPdisconnect(true);
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, PASSWORD);
  delay(1000);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  Serial.println("Connected");
  Serial.println(SSID);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp32cam")) {
    Serial.println("MDNS responder started");
  }
  
  server.on("/", handleRoot);
  server.onNotFound(handleWebRequests); 

  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  
  server.handleClient();
  
}

void handleRoot() {
  String cmd;
  File dataFile;

    cmd=server.argName(0);
    switch(cmd.toInt())
    {
      case 1:   // Start Log
                fb = esp_camera_fb_get();
                dataFile = SD.open("/data.jpg", FILE_WRITE);
                dataFile.write(fb->buf, fb->len); // payload (image), payload length
                dataFile.close();
                esp_camera_fb_return(fb); 
                Serial.printf("Take a photo.\n");
                
    }
    server.send(200, "text/html", index_Dt);
}

void handleWebRequests()
{
  String dataType = "text/plain";
  String path;
  File dataFile;
   
    path = server.uri();
    if(path.endsWith(".txt")) dataType = "text/plain";
    else if(path.endsWith(".css")) dataType = "text/css";
    else if(path.endsWith(".js")) dataType = "application/javascript";
    else if(path.endsWith(".png")) dataType = "image/png";
    else if(path.endsWith(".gif")) dataType = "image/gif";
    else if(path.endsWith(".jpg")) dataType = "image/jpeg";
    delay(5);
    
    dataFile = SD.open(path.c_str(), "r");
    server.streamFile(dataFile, dataType);
    dataFile.close();
    delay(5);
}
  • 29から35行:ここでサーバーに必要なヘッダーの読み込み。サーバーの宣言等を行っています。
  • 40から51行:HPのHTML
    • 49行:
      • この部分でクライアントに画像を送っています。
  • 89から115行:WiFiに繋いてサーバーを起動
    • 107行:ここでDNSを設定しています。サーバーにアクセスする時は、”esp32cam.local”でアクセス出来ます。
  • 124から141行:サーバーの内部
    • 131から137行:HPでボタンを押すとここに来ます。
    • 132行:fb = esp_camera_fb_get();
      • 写真を撮る関数。
    • 133から135行:撮った写真をSDカードに保存
    • 140行:HTMLをクライアントに送信
  • 143から162行:この部分でクライアントに写真の送信を行っています。

コンパイルして実行して下さい。ブラウザに、”esp32cam.local”と入力するとHPが表示されます。最初は画像の無いHPですが、”Take”ボタンを押すと撮影した画像が表示されます。

このHPのコードは、


<!DOCTYPE html>
<html>
<head>
<title>ESP32 Timelapse</title>
<style type='text/css'>
button.bt1 {background:#90ee90;font-size:50px;padding:10px;margin:20px;border-radius:30px;box-shadow:4px 4px #555;}
</style>
</head>
<body>
<center>
<div style='width:700px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31'>
<p style='font-size:70px'><b><i><u>Timelapse</u></i></b></p>
<img src='/data.jpg'>
<form method='get'>
<button type='submit' name='1' class='bt1'>Take</button>
</form><br><br>
</div>
</center>
</body>
</html>

さい先の良い出だしです。次回は外に持ち出す為のハードの改良です。