m5camera の映像をArduino IDE のシリアルモニターに表示させている画像

M5Camera の映像をArduino IDE シリアルモニターに表示させてみる

記事公開日:2019年7月19日

超久々の投稿です。お待たせしました!!!

今回は M5Camera ( M5Stack社製 )の動作を解明するための第1弾として、M5Camera で撮った映像を Arduino IDE のシリアルモニターにリアルタイムに表示させる実験をしてみました。しかも、PSRAMは一切使いません。

Arduino core for the ESP32 にある esp32-cameraライブラリを読み解き、M5Camera にマウントされている OmniVision Technologies社製CMOSカメラモジュール ( イメージセンサ )からの画像データを自分の意図した形で取り出せるようになりました。
Arduino IDE のシリアルモニターはテキスト表示専用ですが、それに画像表示ができると新鮮味がありますね。

スポンサーリンク

ところで、いきなり話が逸れますが、最近は M5Stack社から M5StickV というものが販売されて話題になっていますね。
それは主にMicro Python用で、Arduino IDEのC/C++で開発はできない模様です。
私にはとても使いこなせそうにありません。まだまだArduino IDE の C/C++ 言語だけで手一杯ですので、しばらく ESP32 関連に絞った開発をしていきます。

ということで、話を戻して、何はともあれ以下の動画をご覧ください。

どうでしょうか?
LCDディスプレイに表示させるのとは違って、なかなか面白いと思いませんか?

因みにこれはQQVGA( 160 x 120 pixel )の画像を更に部分的に抽出して、60 x 20 pixel の画像を出力しています。

ただ単に、Arduino core for the ESP32 の開発チームの方々が作られたライブラリを使わせて頂いているだけですが、これが出来るようになると、自分の力でカメラセンサーを制御してやったぜ!!!・・・っていう気になっちゃうかもしれませんね。

では、この方法をこれから紹介していきますが、esp32-cameraライブラリの解説についてはあまりにも情報量が多いので、今回の記事ではまずは簡単なサンプルスケッチからpixel ( 画素 )データを抽出する方法を紹介したいと思います。

ところで、ちょっとここでお礼を言わせてください!

しばらくこのブログ記事更新が滞っていましたが、それでもこのブログの支援を続けて下さった方々に本当に感謝したいと思います。
とっても力になっており、ブログ運営費に有効に使わせて頂いております。

本当にありがとうございました!!!
m(_ _)m

まだまだ多忙で、なかなか記事アップの頻度が上げられませんが、後日アップする予定の記事では、さらに踏み込んだ内容で、ESP32 開発ボードと OV2640 単体モジュールをブレッドボードで接続した例を載せる予定です。
今後とも何卒よろしくお願いいたします。

このブログの維持運営にご支援いただけると助かります。
支援方法はこちらの記事をご覧ください。
(管理人:mgo-tec)

 

    【目次】
  1. M5Camera および esp32-cameraライブラリの解明がムズイ!
  2. 使う物
  3. Arduino core for the ESP32 のインストール
  4. Arduino core for the ESP32 のボード設定
  5. esp32-cameraライブラリを使って、カメラ映像をシリアルモニターに表示させるサンプルスケッチ
  6. コンパイル書き込み実行
  7. 編集後記

M5Camera および esp32-cameraライブラリの解明がムズイ!

まず、苦労話からザッと言わせてください。

実は以前、このブログで「今年こそはディープラーニングを始める」と宣言したのですが、そもそもそれ以前の問題で、まずはカメラモジュールを自在に制御できないと何も始まりませんでした。

そこで、手軽な M5Camera を使って、まずは画素データを抽出しようしたのですが、サンプルスケッチがとんでもなく難解!
そして、esp32-cameraライブラリの動作の仕組みがなかなか読み解けなかったんです。
ネット上にも殆ど情報がありませんでした。

先に紹介した動画のように、M5Camera の CMOSカメラモジュール OV2640 のデータをプログラミングで自分の意図したデータが取り出せるようになるまではメチャメチャ苦労しました。

また、Twitterでもつぶやいておりますが、ここ数か月は本業と家庭の事情でとっても多忙でした。

かれこれ4か月近く、数少ない空いた時間でひたすらこの解明に取り組んでいましたが、私の様な独学素人では、SCCBインターフェースやI2S通信、DMA転送などを理解するのにえらく時間がかかってしまいました。
正直、まだ半分も理解していないと思います。

