スタートレックのコミュニケータを作る企画の9回目です。
前回は、TFT ディスプレイの表示テストを行って、最終的に LovyanGFX ライブラリの使用方法を検証できました。
(前回の TFT の表示についての記事は、以下のリンクをご覧ください。)
今回は、LovyanGFX ライブラリを使ってモアレ動画の再生にチャレンジして成功しました。
なお、以前は1つの記事だった SD カードの詳細と、AliExpress に注文した SD カードが容量偽装品だった事については、長くなるので別記事にしました。(リンク先をご覧ください。)
Arduino IDE で読みこみ
SD カードを Arduino IDE で使用するには、「SD.h」「SdFat.h」「SD_MMC.h」の3種類のライブラリが用意されています。
しかし、ネットで調べた限りでは「SD_MMC.h」は配線などが色々と面倒らしいので、「SD.h」「SdFat.h」を試してみます。
(この2つでは「SdFat.h」が動作が速いらしいです。)
SD ライブラリ
SD ライブラリは標準で導入済みなので、スケッチを書きこめば動作します。
この企画の7回目の接続表どおりに ESP32 と SD カードアダプタを接続します。
そして、SD カード内に「test1.txt」という名前のテキストファイルを書き込んで、下のスケッチを書きこめば、内容が読み込まれてシリアルモニターの画面に表示されます。
#include "FS.h"
#include <SD.h>
#define sd_sck 4
#define sd_mosi 6
#define sd_ss 2
#define sd_miso 5
void setup()
{
File fo;
char ch;
delay(1000); //ウエイトを入れてから起動しないとシリアルが出力されない。
Serial.begin(115200); //COMオープン
SPI.begin(sd_sck, sd_miso, sd_mosi, sd_ss);
//SDモジュールの初期化
if(!SD.begin(sd_ss)){
Serial.println("Failed to mount card");
return;
}
//sample.txtファイルを読込み用に開く
fo = SD.open("/test1.txt",FILE_READ);
if(fo){
Serial.println("Read from SD");
//ファイルの中身を読込んでシリアルモニタに表示
while(fo.available()){
ch = fo.read();
Serial.print(ch);
}
Serial.println("\nRead End");
//ファイルを閉じる
fo.close();
}else{
//ファイルを開けなかった場合
Serial.println("Opening File to read failed");
return;
}
}
void loop()
{
}
なお、ESP32 C3 でシリアル通信を有効にするには、「ツール」の「USB cDC On Boot」を「Enable」にします。

SdFat ライブラリ
SdFat ライブラリは、ライブラリマネージャーからインストールします。

そして、SD カード内に「test1.txt」という名前のテキストファイルを書き込んで、下のスケッチを書きこめば、内容が読み込まれてシリアルモニターの画面に表示されます。
#include "FS.h"
#include <SdFat.h>
#define sd_ss 2
SdFat sd;
SdFile myFile;
void setup()
{
delay(1000); //ウエイトを入れてから起動しないとシリアルが出力されない。
Serial.begin(115200); //COMオープン
//SDモジュールの初期化
if(!sd.begin(sd_ss, SPI_FULL_SPEED)){
Serial.println("Failed to mount card");
return;
}
//test1.txtファイルを読込み用に開く
myFile.open("/test1.txt", O_READ);
Serial.println("test1.txt:");
//ファイルの中身を読込んでシリアルモニタに表示
int data;
while ((data = myFile.read()) >= 0) Serial.write(data);
//ファイルを閉じる
myFile.close();
}
void loop()
{
}
SD カードの画像ファイルを表示
それでは、SD カードの画像を表示します。
画像を表示するには以下の物を準備する必要があります。
・小容量の SD カード:最大でも 32 GB 以下、手に入れば 2 GB のものを FAT でフォーマットしてください。
・画像ファイル:Jpeg なら「プログレッシブ」の設定を外して保存してください。LovyanGFX ライブラリではプログレッシブ Jpeg は読み込めません。
今回は PNG ファイルで保存したので設定は不要です。
モアレ用画像
コミュニケータの「アルファ」用のモアレ・パターンを HeroComm さんのページから入手します。
最初、オリジナルのコミュニケータの動作をまねて、「Bottom」画像を下にして、「Top」画像を重ねてプログラムで処理しようと考えました。
都合の良いことに、今回使用する LovyanGFX ライブラリにはいろいろなことが出来ます。
画像表示のために「スプライト」と呼ばれる、画像処理ソフトのレイヤーみたいな機能です。
このスプライトを使うと、読み込んだ画像を重ねるだけではなく、画像の拡大・縮小・移動や回転、指定色を透過色にすることまで出来ます。
まさに、コミュニケータのモアレを作るための機能みたいですね。
早速、HeroComm さんのページから入手したモアレのパターンを、スプライトに読み込んで回転させてみました。
・・・ダメですね。
私のやり方が悪いのか、 240 X 240 では解像度が足りないのか、透過色の部分がモヤがかかったように不鮮明でモアレ模様になりません。
他の方法を考えます。
モアレ用の画像を作る
しかたがないので、モアレ用の画像を事前に作っておいて、パラパラ・アニメの要領で画像を切り替える方法で試験します。
(キレイにグルグルするか心配です。)
入手した画像を GIMP に読み込みます。
Bottom を下に、Top を上に重なるレイヤーに読み込みます。

