凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

筋電によるジェスチャコントロールが可能なアームバンド Myo が届いたので遊んでみた

はじめに

先週、昨年の 6 月にプリオーダーしていた Myo の Developer Kit が届きました。

f:id:hecomi:20141206190843j:plain

f:id:hecomi:20141206190937j:plain

f:id:hecomi:20141206191053j:plain

Myo は Thalmic Labs 社によって開発されたワイヤレスなアームバンド型のジェスチャコントローラです。

価格はプリオーダー時が $149、現在は $199 です。

Buy Preorder Myo Gesture Armband Controller by Thalmic Labs

ハードウェアとしては 9 軸の IMU センサと医療レベルの EMG(表面筋電位)センサ、ハプティック用にバイブレータ、無線接続用に BLE (PC とペアリングするドングルも同梱)、そしてジェスチャの解析用に ARM Cortex M4 プロセッサを搭載しています。用途としては、PC の操作(プレゼン支援など)やスマホの操作(音楽再生・音量変更など)といったことが可能ですが、公開されている SDK に Unity 用のパッケージも含まれており、これを利用することで簡単に Myo を利用したゲームなども作成可能です。今年の 3 月あたりから Oculus Rift と連携した動画も公開されていました。

試作品を私は、Developer Kit と製品版両方注文していたのですが、先週 Developer Kit の方が届いたので遊んでみました。

デモ

取れるジェスチャの種類

Leap Motion のように自由自在、というわけには行かず、現状認識可能なジェスチャは、リラックス状態、ダブルタップ(親指と人差指 or 中指で2連続でタップ)、グー、パー、内スワイプ(内側に腕を曲げた状態 )、外スワイプ(外側に腕を曲げた状態)の 6 状態です。これに加えて、IMU センサによって回転が取れる形になります。

f:id:hecomi:20141210225838p:plain

SDK の外観

SDK のページは以下になります。

スタックを見てみると以下のようになっています。

f:id:hecomi:20141210014514p:plain

BLE からの情報を libmyo が受け取って各言語にバインディングしている形でシンプルです。

Unity のサンプルと仕組み

サンプル

SDK をダウンロードすると unitypackage が同梱されているので、これを展開することで Myo を Unity 上で扱えるようになります。

f:id:hecomi:20141210232240p:plain

サンプルとして Box On A Stick シーンが含まれており、腕の姿勢をオブジェクトに反映したり、ジェスチャに応じてオブジェクトの色を変更したりバイブレーションを Myo に指示したり出来るようになっています。

Unity 用 SDK の仕組み

Plugins 下に Mac/Win 用の libmyo が入っており、これを Myo/Scripts/Myo.NET/libmyo.cs から DllImportバインディングしています。それを Myo/Scripts/Myo.NET/Myo.cs でイベント(e.g. ジャイロセンサのデータが渡ってくる GyroscopeData やジェスチャが変化した際にジェスチャに種類が渡ってくる PoseChange)や関数(e.g. ジェスチャ認識を再開する Unlock や Myo 本体をバイブレーションさせる Vibrate)とユーザが利用する形でラップしています。この libmyo.cs から別スレッドでイベントをポーリングしたり、その結果を Myo.cs とよしなに結びつけてくれるのが Myo/Scripts/Myo.NET/Hub.cs で、Myo はマルチペアリングを想定しているので、その辺りの割り振りもここで行っています。そして、Myo/Scripts/ThalmicHub.csMyo/Scripts/ThalmicMyo.csMonoBehaviour を継承したこれらのクラスのラッパーになり、Unity の世界と結びつけてくれるスクリプトになります。

そしてスクリーンショットのように ThalmicHub.cs をアタッチした GameObject の子に使いたい Myo の数だけ ThalmicMyo.cs をアタッチした GameObject を配置しておきます。これにより、該当の ThalmicMyo から色々なデータを引っこ抜けるようになります。

自然言語だと分かりにくいと思うので、Myo Samples/Scripts に入っているサンプルコードを見てみます(サンプルコード自体はシンプルなのですが、分かりやすいように大幅に書き換えています)。まずはジェスチャに応じてマテリアルを差し替えるスクリプトです。

