Windows Phone 7.1 センサー利用時の注意

Windows Phone 7.1センサー利用時の注意点を幾つか挙げておきます。センサープログラミングに関しては、センサープログラミングの基礎を見てください。

その1) いつでもあると思わないでね

Windows Phoneのハードウェア仕様を見ると、CompassとGyroは、オプションであると明記されています。製品によってはCompassとGyroscopeは使えない場合があるということです。この二つのセンサーが搭載されているかは、両方のクラスのスタティックプロパティのIsSupportedを参照すればわかります。このプロパティがfalseならば、残念ながらそのデバイスにはセンサーが搭載されていないことになります。アプリケーションを設計する時には、必要なセンサーが無い場合の対策を入れておきましょう。例えば、

  • 搭載されていない場合は提供機能を縮小する
  • 代替策がある場合は、別のセンサーやエミュレーションで機能ロジックを補完する
  • 必要なセンサーが搭載されていないことを表示する
  • Marketplaceのアプリ概要説明で、必要なセンサーを明記

などです。

if (!Compass.IsSupported)
{
    MessageBox.Show("王舞我”);
    ...

その2) 必要な時だけ使う

繰り返しになりますが、センサーデバイスを使っているとそれなりに電池を食います。無駄にセンサーであたうぃを取得し続けると、他のいざという時電池切れ・・・なんてことになりかねないので、センサーが必要になるタイミングと必要なくなるタイミングをきちんと設計して、Start()、Stop()メソッドをコールしましょうね

その3) その値、本当に正しい?

4つのセンサークラスには、IsDataValidというプロパティが用意されています。特にCurrentValueを使って同期的に値を取得する場合、この値がtrueの時だけ正しい値を取得可能です。センサーはセンサーデバイスなどハードウェア的な仕掛けを使うので、そのハードウェアの初期化やら何やらの手続きが必要でStartメソッドをコールしてから、実際に値が取得できるまで時間がかかる場合もあります。例えばMSC2011のD1-401でお見せしたARデモでは、Compassが直ぐには計測できなかったので、以下のようなコードを書きました。

var compass = new Compass();
compass.Start();
while (!compass.IsValid)
{
    System.Threading.Thread.Sleep(100);  // この秒数が妥当かどうかは現時点では不明。無限ループの可能性があるので、何回かトライしたらExceptionを発生するなどの対策が必要
}

デバッガーでのステップ実行では人間がF10を押す間にIsValidがtrueになってしまうので、このコードを入れなくても、ちゃんと動いてしまいます。知らないとなかなか見つけられない問題なので、ステップ実行では動作するのにするっと動かすと正常に値が取れていないような場合は、IsValidを疑ってみましょう。

その4) その値、本当に正しい? Again

物理的事象を精密に計測する場合、精度と誤差を必ずきちんと考える必要があります。大雑把な動きや方向などをアプリに取り込む場合は問題ありませんが、ある程度正確な値が必要な場合は、例えば平均をとって慣らすなどの処理を入れましょう。(まぁもともとコンシューマーデバイスのセンサーなので、あまり厳密な計測には向かないかも…です)
Compassには、Calibrateというイベントが用意されています。これはTrueHeadingの値が±20度以上違うとシステムが認識した時に発火するイベントです。ナビゲーションアプリケーションなど、ある程度正確な方位が必要なアプリを作る場合には、このイベントにもきちんと対応しましょう。キャリブレーションの方法はまた別途ポストしますね。

その5) なるべくMotionセンサーを使いましょ

Motionセンサーはアプリケーションが利用しやすい形にセンサーデバイスの計測値を加工してくれるので、出来る限りMotionセンサーを使いましょう。

その6) 実行スレッド

非同期的に計測データを取得するには、CurrentValueChangedイベントにハンドラーを登録して、システムから通知を受けますが、ハンドラーをコールするスレッドは、アプリのメインスレッドとは異なるので、そのままSilverlightのコントロールを操作しようとするとExceptionが発生します。しばらくぶりにプログラミングすると、大抵忘れているので、Exception発生した時には思い出してください。

Deployment.Current.Dispatcher.BeginInvoke(()=>
{
    var accel = e.Accelaration;

このブロックの中での処理は、メインスレッドのディスパッチャーキューに入って順番に実行されているので問題ないですが、コントロールアクセスがなく単にクラスのメンバー変数を更新する場合など処理を委譲せずにそのままハンドラーをコールしたスレッドで処理を行うような場合は、lockやMutexなどを活用してきちんとスレッド間の排他処理を入れましょう。

 

と、まぁ、こんなところでしょうか。

センサーとは、デバイスを取り巻く実世界の様々な事象を数値化して取り込んでくれるものです。その類のフィーチャーは、Accelerometer、Gyroscope、Compass、Motionの4クラス以外にも、位置情報やカメラ、マイク、FM電波の強度、電池の残りなど、他にも沢山あります。これまであまり活用されていなかったフィーチャーを使い倒して、魅力的なアプリケーションを是非、開発してくださいね。