雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

わんくま東京勉強会 #64 アフターフォロー (22) : センサー

セッションでは扱いませんでしたが、 Windows Phone には色々なセンサーが搭載されています。
また、アプリケーションからセンサーの情報を取り出す為の API も用意されています。
但し、一部のセンサーについてはオプションとなっている為、機種によっては使用出来ない場合があるので注意が必要です。
※以下に記載した搭載要否の情報は 2011/12時点のハードウェア要件に基づくものです。今後の規約改訂で変わる可能性はあるのでご承知おきください。

加速度センサー (Accelerometer)
端末の x-y-z 軸への加速度成分量を取得出来ます。(全ての端末に搭載されています)
コンパス (Compass)
磁北からの時計回りでの角度を取得出来ます。(オプション機能の為、搭載されていない端末もあります)
ジャイロ (Gyroscope)
端末の x-y-z 軸からの回転角度を取得出来ます。(オプション機能の為、搭載されていない端末もあります)
複合モーション (Motion)
端末の動きについての低レベル Raw データを取得出来ます。(全ての端末に搭載されています)

センサーの利用方法

センサーの API は基本的にどれも同じ様になっています。
ここでは加速度センサー (Accelerometer) を例として挙げますが、他のセンサー API も利用方法は一緒です。

同期実行
// 以下の名前空間を using に加えておきます
// Microsoft.Devices.Sensors
// Microsoft.Xna.Framework

using (var sensor = new Asscelerometer())
{
  sensor.Start(); // Start メソッドでセンシング開始
  var current = sensor.CurrentValue; // CurrentValue プロパティで情報を取得
                                     // センサーによって返ってくる型が変わります
                                     //    加速度センサー     : AccelerometerReading
                                     //    コンパスセンサー   : CompassReading
                                     //    ジャイロセンサー   : GyroscopeReading
                                     //    モーションセンサー : MotionReading
  var x = current.Acceleration.X; // X 軸
  var y = current.Acceleration.Y; // Y 軸
  var z = current.Acceleration.Z; // Z 軸
}

※非常に簡単ですが、同期実行だとセンシングの間スレッドをロックしてしまうので、通常は下のイベント方式を使うべきです。

イベント形式

まずは定義。

sensor = new Asscelerometer(); // sensor 変数はクラスのメンバ変数で定義しておきましょう
sensor.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(Sensor_CurrentValueChanged);
                               // CurrentValueChanged イベントにイベントハンドラを登録します

イベントハンドラはこんな感じで。

private void CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
{
  // UI スレッドじゃないので Dispatcher.BeginInvoke が必要です
  Deployment.Current.Dispatcher.BeginInvoke(
      () => {
                var current = e.SensorReading; // 情報は EventArgs の SensorReading プロパティから取得出来ます
                // 後は一緒
                var x = current.Acceleration.X;
                var y = current.Acceleration.Y;
                var z = current.Acceleration.Z;
            });
}

後は、センシングを開始するタイミングで sensor.Start() を呼び出せば OK です。
センシングは結構バッテリを喰うので必要最低限の間隔で行う様にしましょう。
ちなみに、センシングの停止は Stop メソッドで行えます。
※センサーは IDisposable なクラスなので、オブジェクト破棄のタイミングで Dispose メソッドを呼ぶのもお忘れなく。

センサー利用の許可

アプリケーションでセンサーを利用する場合は、利用するセンサー毎に必ずユーザーに同意を求める様にしてください。
※この確認は、センサー毎にアプリケーション内で初回に利用する際のみで OK です。

オプションなセンサーの扱い

現時点でコンパスとジャイロのセンサーはオプションなので、機種によってはセンサーが搭載されていない場合があります。
該当するセンサーが搭載されていない端末でセンサー API を呼び出すと例外が発生してしまうので、オプションなセンサーを呼び出す際は呼び出しの先頭でセンサーが有効であるかを必ず確認してください。

if (!Compass.IsSupported)
{
  // コンパス非サポート端末への代替処理
  // ……実際にはエラーメッセージを出すとかですかね。。。
}