以前、M5Camera のこちらの記事で、カメラ映像をスマホにリアルタイム転送できるサンプルスケッチを紹介しました。
esp32-camera のサンプルスケッチはとっても便利ですが、どこをどうやってプログラミングしたら画素データを取り出せるのかがサッパリ分かりませんでした。
しかも、M5Camera には PSRAM メモリが装備されていて、esp32-cameraサンプルスケッチの解明も更に難解にしている要因でした。

しかし、あきらめないで続けていた結果、今回、ようやくある程度解明できて、カメラモジュール OV2640 が取得したピクセル(画素)データを抽出することができるようになりました!!!
これでようやくディープラーニングの勉強が始められそうな気がしてきました。

今回は、PSRAM を一切使わず、カメラモジュール OV2640 が取得したデータをリアルタイムに抽出して、Arduino IDE のシリアルモニターに表示させることができました。
ただし、画面サイズは QQVGA ( 160 x 120 pixel ) のみです。
PSRAM等の外部メモリ無しではこのサイズが限界のようです。たぶん・・・。

ということで、これから Arduino core for the ESP32 内の esp32-cameraライブラリを自己流で解読したことを紹介していきますが、あまりにも情報量が多いので記事を分割して投稿します。
今回はその第1弾として、esp32-cameraサンプルスケッチ(サンプルソースコード)をちょっと改変して、Arduino IDE のシリアルモニターにカメラ映像を表示させる方法を紹介したいと思います。
(次回の記事では、M5Camera を使わず、ESP32開発ボードとOV2640モジュールだけで制御する方法を紹介する予定です。)

使う物

M5Camera

m5camera_serial_monitor01.jpg


スイッチサイエンスさんで販売しています。

https://www.switch-science.com/catalog/5207/

M5Stack社製で、Espressif社製 Wi-Fi & Bluetooth マイコンモジュール ESP32 WROVER を搭載し、4MBのFLASHと4MBの PSRAM 内蔵です。
OmniVision Technologies社製CMOSカメラ(イメージセンサ)モジュール OV2640 を搭載していて、160×120 pixel~最大1600×1200 pixel の画像処理が可能です。
これの初期動作をレビューした記事がありますので、以下のリンクを参照してください。

M5Camera をレビューしてみた。分解したり、Arduino IDE でスマホに映したりする実験

M5Camera は、いざ自分で OV2640 モジュールとマイコンを結線しようとすると、多量のワイヤーを繋げねばならず、面倒なので、予め基板接続してあるM5Cameraを使った方が断然安心で手っ取り早いですね。

パソコン、USB-TypeC ケーブル等

以下、Windowsパソコンで説明します。

パソコンはできるだけ高速CPU、大容量メモリのものを使用してください。

Arduino core for the ESP32 のインストール

Arduino IDE のバージョンは 1.8.9 で動作確認しております。

Arduino IDE のボードプラグイン、Arduino core for the ESP32 のバージョンは stable 1.0.2 で動作確認しております。
Arduino core for the ESP32 のインストール方法は以下の記事を参照してください。

Arduino core for the ESP32 のインストール方法

Arduino core for the ESP32 のボード設定

Arduino core for the ESP32 のボード設定は以下のようにしてみてください。
ボードは本来 ESP32 WROVER ですが、今回はより細かい設定ができる ESP32 Dev Module にします。
そして、PSRAM は Disabled にするところがポイントです。
あとはご自分の環境に合わせて設定してみてください。

ボード:  ESP32 Dev Module
Upload Speed:  921600
CPU Frequency:  240MHz (WiFi/BT)
Flash Frequency:  80MHz
Flash Mode:  QIO
Flash Size:  4MB (32Mb)
Partition Scheme:  Huge App
Partition Scheme:  Huge APP (3MB No OTA/1MB SPIFFS)
Core Debug Level:  なし
PSRAM:  Disabled
シリアルポート:  ※ご自分の M5Camera のUSBポート
————————————-
書込装置: USBasp

 

m5camera_serial_monitor02.jpg


esp32-cameraライブラリを使って、カメラ映像をシリアルモニターに表示させるサンプルスケッチ

では、esp32-camera ライブラリを使って、カメラセンサーモジュール OV2640 が取得した画像データをシリアルモニターにリアルタイム表示させる簡単なスケッチ(サンプルプログラム ソースコード)を紹介します。

シリアルモニターは白黒モノトーンの文字しか表示できないので、Red, Green, Blue それぞれ0~255の値で構成された pixel(画素)データで、全ての色が100を下回った場合のみシリアルモニターに文字表示させました。
白い紙に黒色文字を書いた物を投影する場合と思ってください。

#include "esp_camera.h"