ColorBoxByPose.cs
using UnityEngine;
using Pose = Thalmic.Myo.Pose;

#pragma warning disable 108 
public class ColorBoxByPose : MonoBehaviour
{
    public GameObject myo;
    
    public Material waveInMaterial;
    public Material waveOutMaterial;
    public Material doubleTapMaterial;
    
    private Pose lastPose_ = Pose.Unknown;
    private ThalmicMyo myo_;

    private Renderer renderer_;
    private Renderer renderer 
    {
        get { return renderer_ ?? (renderer_ = GetComponent<Renderer>()); }
    }
    
    void Awake()
    {
        myo_ = myo.GetComponent<ThalmicMyo>();
    }
    
    void Update()
    {
        // 前回と比較して変化があればイベント発火
        if (myo_.pose != lastPose_) {
            lastPose_ = myo_.pose;
            
            // ジェスチャに応じて処理を分ける
            switch (myo_.pose) {
                case Pose.Fist: 
                    myo_.Vibrate(Thalmic.Myo.VibrationType.Medium);
                    break;
                case Pose.WaveIn:
                    renderer.material = waveInMaterial;
                    break;
                case Pose.WaveOut:
                    renderer.material = waveOutMaterial;
                    break;
                case Pose.DoubleTap:
                    renderer.material = doubleTapMaterial;
                    break;
            }
        }
    }
}

myo.cs でハンドルしているイベントは非同期のスレッドで走っているため、イベントのタイミングでマテリアルの設定は出来ません。最新の PoseMyo クラスのメンバの pose に保存されているので、それを前回と比較しながら変化があったらそれに応じた処理を行う、という形になっています。

次に Myo の角度にオブジェクトを合わせるサンプルです。サンプルでは JointOrientation.cs がそれにあたりますが、簡単に書きなおしたものが以下になります。

MyoSensorDataToTransform
using UnityEngine;
using System.Collections;

public class MyoSensorDataToTransform : MonoBehaviour
{
    public GameObject myoObject;
    public TextMesh accelText, gyroText;
    
    private Vector3 offsetRotation_ = Vector3.zero;
    private ThalmicMyo myo_;

    void Awake()
    {
        myo_ = myoObject.GetComponent<ThalmicMyo>();
    }

    void Update()
    {
        // 姿勢情報は ThalmicMyo がついた GameObject に入っている
        var rotation = myoObject.transform.rotation.eulerAngles;
        rotation = new Vector3(-rotation.x, rotation.y, -rotation.z);
        
        // 現在の位置を基準の角度にする
        if (Input.GetKeyDown(KeyCode.R)) {
            offsetRotation_ = rotation;
        }
        
        // 回転
        transform.rotation = Quaternion.Euler(rotation - offsetRotation_); 

        // 加速度やジャイロの生値も使える
        accelText.text = myo_.accelerometer.ToString();
        gyroText.text = myo_.gyroscope.ToString();
    }
}

これで腕の向きがオブジェクトに反映されます。その他のイベントやパラメタについては ThalmicMyo.cs やドキュメントをご参照下さい。

EMG 生値について

Myo は今のところ EMG の生値にアクセスすることが出来ません。しかしながら生値のストリームへのアクセスは、近日中(12月中)に可能になると公式ブログで述べられています。

未だ公開していない理由としては、バッテリーの問題や生値の取扱が難しいことなどが上げられています。異なる二人のデータを比較しながら説明したりと、面白い内容になっていますのでぜひご一読下さい。

なお、既にアクセスしている人もいますので先んじて扱いたい場合は以下を参考に可能かもしれません(私はまだ未確認です)。

Tips

使っているうちに認識が微妙になったのですが、Myo Armband Manager からキャリブすると精度が向上しました(代わりに他の人がつけるとあまり認識しない感じになっているかもしれません)。

おわりに

アームバンド型であることから手のひらには何も装着しなくてよく、他のデバイスとの相性も良いと思います。また生値が扱えるようになれば、手の形は同じだけれど力を入れている、といったようなビジョンベースでは取れない情報も取ることができるようになると思われるので、面白いインタラクションが可能になるのではないでしょうか。今後のアップデートに注目です。