WinRT APIによるセンサー利用

自分のブログを振り返ってみて、あれ?WinRT APIのセンサー系に関する投稿が無い!!…ってことで、WinRT APIによるセンサープログラミングの解説です。

Windows 8のタブレットでは、WinRT APIを通じて以下の7つのセンサーを利用したプログラミングが可能です。

  • Accelerometer: 加速度センサー
  • Gyrometer: ジャイロセンサー
  • Compass: コンパス
  • LightSensor: 照度センサー
  • Inclinometer: 傾斜計
  • SimpleOrientationSensor: シンプルな方向センサー
  • OrientationSensor: 方向センサー

これらはWindows.Devices.Sensors 名前空間で提供されるクラス群です。これらのクラスを使ってタブレットの姿勢や向いている方向、動き、周囲の明るさをアプリケーションのシナリオに取り込むことができるわけです。各センサーから得られる値の種別は、センサー毎に異なりますが、全て同じ流儀で計測値を取得できます。Accelerometerを例に、センサープログラミングのパターンを説明しますね。

まず、センサーへの参照の取り出し方です。

var mySensor = Windows.Devices.Sensors.Accelerometer.GetDefault();

各センサーのクラスにはGetDefault()という名前のスタティックメソッドが用意されています。このメソッドをコールすることにより、センサーへの参照が取得できます。残念ながら全てのWindows 8 PCにセンサーが装備されているわけではありません。センサーが装備されていないPCでこのコードを実行すると、nullが返されます。センサーを活用するアプリを開発する場合には、センサーが装備されていない場合の考慮も必要です。ストア申請で、「アプリにはセンサーが必要」と明記するか、キーボードやマウスによる代替入力手段を用意するかしておきましょう。勿論、センサーが装備されていない場合(GetDefaultでnullが返された場合)に、不用意にmySensorにアクセスしないようにnullチェックを入れる必要があります。

センサーが計測したデータを取得する方法は二種類あります。一つはセンサーの計測値が必要な時点で計測値を要求する方法で、もう一つは、センサーがデータを計測した時点でイベントハンドラで計測値を受ける方法です。
前者のコードは以下のようになります。

if (myAccel != null)
{
    var reading = mySensor.GetCurrentReading();

各センサーのクラスには、必ずGetCurrentReading()というメソッドが用意されていて(※SimpleOrientationSensorを除く)、このメソッドをコールすることにより、センサー計測値を参照したいときに値を取り出すことができます。Accelerometerクラスの場合、このメソッドが返すのはAccelerometerReadingという型の変数です。他のセンサーの場合も、クラス名にReadingという接尾詞がついた型が用意されています。AccelerometerReadingの場合は、X、Y、Zというプロパティが定義されていて、それぞれX方向、Y方向、Z方向の加速度が格納されています。

次に、センサーがデータを計測した時点でのイベントハンドラで計測値を受ける方法ですが、

 if (mySensor != null)
 {
    mySensor.ReadingChanged += mySensor_ReadingChanged;
 }

とイベントハンドラを登録します。前者と同様、各センサーのクラスには、ReadingChangedというイベントが用意されています(※SimpleOrientationSensorを除く)

登録したイベントハンドラは、

void mySensor_ReadingChanged(Windows.Devices.Sensors.Accelerometer sender, Windows.Devices.Sensors.AccelerometerReadingChangedEventArgs args)
{
    var reading = args.Reading;
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
                // UI要素にアクセスする場合、実行スレッドが異なるので、UIのスレッドに処理を移譲する。形式はこの通り
    });

という形式をとります。sender、argsの2つの引数の型は、各センサー毎に合致した型に変わりますが、全て形式は一緒(※SimpleOrientationSensorを除く)です。argsには、Readingというプロパティが用意されていて、その方は前述のGetCurrentReading()で返される型と同じ型になっているので、そこからセンサー計測値を取得可能です。

Accelerometerクラス以外のセンサークラス毎の <センサークラス名> Readingのプロパティは以下の通りです。

  • Gyrometer: ジャイロセンサー
    • AngularVelocityX: X方向の角速度
    • AngularVelocityY: Y方向の角速度
    • AngularVerocityZ: Z方向の角速度
  • Compass: コンパス
    • HeadingMagneticNorth: 磁極の北極からの角度
    • HeadingTrueNorth:    真の北極からの角度
  • LightSensor: 照度センサー
    • IlluminanceInLux: 照度のルクス値
  • Inclinometer: 傾斜計
    • PitchDegrees: ピッチ角
    • RollDegrees:   ロール角
    • YawDegree:  ヨウ角
  • OrientationSensor: 方向センサー
    • Quatanion:    デバイスの方向を記述する四元数
    • RotationMatrix: デバイスの方向を記述する3×3行列数

OrientationSensorのRotationMatrixは、DirectXの3次元モデルの変換行列と型が同じなので、3次元オブジェクトの3次元の回転変換などにそのまま使えるようになっていたりしますが、各値の意味にピンとこない読者は、センサーが装備されたデバイスを購入して実際にプログラムを組んで試してみてください。Readingには他にTimestampというプロパティもあり、値が計測された時間を取得できます。

SimpleOrientationSensorの場合は、計測値をすぐ取得したい場合にはGetCurrentOrientation()をコール、イベントは、OrientationChangedとなっていて、メソッドの戻り値はSimpleOrientationという列挙型を返し、イベントハンドラの引数にも、ReadingではなくOrientationというプロパティが用意されています。Timestampもイベントハンドラの引数の直下に用意されています。

 

全部の値を表示するアプリを作って、Surfaceで表示すると、こんな感じです。

例として使ったAccelerometerには、他のクラスとは異なり、ReadingChangedイベントのほかにもう一つ、Shakenというイベントが用意されています。このイベントを通じて、デバイスが振られた(シェイク)ことを検知可能です。加速度センサーは3軸でデバイスにかかった加速度を計測可能ですが、案外、デバイスが振られたという事を計測値から判断するのは意外に難しいものです。このイベントを使うことにより、デバイスが振られたらマラカスの音を出すとか、そろばんの珠をご破算にしたり、二回振ったらSMAPの曲を流すとかいった処理を簡単に実現できます。

以上、センサーの使い方を解説してきました。とっても簡単ですね。ストアを除くと、まだまだ、センサーを活用したアプリケーションは少ないです。今後タブレットのWindows 8/8.1デバイスは確実に増えていくので、是非、センサーを活用した素敵なアプリを開発してストアから公開してくださいね。