#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    15
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     22
#define SIOC_GPIO_NUM     23

#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM        5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       32
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

void setup() {
  Serial.begin(500000);
  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_RGB888;
  config.frame_size = FRAMESIZE_QQVGA;
  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;
  }
}

void loop() {
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;

  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }

  uint8_t * test_buf = NULL;
  test_buf = fb->buf;

  uint8_t red = 0, green = 0, blue = 0;
  const uint16_t max_h_pix = 160 * 3;
  const uint16_t max_v_pix = 120;

  for(int j = 0; j < max_v_pix-100; j++){
    for(int i = 0; i < max_h_pix-300; i++){
      red = *(test_buf + j * max_h_pix + i);
      green = *(test_buf + j * max_h_pix + (i+1));
      blue = *(test_buf + j * max_h_pix + (i+2));

      if (red < 100 && green < 100 && blue < 100) {
        Serial.print('#');
      } else {
        Serial.print(' ');
      }

      i += 2;
    }
    Serial.println();
  }
  Serial.println("------------------------------------------------------------");
}

【解説】

●1行目:
esp_camera ライブラリのインクルードです。

●3-19行:
M5Camera 内蔵の ESP32 WROVER の GPIO ピンアサインを定義しています。

3行目の PWDN_GPIO_NUM はパワーダウンモードに切り替えるためのものですが、これは今回使いませんので、-1にしてあります。

また、OV2640 カメラモジュールには、Y1, Y0 ピンがあるのですが、M5Camera では使いませんので定義不要です。
実は後日記事にしようと思っているのですが、外付けで OV2640 モジュールを接続する時に、PWDN ピンと、Y1, Y0 ピンの接続方法を気を付けなければいけない点があるのです。
次回記事で説明します。

●22行:
シリアルモニターの動作開始指令ですが、シリアルデータ転送速度を 500000bps としています。
これには実は理由があって、ESP32 開発ボードとOV2640カメラモジュールをブレッドボードで接続して実験する場合は500000bpsが限界なのです。
本当は2000000bpsにしたいところですが、ブレッドボードでは無理でした。
M5Camera を使った場合は 2000000bps でも問題ありませんでした。

●25-47行:
esp32-camera ライブラリの config 設定構造体の初期化です。
26-27行目のところで、LEDC信号発生の為の定義をしていますが、ESP32 の LEDC を使って高周波クロックを発生させています。
LEDC については以前のこちらの記事を参照してください。
28-35行目は、OV2640 から送信されてくるパラレルデータを、ESP32 の I2S LCD カメラスレーブモードで受信するためのピンアサインです。これについては、後日の記事で詳しく紹介しようと思います。

44行目の xclk_freq_hz は、ESP32 の xclk ピンから、LEDCのPWMで生成したクロック周波数を決めています。
以前のこちらの記事で説明したように、ESP32 で出力できるクロックパルスの周波数は 40MHz が最高で、その次に低い周波数は必然と 20MHz になってしまいます。
OV2640 のデータシートによると、最低周波数が6MHz で 24MHz が標準のようですが、ESP32 では24MHz直近の20MHzが良いということになります。

46行目では画像のフレームサイズをQQVGA ( 160×120 pixel )にしています。
それ以上だとPSRAMが必要になります。

●50行目:
ここで、esp-cameraライブラリの初期化をします。
この esp_camera_init という関数で、ESP32 の SCCB インターフェース( I2C互換 )をセットアップして、OV2640を起動させ、指令を与え、画素データを8bitパラレルで ESP32 に送信させるようにしています。
そして、ESP32 は I2S LCD カメラスレーブモードで受信する体制を整えています。

ところで、SCCBインターフェースは I2C 互換なので、試しに Arduino core ESP32 の Wireライブラリで制御してみたりしたのですが、うまくいきませんでした。
これについては後日アップする記事で詳しく解説しようと思っています。

●57-93行:
esp_camera_initを実行すると、OV2640から延々と止め処なく画像データが ESP32 の GPIO に送られてきます。
1pixel の中の red, green, blue の各1バイトの色データは ESP32 の SRAM 上の
fb->buf
に格納されています。
SRAM上ですから、QQVGA までのフレームサイズで限界というわけです。
それ以上は PSRAM を使う必要があります。
OV2640 から送られてくるデータは、まずは ESP32内のDMA専用のメモリに格納されていて、それから fb->buf に順番にコピペされているわけです。
(この DMA っていうものが不勉強な私にはかなり難しかったわけですが、これについては後日の記事で詳しく解説します。)
そしてリアルタイムに1フレームごと常に fb->buf が書き換えられています。
そのバッファメモリデータを 61行目の esp_camera_fb_get 関数で読み取りに行っているというわけです。

