0
0

ESP32 WROVER CAMで複数ライブカメラ

Posted at

ESP32-CAMでもテストしましたがなんだか不安定なのでESP32 WROVERでのテストにしました。LAN内に複数カメラを設置してWIFIでそれぞれの画像を監視するものです。例えば家の中の部屋にいくつか設置したり、家の中から外に向けて設置したりして画像を確認するものです。各部屋のURLはHTMLのリンクでつなげます。

wifi,固定IPなどの設定

  • wifiのIDなどを指定する
  • thread処理したら不安定だったのでesp_http_server.hを使い単一接続とする
  • DHCPでなく固定IPとなるように設定する
/*
 * @file  wrover_webserver-nothread.ino
 * @brief ESP32-WROVER カメラを使いLAN内で監視カメラ構築
 * @details HTTPのマルチパートストリームを用いて複数のWROVERをWEBリンクで繋ぐ。
 *          10秒間だけWEBストリーミング画像を映す。(負荷低減の為)
 *          DHCPアドレスを固定IPに指定する。
 */
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_http_server.h"

// 変更箇所①
const char* ssid = "XXXXXXXXX";  // 接続するWiFiのSSID
const char* password = "XXXXXXXXX";  // 接続するWiFiのパスワード

// 変更箇所②
const IPAddress ip(192,168,0,13);
const IPAddress gateway(192,168,0,1);
const IPAddress subnet(255,255,255,0);

HTTPのマルチパートストリーム

//リアルタイムにストリーミング画像を表示するためには、HTTPのマルチパートストリームを利用。
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=frame";
static const char* _STREAM_BOUNDARY = "\r\n--frame\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

// 変更箇所③
static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESP32 Camera</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; }
        img { width: 320px; height: 240px; }
        .link { margin: 10px; display: block; }
    </style>
</head>
<body>
    <h1>部屋A</h1>
    <img src="/stream" id="camera-stream">
    <h2>他カメラ</h2>
    <a href="http://192.168.0.12" class="link">リビング</a>
    <a href="http://192.168.0.13" class="link">部屋A/a>
</body>
</html>
)rawliteral";

ストリームを処理するハンドラ

  • 15秒間だけストリーミングするようにする(負荷軽減)

static esp_err_t stream_handler(httpd_req_t *req) {
    camera_fb_t *fb = NULL;
    esp_err_t res = ESP_OK;
    size_t _jpg_buf_len = 0;
    uint8_t *_jpg_buf = NULL;
    char part_buf[64];

    res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
    if (res != ESP_OK) {
        return res;
    }

    unsigned long startTime = millis();  

    while (millis() - startTime < 15000) {  // 15秒間ストリーミング時
        fb = esp_camera_fb_get();
        if (!fb) {
            Serial.println("Camera capture failed");
            res = ESP_FAIL;
        } else {
            if (fb->format != PIXFORMAT_JPEG) {
                bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
                esp_camera_fb_return(fb);
                fb = NULL;
                if (!jpeg_converted) {
                    Serial.println("JPEG compression failed");
                    res = ESP_FAIL;
                }
            } else {
                _jpg_buf_len = fb->len;
                _jpg_buf = fb->buf;
            }
        }

        if (res == ESP_OK) {
            size_t hlen = snprintf(part_buf, 64, _STREAM_PART, _jpg_buf_len);
            res = httpd_resp_send_chunk(req, part_buf, hlen);
        }
        if (res == ESP_OK) {
            res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
        }
        if (res == ESP_OK) {
            res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
        }

        if (fb) {
            esp_camera_fb_return(fb);
            fb = NULL;
            _jpg_buf = NULL;
        } else if (_jpg_buf) {
            free(_jpg_buf);
            _jpg_buf = NULL;
        }

        if (res != ESP_OK) {
            break;
        }


    }

    // ストリーミング終了後、残りのチャンクを送信して終了 15秒間ストリーミング時
    httpd_resp_send_chunk(req, NULL, 0);

    return res;
}

カメラサーバーを開始する関数


void start_camera_server() {
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    httpd_uri_t index_uri = {
        .uri       = "/",
        .method    = HTTP_GET,
        .handler   = index_handler,
        .user_ctx  = NULL
    };

    httpd_uri_t stream_uri = {
        .uri       = "/stream",
        .method    = HTTP_GET,
        .handler   = stream_handler,
        .user_ctx  = NULL
    };

    if (httpd_start(&server, &config) == ESP_OK) {
        httpd_register_uri_handler(server, &index_uri);
        httpd_register_uri_handler(server, &stream_uri);
    }
}

その他の設定

  • カメラモデルに基づくピン配置の設定
    if defined(CAMERA_MODEL_WROVER_KIT)
  • カメラの設定
    camera_config_t config
    上記はいつもと同じように設定します。
  • 電源はPCからとらずAC電源からUSB接続します。特にESP32-CAMでするときはで電圧降下しました。
  • その他安定させるために色々策を施しています。

テスト結果

  • 画像下のリンクURLをクリックすると各カメラへ移動します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0