上のレイヤーを指定したら、 Shift+Rキーで「回転ツール」を起動して、ダイアログの「角度」に数値を入力して回転させます。

Top 画像を少しずつ回転した画像をグレースケールに変換して、サイズを 240 X 240 の PNG ファイルに保存しました。
今回の表示試験では、10度ずつ回転したものを18枚(10°~180°)準備しました。
元の RGB 画像だと1枚 100 kB 位ですが、グレースケールに変換すると1枚の容量は 50 kB 程度に小さくなり高速に表示できます。
使用した18枚の合計で 1 MB ぐらいですから、この程度の容量なら、ESP32 内部のメモリ(1.5 MB)にも入りそうですが、その後の画像追加のために SD カードから読み込みます。
Jpeg 画像の設定
PNG ファイルで保存する時には問題ありませんが、Jpeg ファイルで保存する場合の出力設定を残しておきます。
(LovyanGFX ライブラリの Jpeg 表示は、Progressive 画像に対応していないようです。)
まず、GIMP で出力する場合です。
赤く囲った「Progressive」部分のチェックを外します。

次に良く利用している画像表示ソフトの「IrfanView」です。
名前を付けて保存の、この部分のチェックを外してください。

動画の再生
LovyanGFX ライブラリを使って SD カード内の画像を連続して読み込んで、モアレ用の簡易動画を再生します。
今まで使ったことのある TFT 画面用のライブラリで画像ファイルを動画のように表示するためには、
・SD カードを読み込みモードにする。
・SD カード内の画像を用意したバッファに読み込む。
・読み込んだ画像をデコードする。
・TFT 画面を初期化する。
・データを TFT 画面に送る。
・次の画像を準備する。
といった面倒な処理が必要でした。
ところが、LovyanGFX なら SD カードの初期化後は、「lcd.drawPngFile(SD, “ファイル名.png”, 0, 0);」の1行だけで画像を表示できます!
なんと初心者にやさしい仕様なのでしょう。
こんな簡単なスケッチだけで、SD カード内に保存した画像を高速表示して、モアレ用の動画が再生できました。
(スケッチと同じフォルダに、前回作成した TFT 設定ファイル(GC9A01.hpp)を入れています。)
LovyanGFX を使い慣れた方なら、表示画像をスプライトに事前に読み込んで、さらに高速表示が出来ると思います。
#include <SdFat.h>
#include "GC9A01.hpp"
static LGFX lcd;
#define CS_PIN 2
SdFat SD;
void setup() {
lcd.init();
lcd.setRotation(0);
SD.begin(CS_PIN, SPI_FULL_SPEED);
}
void loop() {
lcd.drawPngFile(SD, "/Grey/10.png", 0, 0); //Greyスケール
lcd.drawPngFile(SD, "/Grey/20.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/30.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/40.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/50.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/60.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/70.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/80.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/90.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/100.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/110.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/120.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/130.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/140.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/150.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/160.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/170.png", 0, 0);
lcd.drawPngFile(SD, "/Grey/180.png", 0, 0);
}
あ、重要な注意点を忘れてました。
LovyanGFX のTFT ディスプレイ用の設定ファイルの内容を確認します。
SD カードを使用する設定になっていないとファイルを読み込むことが出来ません。
具体的には(今回なら GC9A01.hpp の)真ん中あたりの記載です。
「 cfg.pin_miso = 5; // MISOピン番号,SDカードと共通のSPIバスを使う場合、MISOは省略せず必ず設定」
こんな感じで MISO のピン番号を設定しないと SD カードの画像は読み込めません。
SD カードのテキストデータ読み書きはできるのに、画像データが読み込めなくて3日ほど悩みました。
何度スケッチの本体側でピン番号を指定しても、設定ファイル側が優先されるようですね。
(cfg.pin_miso = -1; になってました。)
実際の画像です。

静止画ではアニメーション具合が分からないので、等倍速の動画です。
カクカクすると思ったのですが、思ったよりもスムーズに回転して見えますね。
コミュニケータにはこの「動画」を採用します。
次回の予定
一番実現したかったモアレ画像の動画再生は、(最初は失敗しましたが)簡単に実現できました。
また、購入した SD カードが容量偽装されていて、久々に返品する手間もかかりました。
次回は、アンテナ部を開けたときに「きゅーきゅきゅ」とギミック音を鳴らす機能を追加します。
すでにバック・トゥ・ザ・フューチャーのデロリアンで DFPlayerMini で音楽の再生は出来ているので、簡単に実現できると良いのですが・・・




コメント