74行目の forループでは、シリアルモニターに垂直120 行 まで表示させてしまうと、画面が大きくなり過ぎるので、シリアルモニターウィンドウに適度に収まるように、適当にmax_v_pix から100行差し引いています。

また同じく、75行目も水平160 pixel では画像が大きくなり過ぎるので、シリアルモニターウィンドウに収まるように、300を差し引いています。

76-78行のように、test_bufポインタには、red, green, blue の各データが順番に格納されているので、順番に取り出せば良いわけです。

そして、80-84行にあるように、各色0~255の範囲の明るさなので、100以下の明るさの場合は’#’を表示させています。それ以外は空白表示です。

コンパイル書き込み実行

では、先のスケッチ(プログラムソースコード)を Arduino IDE でコンパイル書き込み実行させてみて下さい。

そして、シリアルモニターの設定を下図の様にしてみてください。
自動スクロールにして、転送速度を 500000 bps にしてください。

m5camera_serial_monitor03.jpg


これで、最初に紹介した動画のように表示されればOKです。

500000 bps ということは、1秒間に 500,000 bit をシリアルモニターに転送しています。
1画像(1フレーム)のサイズ 160 x 120 pixel を更に縮めて、60 x 20 pixel にしています。
破線”———“や改行コード等を入れると、62 x 21 バイトを送信していることになるので、1フレームのビット数は
62 x 21 x 8 = 10,416 bit
になるのかなと思います。
(間違えていたらゴメンナサイ。)
そうなると、シリアルモニターと言えども、フレームレートはかなり速めではないかと思います。
これは各自計算してみて下さい。
まぁ、シリアルモニター表示程度でフレームレートを計算する必要は無いと思いますが・・・。

また、最初の動画にあるように、文字表示専用のシリアルモニターに無理やり画像を表示させていますから、チラつきがあるのは仕方ありません。
ちゃんとしたカラー画像をLCDディスプレイに表示させる方法は、後日、段階的に記事にしていきたいと思います。

ということで、このプログラムをいろいろ工夫すれば、特定の色や輝度に反応するプログラムも書けそうですね。いろいろな創造の幅が広がります。
ディープラーニングに使うデータ収集もできそうな気がしますね。

それにしても、このesp32-cameraライブラリはよくできていますね。
開発者チームの方々に改めて感謝したいです。

ありがとうございまーーす!!!

m(_ _)m

編集後記

最初にも申し上げましたが、かれこれ4か月以上、私の本業が多忙になったことと、家庭の事情などでブログ記事更新が滞っていました。
そんな状態でも粘り強くこのブログを支援して下さった方々、重ね重ねですがほんとうにありがとうございました。
m(_ _)m

4か月の間、空いた時間でチマチマとM5Camera と esp32-cameraライブラリの解明をしていましたが、あまりにも組み込み開発関連の自分自身の知識不足のために途方に暮れていました。
SCCBインターフェースや、I2S インターフェース、DMA転送など、アマチュアの私には難解過ぎました。
カメラセンサーの値を高速でリアルタイムに可視化することって、こんなにも難しいものなのかと思いました。
SCCB や I2S、および DMA については次回の記事で解説していきたいと思います。
SDカードの画像データをLCDディスプレイに表示することよりも、かなり難易度高いと思いました。

でも、あきらめずに、ESP32 や OV2640 のデータシート読み解きながら、少しづつ解釈していくと、いつか見通しがパッと開けるときがあるもんですね。
そうなってくると俄然楽しくなりますね。

結局のところ、OV2640カメラセンサーから画像データを取得することと、SDカードからデータを抽出することは、そんなに変わりはない仕組みだということも最近やっと分かって来ました。
これらを開発してきた先駆者の方々はホントにスゴイものがありますね。
そのおかげで、今、私たちが趣味の電子工作ができるわけですからね。

ということで、次回は esp32-cameraライブラリを更に踏み込んで解説するために、ESP32 開発ボードと OV2640 カメラモジュールをブレッドボードで接続して動作させた実験を紹介したいと思います。

ではまた。。。

スポンサーリンク


Amazon.co.jp 当ブログのおすすめ
Amazon.co.jp
M5Stack Basic
スイッチサイエンス
Amazon.co.jp
ESPr Developer 32
スイッチサイエンス(Switch Science)
Amazon.co.jp
Amazon.co.jp

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください