KindleとESP32を使って高機能ディスプレイオーディオを作ろうとした

私の車は今まで中華Android搭載カーナビを入れて使っていたのですが、最近タッチパネルが全く反応しなくなり（操作するときはグローブボックスに入れているマウスでやってます）、新しくしたくなりました。
といっても最近はBluetoothオーディオ再生機としてしか使っていなかったので、適当なBluetooth対応オーディオデッキを入れても良かったのですが、それだとちょっと寂しいなと。
個人的に、Tesla Model 3みたいに、大きめディスプレイにいろいろな情報を（かっこよく）表示させて近未来的な感じにしたいと思っていました。
![](https://tesla-cdn.thron.com/delivery/public/image/tesla/d4f29128-35ad-4912-9282-32701225c77b/bvlatuR/std/1920x1080/lhd-interior-hero-desktop)

で、いろいろ考えた結果、余っているAndroid端末、ESP32、温度センサなどを使ってディスプレイオーディオ的なものを作ることにしました！！
## 構成
こんな感じです。
![Main - 3ページ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/a11fb7eb-af80-916d-35e0-d53001bd95cd.png)

結構複雑ですね。。。

### ディスプレイ（Android端末）
Android端末です。
キーオンで電源オン、ESP32にWiFiで接続します。

#### 自作Androidアプリ
![d37326b7a86b6891.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/1087fadd-1229-ab88-595b-da0339dc441d.png)
ディスプレイ用Android端末で動かすアプリです。
自動起動するよう設定します。


機能としては、
- Mapboxを用いて現在地地図を表示（経路案内は必要ないので実装しない）
- 時計表示
- 車側モジュールから受け取った環境情報を表示
    - 車内温度
    - 車外温度
    - GPS測位状況
- 車側モジュールから受け取った再生している曲の情報を表示
- 音楽再生の操作ボタンによって、車側モジュールに対して再生制御コマンドを送信
- 各種設定（車側モジュールのIPアドレス、TCPポート番号など）

### 車側モジュール
![041ee9babfe89d1d.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/37975bfe-3cae-c304-51c6-5e9ff9fa28e0.jpeg)

#### ESP-WROOM-32
ESP32のボードです。
こいつが結構仕事が多いんですが、
- WiFiアクセスポイント（ホスト）
- 車内外温度センサーからの環境情報（車内外気温、車内湿度、車内気圧）をTCPでAndroidのアプリへ送信
- Bluetooth A2DP Sinkとして手持ちスマホ（ディスプレイではない）と接続し、音声をI2Sを通じてDACへ送り、車のスピーカーを鳴らす
- A2DP再生をしている際、AVRCPを通して曲の情報を受取り、Androidのアプリへ送信
- A2DP再生をしている際、AndroidアプリからTCPで受け取った再生制御コマンド（再生、停止、前の曲、次の曲）を解釈してAVRCPを通して手持ちスマホの再生をコントロール

#### 車内外温度センサ
車外用にはOneWire接続の[DS1820搭載防水温度センサ](https://www.aliexpress.com/item/4000591195642.html)、車内用はI2C接続のBME280を使っています。
BME280は気温だけでなく、湿度や気圧まで測ることが出来るので、これらもついでにアプリに表示出来るようにします

#### I2S DAC
ESP32にも内蔵DACはありますが、分解能が8bitですし、実際にイヤホンをつないで聞いてみると結構ノイズが多かった（WiFiとBluetoothを同時に動かしながらだから仕方ないと思われる）ので、別に16bitのステレオDACを用意することにし、I2Sという通信方式でデジタルデータを送る形にしました。

## 誤算
今回は家で眠っていたKindle Fire 7（2017）をディスプレイとして利用しようと思っておりました。
ですが、この端末はGPSを内蔵していないということに後で気づき、頭を抱えましたw

GPS搭載のタブレットを買うというのもアリだったんですが、流石に1万円は超えてしまうなーと思い、できるだけ安く作りたかったので回りくどい方法を取りました。

[GPSモジュール(NEO6M)](https://www.amazon.co.jp/dp/B01D1D0F5M)を利用することにしました。

ESP32へUARTを通してNMEAを受け取り、ESP32がそれを端末へTCPで垂れ流します。

[NMEA](https://www.hiramine.com/physicalcomputing/general/gps_nmeaformat.html)というのは、この手のシリアル通信のGPSモジュールが吐き出すテキストベースのフォーマットで、
緯度や経度、標高だけでなく、設定によっては測位衛星数などの細かい情報まで取得することができます。

後は端末側でNMEAから緯度、経度、移動方位、移動速度、標高など必要な情報をパースしてマップに渡したり表示したりするわけですね。

![IMG_20210815_170452.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/205cae97-eb48-0fb0-5fd9-9bb64a1732a4.jpeg)
（画像左上の基盤と四角いやつがGPSモジュールとアンテナ）

またESP32の仕事が増えてしまいましたが、致し方無いですね...

## 実装
意外とサクサクと実装できましたが、いくつか躓いたポイントがありました。

### ESP32のメモリ不足
ESP32が担う仕事が多すぎて、コードもデカくなってしまって（特に[ESP32-A2DP](https://github.com/pschatzmann/ESP32-A2DP)がでかい)書き込みできない問題が発生しました。

問題は、書き込み時にパーティションの設定を変えることでどうにか解消しました。
https://asukiaaa.blogspot.com/2019/03/esp32-wroom032ota.html
どのパーティション設定を利用したかは失念してしまったのですが、パーティション設定を変えてユーザー領域を多くすることによってコードはすべて書き込めたという形になります。

### 基板実装
ユニバーサル基板上に部品を配置して、エナメル線orスズメッキ線で配線をしています。
流石に部品が多く配線も多い上に基盤1枚に収めたかったので、事前にちゃんと配線取り回しを考えてから実装しました。

![IMG_20210815_170516.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/449dd5b7-9cad-8f07-15f6-274783a7b804.jpeg)

2DINスペースの下側にALPINEの1DINオーディオを取り付けて、その上の1DINスペースにモジュールを置きたかったので、ショート防止の為にコチュジャンの入っていたタッパーにUSBケーブル用の溝だけ空けて置きました。力技ですが、見えない所なので問題ないでしょう。

### Kindle固定
最も苦労したかもしれません。
Fusion360と3Dプリンターを使用してチルト・取り外し可能なマウントを作りました。
Kindle側はケースを外して裏から皿ねじを使ってステーを固定するという力技を発揮して固定し、車両側は2DINのステーにホムセンL字金具と3Dプリンタで印刷したチルト機能付き差し込み部品を使って固定してます。
Kindleを差し込んで、上から適当な釘で閂（かんぬき）を刺すことで固定する手筈でした。

![IMG_20210815_195423.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/93e67c10-ebed-1e63-37a5-a7812771aae8.jpeg)

実際はチルト部分はモーメントに耐えられず水平にしか固定できず、閂を刺すために指を入れるスペースもほとんど取れなかった（シフトレバーへの干渉を恐れてKindleをダッシュボード側に近いかたちで設計したため）ので、まあ固定はできたのですがうまくいったとは言えませんでした...

（そして固定した状態の写真も見つからなかった...）


## 結果
![IMG_20211231_165922.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108489/e0002733-d6ac-3b31-0a3e-5a01c1d88d68.jpeg)
見た目はいい感じになりました。
チルト機能と脱着機構は犠牲にしましたが、一応固定はできています。

### 動作
- GPS測位について
一応問題なく測位できていました。
何度か取り外して家に持ち帰って修正をしていると、GPS測位ができなくなることもありましたが、接触不良か、GPSアンテナ位置の問題な気もします。

- Bluetoothについて
音楽再生は問題なくできました。
極稀にESP32の動作すべてが落ちることもありましたが、頻度はだいぶ低いので一応見て見ぬふりをしています。RAM使用量の問題かもと思っています。

- TCPでのタブレットとの通信
最初は問題ないのですが、しばらく動かしていると反応がなくなってしまうのでコネクションが切れているようです。
ちゃんと検証できていないですが、TCPコネクションの確認の為に数秒ごとにハートビートを送って、コネクションが切れていたら再接続を行う機能を実装する必要があると考えています。

開発途中でバグが多かったのですが、このあたりで本格的に卒業研究が始まってしまい、卒業研究が終わったあと引っ越す頃には愛車ジムニーを手放す（実家に保留中）することになってしまったのでこれらのバグ修正はできずに終わってしまいました😢

## 学びを得た
完成までできず大変悔しいですが、いろいろと学びました。
- Androidアプリ開発
今までも開発はしたことがありましたが、MapBox、別スレッドでのTCP通信、設定画面の実装などのノウハウを学ぶことができました。Kotlinにもだいぶ慣れてきました。

- ESP32での開発
ESP8266での開発は経験がありましたが、Bluetooth機能を使えるESP32での開発は初めてだったので大変勉強になりました。

- TCP通信
オーバーヘッドの大きなHTTPではなくTCPをそのまま用いて簡単なテキストメッセージフォーマットを決めて実装し、通信は成功したのですが、コネクションがよく途切れること、そしてそれをAndroid側で検知できなかったことからコネクションの生存確認の必要性を感じました。

- 記録は大事
ちゃんと日記というか、記事にまとめながら作るのは重要だと感じました。。。

## 今後
車は手放しましたが、東京に引っ越してからもオートバイには乗っていますので、いろいろと落ち着いてから開発を再開したいと思っています。
オートバイになれば音楽再生と車内温度の計測は不必要になり、タブレットは大きすぎるのでディスプレイをスマホに変更することになればGPSモジュールも（おそらく）必要なくなります。
一方、オートバイならばGPSログ機能やジャイロセンサでの斜度計なんかも欲しくなるなーと妄想をしています。

*次こそはちゃんと逐一Qiitaに記事をあげようと思います。。。*