M5Paperの電子ペーパー、表面の触りごごち良すぎて無駄に触っちゃいませんか?
用もなく触ってたらサイズ的にトラックパッドに見えてきたのでBLEマウスにして遊んでみます。
キーボードと並べるとやたらおさまりがいいですね!
タッチの検出
まずはタッチの検出です。
M5Stackのドキュメントによると、2点のタッチが検出できるようです。
The display is a GT911 capacitive touch screen,which supports two point touch and a variety of gesture controls .
M5EPDのサンプルスケッチTOUCH.ino
を参考にタッチされたポイントの数をシリアルポートに出力させてみました。
GT911::update()
でレジスタを読んでメンバの更新を行うスタイルですね。GT911::isFingerUp()
は一度コールするとフラグが落ちる実装になっていましたので連続してコールする場合は注意です。
ちなみにサンプルのスケッチはif(!M5.TP.isFingerUp())
時のみGT911::update()
をコールしてますが、これだとタッチ状態変化後に1回誤検出をしちゃう気がするんですけど、どうなんでしょう・・?
タッチジェスチャの判定
タッチジェスチャを判定します。
スワイプ(タッチしたまま移動)、タップ(短押し)、ドラッグ(一度単押ししてすぐスワイプ動作)、ダブルタップ(短押し2回)の状態変化を図にしてみました。
一定時間状態変化がなかった時(図中✅)にジェスチャが確定しています。
変化した履歴を保存しておけば実現できそうですね。
ちょっとコードが長めですが判定自体は単純です。
タッチ座標の取得
タッチしている指の情報は下記のメソッドか、readFinger(uint8_t num)
を使ってtp_finger_t
構造体で一気に取得できます。
uint16_t readFingerX(uint8_t num); uint16_t readFingerY(uint8_t num); uint16_t readFingerID(uint8_t num); uint16_t readFingerSize(uint8_t num);
これをタッチの検出のサンプルと同様に、M5.TP.isFingerUp() == false
の時に取得すればOKです。
表示される座標を見る限り、RotationがデフォルトだとUSB端子を右側にして置いた状態のようですね。
BLEマウス
BLEマウスのライブラリは ESP32-BLE-Mouse
を利用します。
このライブラリも非常にわかりやすいです。
BleMouse
のインスタンスを生成してsetup()
(じゃなくてもいいけど)でbegin()
をして、click()
move()
press()
release()
をコールしてマウスの動きをPCへ送信できます。
デバイス名やManufacturerはコンストラクタで設定できます。デフォルトのデバイス名はESP32 Bluetooth Mouse
ですね。begin()さえコールすればデバイス一覧に出てくるはずです。
ノイズ対策
今まで実験したことを組み合わせればトラックパッドになるはず!と思ってBleMouseのインスタンスを生成して実装していたらどうにも動きがおかしい。
具体的な現象としては、タップし続けているのにたまにアップ状態になってドラッグが途切れてしまいます。色々実験しているとBleMouseのbegin()を呼ぶとM5.TP.avaliable()が不正にtrueになっていることがわかりました。
そうなると不用意にupdate()してしまうわけで、変な値が取得されてしまうのも納得ですね。
#include <M5EPD.h> #include <BleMouse.h> BleMouse bleMouse; void setup() { M5.begin(); bleMouse.begin(); // ← このメソッドの有無で挙動が変わる・・ } void loop() { if (!M5.TP.avaliable()) { return; } M5.TP.update(); if (!M5.TP.isFingerUp()) { Serial.println("down"); } else { Serial.println("up"); } }
納得したところでどうにもならないので、思い切ってチャタリング除去みたいな読み捨て処理で誤魔化すか?と思っていたところまたも救いの手が。ありがたい・・
失礼します、ESP32の既知の問題に「無線を使うとGPIO36,39にパルスノイズが発生する」というのがありまして。M5PaperはGPIO36がタッチパネルのINTピンに接続されていますので、おそらくですがこれで解決できるかも…です。https://t.co/o0QeiskVXA
— らびやん (@lovyan03) 2021年9月29日
無線を有効にするとGPIO36と39に余計なパルスが入るそうです。
GT911のbeginを見るとバッチリGPIO36を使ってますね。第3引数はavaliable()がtrueになるフラグをセットする割り込みのポートですね。思いっきり現象どおりでした。
if(TP.begin(21, 22, 36) != ESP_OK) { log_e("Touch pad initialization failed."); }
というわけで、setup()
でadc_power_acquire();
をコールしてADCを有効にします。それだけで期待通りの動作になりました。よかった・・。
完成!
さて、今までの成果を組み合わせてどうにかこうにか完成しました。
スワイプ、タップ、ドラッグ、タブルタップ、ホイール全ての想定したジェスチャが実現できました。
M5Paper触り心地がいいしちょうど良いサイズなのでトラックパッドになるのでは?と思ってやってみた
— イナバ (@hollyhockberry) 2021年9月24日
二本指タップの動作もちゃんと動作してるけど、全体的にカクカクしてるのは何でだろ‥?
ちなみに給電しながら使うと指先が熱すぎて常用はつらそうでした😅 #M5Stack #M5Paper pic.twitter.com/UAxN9um69T
実はこの動画はちょっと前に作ったバージョンで、ちゃんとデバッグしてないのでGPIO36のノイズの影響に気づいていない状態ですね。
見た目同じ感じなので動画上げ直すのを横着しちゃいました。