2台のサーモグラフィカメラ

LVGL の学習用に「黄色い基板」を AliExpress で購入したところ、1500円台という格安にもかかわらず意外と使えそうということがわかりました。

ただ運悪くハズレを引いたので、再度の技適ガチャは覚悟の上で「lvgl開発ボード」と謳われた品を 再手配 しました。またハズレた方は「国内の技適なしマイコン、特例届出を行いました」を参考に、「技適未取得機器を用いた実験等の特例制度」を申請中です。

ちょーどその頃、下記のようなお問い合わせを頂きました。そこで LVGL の学習は一旦脇に置き、CYD でも動くプログラムに再構成したので、ここに共有したいと思います

お問い合わせ

ハードウェア

2432S028R、通称 Cheap Yellow Display について

再手配した 2432S028R の背面
再手配した 2432S028R の背面

ラングシップさんの「黄色いESP32液晶ボードシリーズまとめ|Lang-ship」や「ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R)|Random Nerd Tutorials」が詳しく、大いに参考にさせてもらいました。

本章では、XIAO 版サーモグラフィカメラ の移植に必要な、I2C 接続とバッテリー駆動についての調査結果を報告します。

MLX90640 の I2C 接続

「拡張 I/O コネクタ」の P3CN1 のうち、3.3V と GND が来ている CN1 で I2C 接続が可能です。回路図では CN1 の3番ピンがどこにも接続されていませんが、基板のシルク印刷や下記情報により、IO22 に接続されていることが分かります。

下記図中のワイヤー色は、CYD に同梱された JST 1.25mm コネクタ付きワイヤーの色です。

コネクタ P3 のピン配
コネクタ P3 のピン配
コネクタ CN1 のピン配
コネクタ CN1 のピン配

上記「2. Wires - ADDONS.md」と今回作成のプログラムでは、I2C 用の SDASCL のピン設定を逆にしているので注意してください。ハード上の接続とソフト上の設定が合っていればどちらでも動作しますが、僕としては CYD 用ボードパッケージ ESP32-2432S028 CYD(後述)で読み込まれる pins_arduino.h に準拠した設定にすべきと考えています。

さて CN1 の2番ピン(IO27、今回 SDA に割り当て)は、内部的に 10KΩ でプルアップされていますが、3番ピン(IO22、今回 SCL に割り当て)はノーケアです。これらは外部から見れば I2C の要件に合致していないので、外付けでもプルアップすべきと思います。

実際には「プルアップ無し」でも動作することは確認しましたが、ソフトウェア編 でも触れた通り、SDASCL とも 1KΩ でプルアップすれば 信号の立ち上がりがシャープになります。

SCL 観測結果(プルアップなし)
SCL 観測結果(プルアップなし)
SCL 観測結果(プルアップあり)
SCL 観測結果(プルアップあり)
SCL/SDAを1KΩでプルアップ
SCL/SDAを1KΩでプルアップ

ちなみに、アナログ/デジタル入出力用と思われる P3 の1番ピンは、バックライト制御用の IO21 に接続されているため、 CN1 を I2C 用とした場合に使える GPIO は、両コネクタに共通の IO22 を除いた IO35 だけとなることを書き添えておきます。

ピン No CN1 P3
1 3.3V IO21 → バックライト制御用
2 IO27 → I2C SDA に割り当て IO22 → CN1 で I2C に割り当て
3 IO22 → I2C SCL に割り当て IO35 → デジタル入出力のみ可
4 GND GND

バッテリー駆動

CYD をカメラとして使うにはバッテリー駆動が必須ですよネ。ということで下記を参考に Li-Po と充電器を手配し、実験してみました。

Li-Po バッテリーの接続

コネクタ P1 / P5
コネクタ P1 / P5

バッテリーは、USB 端子横の(シリアル入出力と共通の)P1(旧バージョン)または P5(新バージョン)に接続可能です。回路図上の Q1 は P チャネルのパワー MOSFET で、逆接保護用と思われます。

試しに 3.7V の Li-Po を直に接続してみたところ、MLX90640 の出力にブロックノイズが乗ったような状態となりました。未確認ですが、I2C に十分な電圧が出力できていないためと思われます。

