Thalmic Labs の MYO アームバンドが届いたので Google Chrome をマイノリティ・リポートっぽいジェスチャーで操作する Myo Scripts を書いてみる。
主な情報源
- https://developer.thalmic.com/start/
- https://www.thalmic.com/blog/tag/myo-scripting-basics/
- https://developer.thalmic.com/docs/api_reference/platform/script-tutorial.html
基本
Lua で記述し、拡張子は.myoを使う。
作成したスクリプトは Myo Connect を経由してアームバンドとやりとりをすることになる。
デバッグコマンドとして
myo.debug(obj)
が用意されている。
scriptId
スクリプトを識別するためのscriptId
は必ず書かなければならない。
scriptId = 'co.randompaper.myo.chrome'
onForegroundWindowChange(app, title)
function onForegroundWindowChange(app, title)
return app == "com.google.Chrome"
end
onForegroundWindowChange の返り値がtrueの場合、スクリプトをアクティブにする。つまり上のように書けば Google Chrome のウィンドウが最前面に出ている時だけスクリプトを有効化させることが出来る。
いかなる状況でもジェスチャーをハンドルしたい場合は以下のように書く。
function onForegroundWindowChange(app, title)
return true
end
実際には、親指と中指でダブルタップ するジェスチャーを検知した後に、全ての Myo Scripts の onForegroundWindowChange を呼び出している。そして true が返ってきたスクリプトのみを実行している。
アクティブになったスクリプトは一定時間が経過してアームバンドがロックされるまでイベントハンドラーが呼ばれ続ける。
onPoseEdge(pose, edge)
スクリプトがアクティブになっている間に行われたジェスチャーをハンドルするメソッド。
function onPoseEdge(pose, edge)
if pose == 'fist' and edge == 'on' then
myo.debug("グー")
elseif pose == 'fist' and edge == 'off' then
myo.debug("グーじゃなくなった")
end
end
pose の種類
pose | 意味 |
---|---|
rest | 安静時 |
fist | 握り拳 |
fingersSpread | 手を開く |
waveIn | 手首を手前に曲げる |
waveOut | 手首を手前とは逆に曲げる |
doubleTap | 中指と親指でダブルタップ |
unknown | 判別不能 |
onPeriodic()
function onPeriodic()
roll = myo.getRoll()
myo.debug(roll)
end
onPeriodic はスクリプトがアクティブな間ずっと呼ばれ続ける。常にアームバンドのジャイロ情報を取得してなんやかんやしたい時に使う。
実装
以上のハンドラーを駆使し作ってみる。 今回のように Google Chrome のスクロール操作をアームバンドのジェスチャーでやりたい場合、onPeriodic でmyo.getRoll()
メソッドを呼び出せば手首の回転する角度を取得出来るわけである。しかし、そのままonPeriodic上にスクロールを行うコードを続けて書くと常にアームバンドの傾き具合でスクロールされてしまい困る。
そこで、「握り拳を握っている間だけ手首の傾きによってウェブページをスクロールさせる」ようにする。
握り拳を握っている間だけ手首の傾きによってウェブページをスクロールさせる
初めにグローバルで enableScroll
変数を宣言し、false で初期化する。
enableScroll = false
そして、onPoseEdge に握り拳が握られると enableScroll を true に、戻ると false にするコードを書く。
function onPoseEdge(pose, edge)
if pose == 'fist' and edge == 'on' then
enableScroll = true
elseif pose == 'fist' and edge == 'off' then
enableScroll = false
end
end
最後に onPeriodic で手首の角度を取得してキーボードの ↑ か ↓ を連打するコードを書く。
function onPeriodic()
if enableScroll then
roll = myo.getRoll()
key = ''
if roll < -0.05 then
key = 'up_arrow'
elseif roll > 0.05 then
key = 'down_arrow'
end
if key ~= '' then
myo.keyboard(key, 'press')
end
end
end
実際にこのスクリプトを動かしてみると上手くスクロールしない。myo.getRoll()で取得した角度は絶対的な角度だからだ。握り拳が作られた瞬間の角度を 0 として扱った方がプログラムの見通しも良くなる。
そこで新たに initRoll 変数をグローバルで宣言する。そして onPoseEdge を以下のように修正する。
function onPoseEdge(pose, edge)
if pose == 'fist' and edge == 'on' then
initRoll = myo.getRoll()
enableScroll = true
elseif pose == 'fist' and edge == 'off' then
enableScroll = false
end
end
続けて onPeriodic の
roll = myo.getRoll()
を、
roll = myo.getRoll() - initRoll
に修正する。
これで、絶対角度を握り拳が握られた瞬間の手首の角度を 0 とする相対角度を取得出来る。
実際に動くスクリプトを Github で公開している。
番外編
Myo C++ SDK を使ってアイアンマンみたいなジェスチャーでレーザーガンを撃った気分になれるアプリを作った。