本記事の目的と概要
M5Stack社は、WiFiやBluetoothによる無線通信やアナログ・デジタル入出力ポートを複数持ちディスプレイやボタンなど一通りの入出力を備えたマイコン開発キット「M5Stack(※)」や、M5Stackシリーズ共通で備えているGroveポートを介して接続可能なセンサ等の周辺機器などを開発・販売している。
※:M5Stackのほかにも、M5AtomなどEspressif社のマイコン「ESP32」を搭載する製品群を扱っている。
M5Stackは安価な割に使いやすいことから非常に人気であり、様々な書籍等で扱われているため入門はしやすい。一方で、M5Stack向けのセンサ等(UnitやHATなど)については、非常に簡単に手に入る一方でドキュメントやサンプルプログラムが(初心者には)わかりづらかったり説明不足であると感じる部分が多くある。
特に、マイナーな本体(M5Atomなど)やマイナーなユニット、あるいはそれらを組み合わせるとサンプルプログラムそのままでは動かず、初心者にはどこを修正すれば動くのか見当もつかず途方に暮れることになる。
ところで、M5Stack社が扱う製品の中には、マイコン本体ともユニットともつかない微妙な立ち位置のものがある。例えば、本記事で扱うUnit CamS3-5MPなどのように、ユニットと名乗りながらユニット自体にESP32のようなマイコンを搭載しているものがある。このようなユニットはM5Stackなどのいわゆる「本体」なしでそれ単体で動かすことができる(が、そのせいで他のユニットの情報が役に立たなかったりして結構面倒だったりする)。
前置きは以上として、本記事の目的はM5Stack社 Unit CamS3-5MPを使って500万画素の写真を撮影する方法をまとめることである。
www.switch-science.com/products/9923
Unit CamS3-5MPは、2メガピクセルのカメラ「OV2640」を搭載したUnit CamS3(生産終了)の後継となる製品で、謎のカメラモジュール「PY260」を搭載し500万画素の写真を撮影することができる(ということになっている)。
ところが、「Unit CamS3-5MPはUnit CamS3のプログラムと互換性がなく、旧製品のプログラムをそのまま流用しても動かない」とか、「M5Stackのサンプルプログラムでは動かない」とかいうような情報ばかり見つかり、どうすればうまく動くかがまとめられた情報が見つからなかった。特に、せっかく「5MP」という特徴があるにもかかわらず、どうすれば500万画素の写真が撮れるか、という点については全く情報が見つからなかったので試行錯誤することになった。本記事では、どうにか500万画素で写真を撮影することができたので、その手順等についてまとめる。
M5Stack社公式のArduino向けサンプルプログラムの書き込み手順について
M5Stack社の公式HPに記載のArduinoを使ったサンプルプログラムの書き込み手順についてリンク先の手順を抜粋しつつ簡単に示す。
手順①:ボードマネージャ周りの設定
以下のURLをAdditional Boards Manager URLsに「https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json」を追加する。
サイドバーのBoard Manager optionに「ESP32」を入力し、最新の「esp32 by Espressif Systems」をダウンロードする。
手順②:ESP32-CameraのStatic Libraryを入れ替える
libespressif__esp32-camera.zipをダウンロードし、「libespressif__esp32-camera.a」や「esp_camera.h」「sensor.h」を置き換える。
手順③:サンプルプログラムの入手・編集
Unit CAMS3-5MP Arduino Demo CameraWebServerからサンプルプログラムを入手し、自宅のWiFi環境に合わせSSIDとパスワードを編集する。
手順④:コンパイル&書き込み
以下の設定を忘れずに行い、コンパイル&書き込みを行う。
- Board Selection: Tools -> Boards -> ESP32 -> M5UnitCAMS3
- USB CDC Configuration: Tools -> USB CDC On Boot -> Enabled
- PSRAM Configuration: Tools -> PSRAM -> OPI PSRAM
手順⑤:実行
プログラムが書き込まれたら、自動的にUnit CamS3-5MPが再起動される。この時、シリアルモニターでボーレートを115200に設定していれば、UnitCamS3-5MPのIPアドレスがシリアルモニターに表示されるので、Unit CamS3-5MPと同じWiFiに接続されているPC/スマホからUnit CamS3-5MPのIPアドレスにアクセスする。
※:例えば、Unit CamS3-5MPのIPアドレスが「192.168.0.34」ならば、Google Chromeなどのウェブブラウザのアドレス欄に「http://192.168.0.34」などを入力すればよい。
以上の操作を行うことで、ブラウザ上の「Get Still」などのボタンを押すことで、ブラウザ上にカメラの画像が表示される。なお、サンプルプログラムを実行すると、最高でも1600×1200の2MP(200万画素)の写真しか撮れない。
5MP(500万画素)の写真を撮るためには?
色々調べた結果、5MPの写真を撮るためには、カメラの設定「frame_size」を「FRAMESIZE_5MP」に設定すればよさそうなことが分かった。しかし、サンプルプログラムは無駄に複雑で、どこを書き換えればよいのかさっぱりわからなかった。
そこで、Unit CamS3-5MPのサンプルプログラムのもととなったプログラム「ESP32-Cam」だとか「CameraWebServer」について調べたところ、Unit CamS3-5MPのサンプルプログラムはこれらのプログラムをほぼそのまま使用し、ピン番号等のみを修正したものであることが分かった。
そこで、ESP32-Camを使った必要最低限の機能で動作するプログラムがないか探したところ、以下のリンク先のような記事が見つかった。
note.com/khe00716/n/n704ec39c4a26
上記リンク先のプログラムを参考に、Unit CamS3-5MPで500万画素の写真を撮影できるようUnit CamS3-5MPのサンプルプログラムを修正したプログラムは以下の通りである。
CameraWebServer.ino
修正のポイントは、WiFiのアクセスポイント情報と、カメラのフレームサイズである。
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
config.frame_size = FRAMESIZE_5MP;
ソースコードは以下の通り。
#include <esp_camera.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM
#include "camera_pins.h"
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
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_5MP;
config.jpeg_quality = 2;
config.fb_count = 1;
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
/*if (MDNS.begin("esp32cam")) {
Serial.println("MDNS responder started");
}
/**/
}
void loop() {
// put your main code here, to run repeatedly:
delay(10000);
}
app_httpd.cpp
これは、Unit CamS3-5MP上で動くhttpサーバで表示されるウェブページの動作を表したプログラムであるが、参考リンクのプログラムそのままである。
#include <esp_http_server.h>
#include <esp_camera.h>
#include <Arduino.h>
httpd_handle_t camera_httpd = NULL;
static esp_err_t capture_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
int64_t fr_start = esp_timer_get_time();
//画像の取り込み
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
httpd_resp_set_type(req, "image/jpeg");
Serial.println(fb->width);
size_t fb_len = 0;
fb_len = fb->len;
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
esp_camera_fb_return(fb);
int64_t fr_end = esp_timer_get_time();
Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000));
return res;
}
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_uri_t capture_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = capture_handler,
.user_ctx = NULL
};
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &capture_uri);
}
}
まとめ
以上の手順を踏むことで、とりあえずUnit CamS3-5MPで500万画素の写真を撮影することができる。それはそれとして、写真のノイズが目立ち画質が悪く見えるため、写真撮影時のパラメータについてはまだまだ調整が必要そうであるので、今後試行錯誤したい。
コメント