先日ESP32×2台&Wi-Fi機能を使用してボイスメールガジェットを作りました。
自機のマイクで10秒以内の音声を録音し、サーバー経由で相手のESP32に通知を飛ばす。着信は昔のガラケーのようにLEDで相手の音声の有り無しが分かるようになっており、基本的には1回(制限時間以内であればもう一度だけ)再生可能としました。
今回はChatGPTのプログラミングコード生成特化AIであるCodexを駆使して電子工作を行いましたが、Wi-Fiとも連携しかなり複雑な機能にはなったものの満足行く仕上がりになりました。
作った目的
仕事で培ったスキルを定着させたかった(フローチャート&状態遷移)
今いる現場がフローチャートと状態遷移をひたすら書かせる現場で、自分自身この開発環境を気に入っています。大抵の現場はプログラム設計書を日本語で書いたりしますが、日本語で設計するよりもフローチャートや状態遷移を書いたほうがレビューを受けるときに圧倒的に周りに理解してもらえます。
またフローチャートや状態遷移も設計の段階からソースレベルで書いてしまえば、設計書のレビュー後にわざわざコードレビューをする必要がありません。昨今のAIの発達により設計書からコードへの置き換えミスは割と簡単に発見できるようになったので、フローチャートや状態遷移をしっかり書くのは良い慣習だなと思っています。
そこで現場で培ったスキルをさらに定着、飛躍させるために自分自身で何か工作をしてみたいと思ったのです。
OTA(遠隔ソフトウェアアップデート)
OTA(Over The Air/遠隔ソフトウェアアップデート)は今組み込み業界ではトレンドになっている技術です。
Webと常に接続されているWebサービスならまだしも、一度売ってしまうと組み込み系(家電)はソフトウェアアップデートが非常に困難です。ところが昨今の技術の進歩もあり、家電も多くの製品がインターネット接続機能を搭載するようになっています。
OTAはこれからの家電で確実に標準搭載となってくるので、その仕組を自分自身で早く体験したかったのです。
Codexを試してみたかった
ChatGPTの一サービスであり、プログラミング特化型AIであるCodex。
今までもプログラミングコード自体はChatGPTでも出力できていましたが、Codexの場合は今まで以上にプログラミングに関する機能が充実しているとのこと。
自分も一介のエンジニアということでCodexの威力を試してみることにしました。
やったこと
まずは仕様を作る
これは電子工作をやるときに毎回行うことですが、まずは自分のやりたいことをメモ帳でもなんでも簡単に箇条書きでリストアップしていきます。そこから企画書的に一枚絵でやりたいことを決めていきます。なるべくワクワクするような資料を作ることがポイントで、一旦は自分ができるかどうかはおいておきます。やれるかやれないかは後でChatGPTと相談すればよいのですから、まずはやりたいことを書けばよいのです。
そして出来上がったのが以下の企画書。
ボイスメールガジェットということで、お互いに自分の音声を送り合うわけですが、送り合うと言っても直接お互いのESP32にデータを飛ばせるわけではありません。音声を録音したら一旦はお互いサーバーに音声をアップロードして、それをお互いダウンロードするシステムにするほか無いのです。
ChatGPT(Codex)に相談してサーバーはどこが良いか聞いてみたところ、初めは「ブログでも使っているConohaWingが良いのでは?」となりました。自身でブログの管理で既に使っているので追加料金なしで行けそうというのもポイントでした。
しかし開発を進めていく中で自分の録音した音声を全世界に公開してしまうことになることに気づいて取りやめに。もちろんConohaWingでもセキュリティをかければアクセスキーを持っている人のみ聞けるように出来るわけですが、それは技術的になかなかハードルが高そうなので断念しました。
再度ChatGPTに相談したところFirebaseにすればよいのでは? という話になり、結局はFirebaseを使用することにしました。
Firebaseは以前少しだけ使用したことがあり、多少勝手は分かっていましたが、とはいえボイスメールガジェットを作るうえではどのように使っていけばよいか分かっていなかったので、まずは以下の通り最終的にやりたい機能をブレイクダウンして、単機能で動きを確認していくことにしました。
- 録音
- 再生
- 音声データのFirebaseアップロード
- 音声データのFirebaseダウンロード
- OTA(遠隔ソフトウェアアップデート)
LED点灯や液晶表示は既に試したことがあるので割愛。今までやったことのない機能を単体で動かしてみて、仕組みを理解します。
自分一人でやる電子工作のポイントは、最初は小分けに機能を作って動きを試していき、問題なければ結合させることです。
完成版の機能
使用したセンサ/アクチュエータ
- ESP32 Dev Module
- マイク(MAX4466)
- OLED液晶 128X32px
- 押しボタンスイッチ
- スピーカー用アンプ(LM386)
- スピーカー
- LEDランプ
基本的な機能
- ボタン操作
- ボタン2回押下で相手音声再生
- 基本的に1回のみ再生可能
- 60秒以内であれば再度再生可能(この場合以後の再生は不可)
- ボタン1秒押下で自分の音声再生
- ボタン3秒押下で自分の音声録音
- 録音開始時:スピーカーからピピッとビープ音
- 録音終了時:スピーカーからピーッとビープ音
- ボタン6秒押下で自分の音声削除
- ボタン2回押下で相手音声再生
- 液晶表示
- ESP32起動時に現在のソフトウェアバージョンを表示
- 相手のESP32がネット接続されているか
- 相手の音声がサーバーに存在するか(ボイスメールの着信があるか)
- 再生中、録音中、サーバーアップロード中などの状態表示
- その他機能
- 犬/猫アイコンによる機種の識別
- LEDランプによる相手音声の着信通知
- スリープ機能による省電力化
- 60秒に1回のウェイクアップで相手音声の存在有無を確認
- ESP32起動時のOTAによるソフトウェアアップデート確認
つまづいたところと解決策
音声をどうやって保存するか
自分が録音した音声をどこかに保存しなくてはいけません。
10秒という短い音声ではあるもののESP32と親和性の高い拡張子である.wavで320KBになります。あとでサーバーにアップロードするので自分で保持し続けなくてもよいとはいえ、一旦はバッファとしてデータを持たなくてはなりません。可能であれば不揮発領域に保存したいものの、EPS32の不揮発は数KBしかない。
どうしたものかとCodexに相談するとESP32はLittleFSという1MBの不揮発領域があり、そちらを使えば録音した音声データを不揮発に記録することが出来るのということで、こちらを使用することにしました。
音がノイズだらけ Part.1
MAX4466というアナログコンデンサマイクを使用して自分の音声を録音するのは良いのですが、録音したものを聴いてみるとまるでプライバシー保護のために音を異常に低くしているかのような、モザイク音声となっていました。
原因はと言うと、アナログマイクからAD変換で16bitデータに変換したあとで不揮発への保存が間に合っておらず、途中処理負荷オーバーを起こしていたのが原因でした。
ここはCPUの処理不可を下げるために、CPUとは別枠で処理を行えるDMAを通信を使うことにしました。
DMA通信を使うと
- AD変換:DMA通信が実施
- 不揮発保存:CPUが実施
と、AD変換処理はDMAがやってくれるようになり、処理負荷が大幅に低減。
無事に正しく音声を不揮発にも保存できるようになりました。
音がノイズだらけ Part.2
音声の録音を単体で試している時は問題ありませんでしたが、他にスピーカーや小型液晶ディスプレイ、LEDも結合させると音に「ジーッ」というノイズが乗るようになりました。
ChatGPTにアドバイスを求め、言われるがままにコンデンサを追加するものの、多少ノイズは低減した感じはしますが、まだまだノイズは気になります。
そこでひとつづつアクチュエーターを外して音声を録音してみると液晶ディスプレイを外したときにノイズがなくなることを発見。原因はディスプレイが発するノイズが共有している電源ラインから回り込んでマイクに入り込んでしまっていたようなのです。
ただ今使用している3.3V電源はひとつしかなく、マイクと液晶で電源を分けることは出来ません。そこで苦肉の策として「マイクで録音中はディスプレイの電源をOFFにする」という方法を取りました。
スリープ復帰後にしばらくボタン操作が不可になる
このボイスメールガジェットは基本的に常時動かしたいものではあります。とはいえ常時フル稼働させると消費電力が大変なことになるので、必要なとき以外はスリープにより機能を無効化させておきます。
ところがスリープから復帰した直後、ボタン操作がしばらく効かないのです。たまに効くときもあるものの、8割の確率でスリープ復帰後5秒ほどはボタン操作が無効化されてしまいます。
考えても埒が明かないので、ChatGPT(Codex)に指示を出し、プログラムに片っ端からデバッグコードを突っ込んで、処理がどこまで到達したかを液晶とログに出力するようにしたのです。
すると原因はスリープ復帰後にWi-Fi接続にトライしていたため、簡易的なデッドロックが発生していたのです。
ESP32とWi-Fiはどうやら相性の問題があるらしく、スリープ復帰後で即座にWi-Fi接続が成功すれば問題ないのですが、接続に失敗する時はとことん失敗する。そのせいでスリープ復帰後しばらく他の動作が受け付けないようになっていたのです。
そこでプログラムを改良し、ボタン操作を何よりも優先度高く設定し、Wi-Fi接続はいわゆるアイドル状態の何もしていないときにトライするように修正しました。
機能のこだわり
OTAによる自動アップデート機能
これは当初から企画していたことですが、実際にOTAをどう実施するかは悩みどころでした。
当初はボタンの長押しで「OTAモード」に入ってそこからアップデートを実施するかなど、色々考えたのですが、結局は「Firebaseにファームウェアを置いておいて、マイコン起動時にファームウェアの存在有無を確認。そのファイル名が現在自機に書き込まれているソフトウェア品番と異なればアップデート実施」としました。
我ながらこれが非常に便利でして。ファームウェアをFirebaseに置いておくだけで勝手にアップデートが走るわけですから。
LEDランプによる着信機能
液晶ディスプレイにも相手から音声が届いているかどうか表示させているので、わざわざLEDランプによる着信通知をする必要はないように思えますが、僕はこれを割と重視していたんですよね。
というのも夜家に帰って部屋が真っ暗になっている中、相手からの着信があって、LEDランプだけがフワァと光ってるのっていいじゃないですか。
自分が高校生の時はまだガラケーで、あのときってLEDランプがどの携帯にも搭載されていたんですよね。それで着信があるとLEDランプが光ったわけですが、あの「着信が入っていることで光るLEDランプ」をこのガジェットでも再現したかったのです。
LEDランプの調光機能
現状LEDランプは点灯/消灯の二種類なのでデジタルアウトプットポートにつなげばよいのですが、ここはあえてPWM制御を行うことにしました。
というのもLEDが思ったよりも眩しくて、明るさを後から調節できるようにしたかったのと、一旦PWMポートに繋いでおけばあとからソフトウェアアップデートでこの辺の制御も変えられるからなと思ったからです。
OTAのお陰で、実機を持ってこなくてもFirebaseにソフトを置くだけでアップデートできますからね。
完成してみて勉強になったところ
DMA通信の制御方法が分かった
今回一番の収穫じゃないですかね。
もちろんDMA通信の存在は知っていましたが、現場で実際に使う機会もなく、また巷でDMA通信の制御方法を学ぶ術もありませんでした。
ところがAIを使えば簡単に制御を織り込んでくれますし、その内容についてもいくらでも深堀りして解説してくれるので、今回でDMAがどういうものか非常によく理解できました。
LittleFSの制御方法が分かった
ESP32に1MBもの不揮発領域があるとは知りませんでしたし、またそれも非常に簡単に制御できるとは思いもよりませんでした。
ほんとこういった制御技術ってAIがなかったら知らないし、知っていたとしてもうまくコントロールできないですよね。
ノイズは割と簡単に乗る
ノイズって簡単に乗るんですね。
現場でマイコンを扱う時はハード屋さんが既にノイズ対策をしたものを使うので、あまりノイズを意識したことはありませんが、こうやって自分で電子工作をすると「こういう事が起きるから、現場ではこういう運用になっているんだ!!」と気付かされることが多いです。
今回ノイズ対策でコンデンサの役割や、ジャンパ線のツイストなど、いろいろな方法を試し、その中で学ぶことがかなりありました。
Codexの威力を思い知ることが出来た
いや~Codexはすごいですね。ほんとにちょっと指示を出すだけでちゃんとしたシステムを作り上げてしまうし、一旦出来上がったプログラムもリファクタリングの指示を出せば自分自身ですべてコードを書き換えてしまうんですから。Web屋さんがしきりに「AIのおかげでエンジニアの仕事は減少する!」と言うだけの理由は分かった気がします。
今回のシステムを作るのにトータルで40時間ぐらいかかった気はしますが、もしこれをAIなしで作ろうと思ったら1年400時間はかかったと思います。
とはいえ、じゃあAIがエンジニアの仕事をすべて奪うかと言えばそうでもないかなぁと思います。
そもそも僕が今回Codexを使いこなせたのも、コーディングをする前の仕様や設計をキッチリと決めていたからで、そこが曖昧だとどうにもならんと思うんですよね。
自分で電子工作を作ったり、世の中に既にある機能を理解するためにAIを使用するのは非常に効果的ではあるものの、やはりどこにバグが埋め込まれる可能性があるか分からないAIではエンジニアの仕事を完全に代替するのは難しいかなぁと思います。
今回電子工作を作って改めて思ったのですが、やはり自分の手でシステムをひとつ作り上げるというのは非常に勉強になりますね。
大容量データをどのように不揮発に保存するであるとか、どうやってCPUの処理負荷を下げるのか、マイクにノイズが乗ってしまうのをどうするかなど、もちろんAIの手を借りながらですが自分の頭で考えて、ひとつずつ対処するのはとても楽しかったです。
何よりも自分のスキルが伸びた実感があるのが一番ですね!