充放電統合/昇圧タイプ
充放電統合/昇圧タイプ

ということで、昇圧回路付き、かつ充放電統合タイプの充電器を AliExpress で探し、USB-C タイプとブレークアウト基板のタイプをそれぞれ1個づつ、お試して購入してみました(送料の方が高かったデス 😅

Amazon なら「バッテリー充放電統合モジュール」を商品検索すれば、類似品が出て来ると思います。動作は未確認なので、ご利用は自己責任でお願いします。

動作検証

ブレークアウト基板タイプは、USB のメスが手元になく給電が難しかったので、USB-C タイプで実験してみました。

購入した充電器には Vout 調整トリマが付いています。テスターで Vout を測ると 5.7V 出ていたので、時計ドライバーでトリマを調整し 5.0V に合わせる必要がありました。また Li-Po を接続する ±B 端子からは 4.2V が出ていることが確認できました。

Li-Po バッテリーの充電回路
Li-Po バッテリーの充電回路
動作検証の様子
動作検証の様子
TP4056 のサーモグラフ
TP4056 のサーモグラフ

次に発熱状況を調べるため、10分程度の動作後に作成したカメラで可視化してみました。カメラと対象との間に空気層があるため、実際の温度は表示温度よりもう少し高いと思いますが、問題は無さそうです(TP4056 動作温度:-40℃〜85℃)。

また Li-Po の充電が完了すると青色の LED が点灯しますが、負荷(CDY)をオンにしてしばらくすると赤色に変わったので、多少 Li-Po からの持ち出しが発生しているのかもしれません。

そこからさらに赤色のまま充電が完了しそうにない振る舞いが見られましたが、CYD をオフしてしばらくすると青色に戻りました。ちょっとした回路定数のバラつきが原因かもしれませんが、放電しながらの充電は出来ているようです。

パッケージングの課題

Li-Po 用の 5V 系充電器はどれも小さく、どうやってカメラとしてパッケージングするかが課題になると思います。加工が難しいですが、micro-USB と USB-C の両方付いた新しい基板なら、micro-USB の方をパターンカットし、ブレークアウト基板タイプの充電器を使うのがベストと思いますが、どうでしょう…

端子について

Li-Po バッテリーの異なる端子
Li-Po バッテリーの異なる端子

Li-Po バッテリーの端子は、それぞれの用途に応じて 1.25mm、PH (2mm)、XH (2.5mm) があるようですが、どれでも対応できるよう部品を持っておくのが吉と思います。

ソフトウエア

ソースコード一式を GitHub リポジトリ「embedded-kiddie/MLX90640」に上げました。現状はドキュメント(README.md)が未整備なので、インストール、設定、キャリブレーションの各方法について取り急ぎ解説したいと思います。

想定する環境は以下の通りです。

インストール

まず、コンパイルが可能になるまでの手順を示します。

Code → Download ZIP
Code → Download ZIP

1.リポジトリからコードをダウンロードし、解凍すると MLX90640-main というフォルダができるので、MLX90640 にリネーム後、ご自分のスケッチ用フォルダに移します。

他のボードとポートを選択
他のボードとポートを選択

2.MLX90640/MLX90640.ino を開き、Arduino IDE メニューの「他のボードとポートを選択」から ESP32-2432S028R CYD を選択、CYD が接続されたポートを設定します。

これにより、CYD 用の pins_arduino.h が読み込まれるようになります。

Tools の確認
Tools の確認

3.IDE のツールメニューから、Partition ShcemeUpload Speed を確認します。

パーティションは、タッチスクリーンのキャリブレーション結果を Flash に保存する場合、少なくとも2つが切られていることが必要ですが、コード中に埋め込むことも可能なので、必須ではありません。

またアップロードのボーレート 921600 は少し下げます。Mac や Linux では 460800、Windows では 512000board.txt に設定された適切な値と思います。

設定

続いて IDE で MLX90640.ino を開き、次のステップに従い構成を設定します。CYD の場合、Step 2. でカメラの向きを設定すれば、後はデフォルトのままで OK だと思います。

Step 1: デバッグ用シリアル出力の設定

不具合でも起きない限り、変更する必要ありません。

MLX90640.ino 10〜18行目
/*--------------------------------------------------------------------------------
 * Step 1: Configure serial output for debugging
 *--------------------------------------------------------------------------------*/
#define DEBUG false
#if     DEBUG
#define DBG_EXEC(x) x
#else
#define DBG_EXEC(x)
#endif

Step 2: 動作の設定

バイリニア補間、マルチタスクの設定はそのままで OK です。ENA_OUTWARD_CAMERA は、MLX90640 が内向き(自撮り)の場合は false を、外向きの場合は true を設定します。

MLX90640.ino 20〜25行目
/*--------------------------------------------------------------------------------
 * Step 2: Configure operational settings
 *--------------------------------------------------------------------------------*/
#define ENA_INTERPOLATION   true  // Enable interpolation
#define ENA_MULTITASKING    true  // Enable multi-task by FreeRTOS
#define ENA_OUTWARD_CAMERA  false // Camera orientation (true: Outward, false: Selfie)

Step 3: グラフィックスライブラリの設定

CYD では LovyanGFX のみ有効としているので、そのままで OK です。新旧どちらの CYD でも LovyanGFX の自動設定を有効にしています。

MLX90640.ino 27〜49行目
/*--------------------------------------------------------------------------------
 * Step 3: Select GFX Library
 *--------------------------------------------------------------------------------*/
#if   1
#define USE_LOVYAN_GFX
/*--------------------------------------------------------------------------------
 * LovyanGFX
 * Note: Currently 'AUTODETECT' only works for 'ESP32 2432S028R'.
 * For other boards you need to configure appropriately to fit your device.
 * See https://github.com/lovyan03/LovyanGFX/blob/master/src/lgfx/boards.hpp
 *--------------------------------------------------------------------------------*/
#define USE_AUTODETECT  true

#else
#define USE_TFT_ESPI
/*--------------------------------------------------------------------------------
 * TFT_eSPI
 * It does not allow the display and touch screen to be on different SPI buses.
 *--------------------------------------------------------------------------------*/
#ifdef ARDUINO_ESP32_2432S028R
#error Not yet supported  // CYD needs XPT2046_Touchscreen library
#endif
#endif
ご参考

TFT_eSPI のタッチ機能が使えず XPT2046_Touchscreen が必要になる理由です。

Step 4: キャリブレーション用データの保存先設定

本プログラムでは、タッチスクリーンのキャリブレーション用データの保存に Preferences を利用し Flash に保存するオプションを用意しています。キャリブレーション時に再コンパイルが不要な true を推奨しますが、デフォルトは false としています。

MLX90640.ino 51〜55行目
/*--------------------------------------------------------------------------------
 * Step 4: Configure flash memory setting to save touch calibration data
 *--------------------------------------------------------------------------------*/
#define USE_PREFERENCES false

Step 5: 解像度の設定

性能の低い CPU 向けの設定なので、CYD ではデフォルトのままで OK です。

MLX90640.ino 57〜68行目
/*--------------------------------------------------------------------------------
 * Step 5: Configure resolution settings
 *--------------------------------------------------------------------------------*/
#if ENA_INTERPOLATION
#define INTERPOLATE_SCALE 8
#define BOX_SIZE          1
#define REFRESH_RATE      (ENA_MULTITASKING ? MLX90640_32_HZ : MLX90640_16_HZ)
#else
#define INTERPOLATE_SCALE 1
#define BOX_SIZE          8
#define REFRESH_RATE      (ENA_MULTITASKING ? MLX90640_32_HZ : MLX90640_16_HZ)
#endif

タッチスクリーンのキャリブレーション

Step 4. で USE_PREFERENCESfalse に設定した場合の埋め込み方法を説明します。true に設定した場合は埋め込みデータは無視されるので、単にキャリブレーションを実行するだけで OK です。

キャリブレーションの実行
キャリブレーションの実行

1.コンパイル&アップロード後にプログラムが起動すると、タッチスクリーンのキャリブレーション画面に移るので、矢印をタッチする前にシリアルモニターを開いてください。ボーレートは 115200 です。

2.四隅を順にタッチすると、シリアルモニターに以下のようなテキストが出力されるので、選択してコピーします。

// LovyanGFX
.cal = { 303, 3765, 311, 179, 3808, 3757, 3764, 196 },

3.IDE から touch.hpp を開き、コピーしたテキストを該当箇所に上書きでペーストします。再コンパイル後は、キャリブレーションは実行されず、通常のカメラ機能が起動します。

touch.hpp 25〜48行目
/*--------------------------------------------------------------------------------
 * Touch panel calibration parameters
 * When 'USE_PREFERENCES' is 'false', the calibration result must be embedded.
 *--------------------------------------------------------------------------------*/
TouchConfig_t tch_cnf = {
#if   defined (LOVYANGFX_HPP_)

  // LovyanGFX
  .cal = { 0, 0, 0, 0, 0, 0, 0, 0 },

#elif defined (_XPT2046_Touchscreen_h_)

  // XPT2046_Touchscreen
  .cal = { 0, 0, 0, 0, 0, },

#else

  // TFT_eSPI
  .cal = { 0, 0, 0, 0, 0, },

#endif

  .offset = { 0, },
};

以上です。お疲れ様でした 🙂

Tips

ドキュメントの整備はボチボチ進めていきますが、ここでは幾つか Tips を紹介しておきます。

I2C の不具合

I2C のエラー

I2C でエラーが発生すると、画面に Failed が表示されます。この場合、ハード的な接続か、ピン配を再確認してください。

特に SDASCL を逆に設定すると、Failed の表示と共にリブートし続ける事象にハマります。この場合は一旦電源を切り、Boot ボタンを押しながら電源を入れ直し、正しく設定したスケッチを再アップロードしてください。

メインスクリーンのタッチ動作

幾つかのウィジェット領域
幾つかのウィジェット領域

画面は、特定の領域を占める幾つかのウィジェットで構成されていて、それぞれクリック時の機能が決まっています。

ここでは2つの機能について補足的な説明をします。

特定点のサンプリング

「A」の領域をクリックすると、クリック地点の温度を表示します。数秒のウィンドー幅を持つ移動平均的なフィルターが適用されるので、安定するまで待ってください。また表示を消す場合は、領域「B」をクリックします。

サーモグラフィ画面へのショートカット

領域「C」をクリックすると、表示温度の設定画面にショートカットします。

ファイルマネージャー画面でのビデオ再生

表示の色合い(Rainbow/Inferno)や温度範囲は、サーモグラフィ画面の設定が適用されます。

起動時のデフォルト設定を変更する

自由度は少ないですが、以下のコードを直接編集することで、幾つか変更が可能です。

mlx.hpp 85〜94行
constexpr MLXConfig_t mlx_ini = {
  .interpolation  = INTERPOLATE_SCALE,  // 1, 2, 4, 6, 8
  .box_size       = BOX_SIZE,           // 1, 2, 4, 8
  .refresh_rate   = REFRESH_RATE,       // sampline frequency (32Hz, 16Hz, 8Hz, 4Hz, 2Hz)
  .color_scheme   = 0,                  // 0: rainbow, 1: inferno
  .marker_mode    = 0,                  // 0: off, 1: min/max, 2: picked up by user
  .range_auto     = false,              // automatic measurement of temperature min/max
  .range_min      = MINTEMP,            // minimum temperature (20 deg)
  .range_max      = MAXTEMP,            // maximum temperature (35 deg)
};

実は…

冒頭の写真にあるように、画角 110°の近距離用(MLX90640 BAA)と画角 55°の中距離用(MLX90640 BAB)の2つの MLX90640 を持っています。

中距離用は、室内の温度分布とかを可視化しています。床付近と天井とでは 2℃〜 4℃ ほども違うことがあり、エアコンの風向きを変えたりサーキュレーターで循環させたりと、暖房効率の向上に一役買ってます :snowman_with_snow:

さて本件関連の今後ですが、MLX90640Viewer の使い勝手が悪いので、Processing のプログラミングで GUI の改善をユルユルと進めようかと思っているところです :fish_cake: