簡単なStreamingと写真撮影。撮影した画像をSDカードに保存するプログラムを書いてみました。
回路
今回のESP32にはSDカードが無いのでSDカードを追加。回路は前回と同じ。
プログラムを作製
サンプルスケッチを元に書いたStreamingと写真撮影、そしてそのデータをSDカードに保管するプログラムです。
sample_02.in0
#include "esp_camera.h"
#include "Arduino.h"
#include "SD.h"
#include "FS.h"
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
// Pin definition for CAMERA_MODEL_WROVER_KIT
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#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 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// Pin definition for SD Card
#define sd_sck 13
#define sd_mosi 15
#define sd_ss 12
#define sd_miso 14
WebServer server(80);
const char *SSID = "xxxxxxxxxx";
const char *PASSWORD = "yyyyyyyyyy";
// Take Picture with Camera
camera_fb_t * fb = NULL;
int c_state = 1;
String index_00 =
"<!DOCTYPE html>\n<html>\n<head>\n"
"<title>ESP32CAM</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>ESP32CAM</u></i></b></p>\n";
void setup()
{
Serial.begin(115200);
delay(1000);
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");
}
init_cam();
SPI.begin(sd_sck, sd_miso, sd_mosi, sd_ss);
SD.begin(sd_ss);
server.begin();
Serial.println("HTTP server started");
server.on("/", handleRoot);
server.onNotFound(handleWebRequests);
}
void loop() {
server.handleClient();
}
void init_cam()
{
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);
}
void handleRoot()
{
String index_dt,cmd;
File dataFile;
cmd=server.argName(0);
switch(cmd.toInt())
{
case 1: // Take photo
if(c_state)
{
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");
}
c_state = !c_state;
break;
}
index_dt = index_00;
cmd = "<img src='/data.jpg'>\n"
"<form method='get'>\n<button type='submit' name='1' class='bt1'>Stream</button>\n";
if(c_state)
{
cmd = "<img src='/data.strm'>\n"
"<form method='get'>\n<button type='submit' name='1' class='bt1' onClick='onBtnStearm()'>Photo</button>\n";
}
index_dt += cmd;
index_dt += "</form>\n</div>\n</center>\n<script>\nfunction onBtnStearm() {\n window.stop();\n}\n</script>\n</body>\n</html>";
server.send(200, "text/html", index_dt);
}
void handleWebRequests()
{
String dataType = "text/plain";
String path;
File dataFile;
int a;
WiFiClient client;
camera_fb_t * fb;
a = 1;
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/jpg";
else if(path.endsWith(".strm"))
{
client = server.client();
String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: multipart/x-mixed-replace; boundary=--frame\r\n\r\n";
server.sendContent(response);
while (1)
{
fb = esp_camera_fb_get();
if (!client.connected())
{
esp_camera_fb_return(fb);
break;
}
response = "--frame\r\n";
response += "Content-Type: image/jpeg\r\n\r\n";
server.sendContent(response);
client.write(fb->buf, fb->len);
server.sendContent("\r\n");
esp_camera_fb_return(fb);
if (!client.connected()) break;
}
a=0;
}
delay(5);
if(a)
{
dataFile = SD.open(path.c_str(), "r");
server.streamFile(dataFile, dataType);
dataFile.close();
delay(5);
}
}
- 10−27行: ピンの定義
- ピンは、” CAMERA_MODEL_WROVER_KIT // Has PSRAM” 用です。
- サンプルスケッチから引用。
- 29−33行: SD Card ピンの定義
- 36−37行: ルータのSSIDとPassword
- 今回はESP32にWebサーバーを立ち上げます。
- ルーターにつなぐ為、ルーターのSSIDとPasswordをここに入力します。
- 40行: camera_fb_t * fb = NULL
- この変数は写真撮影時に使用します。
- 53行: void setup()
- 76行まで: WiFiに接続
- 78−81行: コンピュータ名を”esp32cam”と設定。
- WebサーバーへのアクセスはIPアドレスでは無くコンピュータ名で行います。
- 83行: カメラの初期化。
- 解像度をVGA指定(124行)。それ以外はサンプルスケッチと同じ
- 設定したConfigのポインターを引数に、esp_camera_init(&config);を実行すれば初期化完了
- 85−86行: SDカードの初期化
- 88行: Webサーバーの起動
- 91行: クライアント要求の対応先の指定。
- クライアントからの要求は、handleRoot 関数で行う
- 132行: void handleRoot()
- 写真の保存
- fb = esp_camera_fb_get();(143行)写真の撮影。
- 144行:保存用ファイルの作製。
- 145行:でーたの書込
- 146行:書込終了。
- 147行:esp_camera_fb_return(fb);。esp_camera_fb_get();とセットで使う様です。
- モードの切り替え
- WebサーバーのHPで表示されるボタンを押すたびモードを切り替えています。
- 写真の保存
- Streamingはvoid handleWebRequests()で実行
- 186−213行:クライアントからStreaming要求があったらここで対応しています。
- カメラが撮影した画面(静止画)をひたすらクライアントに送信しています。
- クライアントの接続の有無を終了判定にしています。
- 判定としてはちょっと不適切に思いますが
プログラムの実行
プログラムをコンパイルして実行。PCでWebブラウザーをあげて下さい。ブラウザーはFire Foxを推奨します。どのブラウザーでも動作すると思うのですが他のブラウザーでは動作を確認していません。
- アドレス欄に、”esp32cam.local”と入力すると下記の様な画面が表示されます。
- この時、画像は静止がでは無く動画です。
- ”Photo”ボタンをクリックすると表示されていた画面が”data.jpg”としてSDカードに保存されます。
- ボタンが”Streaming”に代わり、画面に保存された画像が表示されます。(この時は静止画)
- この状態で”Streaming”を押せば、ボタンが”Photo”に代わり、Streamingが始まります。
次回は
設定をちゃんと行えば、fb = esp_camera_fb_get(); で画像の撮影が出来る事が分かりました。 また、これをSDカードに保存する方法も分かりました。
これにメール機能(指定先にメールを送る)を付けて訪問者チェックに使えないかと思っています。次回はメール機能を付けたいと思います。