今回は、1年以上前の作品について、ちょっとブラッシュアップした話です。
機能改善したのは ↓ の記事にある、ソフトウェアレーザポインタです。
前回の状態
↓ の動画の状態ですね。
これは赤い自作基板ですが、今回は2つバージョンが上の青い自作基板で実装しました。
変更点
1つ目の変更点として、基板を更新したことでピン配置が昔と変わっており、動作確認からコードの修正を行いました。そして、ポインタの動作方法について更新しました。
前者は生地にすることが無いので、今回は後者のポインタの動作方法について紹介したいと思います。
前回の動作方法と更新後の動作方法
前回は、初期姿勢を基準として、Roll角とPitch角の変位をそのままマウスカーソルの移動速度に反映していました。そのため、カーソルの移動を止めるためには、ポインタを正確に元の角度に保つ必要がありました。持ち方は、マイコン(センサ)が手のひらの中心に来るようにし、茶碗を持つときのような動きで操作する必要がありました。角度によって移動速度が変化するため、手を静止していたとしても、全速でカーソルが動くこともしばしば。。。
ついでに、ボタンを押していない間もカーソルが移動するようになっており、結構不便でした。
今回は、オイラー角を用いることまでは一緒なのですが、角度をそのまま反映させるのではなく、「角速度」を利用しています。そして更に、角速度を直接PitchとYawから求めるのではなく、仮想的な持ち手を定義して棒を振り回す感じで扱えるようにしました。仮想的な持ち手を定義したことにより、操作量に対しての移動距離が現実とおおよそ対応付けられるようになり 、操作性が向上しています。
角速度を用いていることにより、ポインタに速度が加わらない限りはカーソルも移動しません。また、ボタンを押していない間はポインタが動かない + パワポの「ソフトポインタモード」も切るようにしており、より使いやすくなっています。
実装
#include <MadgwickAHRS.h> #include "IoTBoardUtility.h" // 自作基板用初期設定ライブラリ #include "IoTDisplay.h" // 自作基板用ディスプレイ操作ライブラリ #include "BMX055.h" // BMX055の自作ライブラリ。今回は初期化ぐらいしか使っていない。 #include "BleMouse.h" //https://github.com/T-vK/ESP32-BLE-Mouse Madgwick MadgwickFilter; // ①センサの誤差を確率論的に減らしてくれるフィルタ BleMouse bleMouse; int count=0; unsigned long startTime=0; unsigned long timer=0; unsigned long presenTimer=0; bool timerFlag = false; bool enableSoftMouse = false; // 昔はボタンを1度押したらカーソルが常に動くようになっていた。その名残。 bool softPointerFlag = false; // ソフトポインタモードにするか、ハードのレーザポインタ素子にするか。 bool redFlag = false; // パワポの Ctrl+L を押した状態にする float diffroll=0.0, diffpitch=0.0; float preA[3] = {0,0,0}; float diffA0,diffA2; void setup() { Serial.begin(115200); init(); initBMX055(); initDisplay(); timer=millis(); bleMouse.begin(); // マウスの機能のみでパワポ操作を全て行なう if(digitalRead(DIP4)==HIGH){ softPointerFlag=true; // あるスイッチがHIGHのとき、ソフトレーザポインタをON } MadgwickFilter.begin(20); //周波数 } void loop() { enableSoftMouse=true; // if(bleMouse.isConnected()) { digitalWrite(LED1,LOW); } if(bleMouse.isConnected() && softPointerFlag){ // ② if(digitalRead(SW3)==HIGH && redFlag){ // ボタンを離したタイミングでredを消す bleMouse.click(MOUSE_FORWARD); redFlag=false; } if(digitalRead(SW3)==LOW && !redFlag){ // ボタンを押したタイミングでredを付ける Serial.println("red"); bleMouse.click(MOUSE_FORWARD); redFlag=true; } if(enableSoftMouse && (millis()-timer > 50)){ float dx, dy; int len = 8; if(!digitalRead(SW3)){ getValues(); // Gyro, Acclm Mag配列と、r,p,y,prehogehogeは BMX055.hでfloatで定義している。。。 MadgwickFilter.update(Gyro[0],Gyro[1],Gyro[2],Accl[0],Accl[1],Accl[2],Mag[0],Mag[1],Mag[2]); r = MadgwickFilter.getRoll(); p = MadgwickFilter.getPitch(); y = MadgwickFilter.getYaw(); dx = -atan2((y-preyaw)*4, len)*rad2deg; // 仮想的な持ち手を基準に角速度を求める dy = atan2((p-prepitch)*4, len)*rad2deg; Serial.printf("x:%f\ty:%f\n",dx, dy); bleMouse.move((int)(dx),(int)(dy)); preroll = r; prepitch = p; preyaw = y; //過去の角度として保存 } timer = millis(); } } if(digitalRead(SW2)==LOW && bleMouse.isConnected()){ //戻る(略) if(digitalRead(SW4)==LOW && bleMouse.isConnected()){ //進む(略) if(digitalRead(SW1)==LOW){ //時間計測開始(略) if(timerFlag && (millis()-presenTimer > 1000)){ //450ms 間隔で液晶を更新(略) }
事前条件として「X-Mouse Button Control」というソフトを用いて、windows側でマウスの設定を変えています。私はForwardボタンを日常使用していないため、Forwardボタン(5つ目)をCTRL + L に対応付けてました。
①. Madgwickフィルタを用いているためyaw角の補正が入り、結果として静止時にx軸方向の移動が安定しない問題が残っていますが、個人的には現在ので割と満足です。操作しづらい場合は、変にyaw角の取得にこだわらずに、ジャイロセンサのz軸周りの回転速度を取るだけでもいいかもしれないですね。
②. 今回のメイン改造箇所です。3つのif文がありますが、それぞれ上から「ボタンが離された瞬間、カーソルを通常の➩形状に戻す」「ボタンが押された瞬間、カーソルをポインタ形状🔴にする」「ボタンが押されている間はマウスカーソルを動かす」処理をしています。
getValues( )関数で、Gyro, Accl, Magの9値を更新しており、それをMadgwickフィルタに突っ込んでいます。Madgwickした結果得られたPitchとYaw角を使用し、一度それぞれの角速度を求めています。
そして、角速度を適当に引き延ばしたものと(雑)仮想的な持ち手長"len"を用いて、arctanを計算することで棒を振り回すように、直感的な操作ができるようになっています。
完成品
おわりに
私は、基本的には一度完成したと考えた作品については、あまり改善をほどこさない人間でした。今回、1年以上前のプログラムを引っ張り出して修正してみて、どれだけ意味不明か怖かったのですが、短いコードゆえに意外に苦労しませんでした。システムの改善も意外に楽しいですねぇ。
自作のBMX055用のライブラリが間違っていたっぽくて、今まで正常にroll, pitch, yaw角が取れていませんでした。今回はMadgwickフィルタで手抜きしましたが、今度もう一度修正したいところです。
それでは。