Androidデバイスが物理的に移動したことを検知したいのであれば、このセンサーを使用します。
イベントで通知される値はfloat[3]で、それぞれX軸、Y軸、Z軸に対応しています。
センサーのイベントは「SensorEvent」という共通のデータ構造で通知されます。特に「SensorEvent#values」という値は、センサーのデータそのものが含まれるフィールドなのですが、センサーごとに配列のサイズやその意味が異なります。
加速度センサーでは、サイズ3の配列で、以下のような意味になります。
話が少し戻りますが、加速度とは一体何でしょうか。加速度は速度ではありません。
加速度とは、単位時間当たりの速度の変化率であり、具体的には物体が自由落下する際の加速度は約9.8m/s2です。これは1秒後が9.8m/s、2秒後が19.6m/s、3秒後が29.4m/sという具合に、速度が加速していくことを意味しています。
1秒後は約10m先に、2秒後は約30m先に、3秒後は約60m先に移動しているわけですから(60mは地上20階ぐらいです)、重力加速度はかなり速いです。
例えば、手に持った消しゴムをその場で離して、地面に落ちる前に離した手でつかむ、ということをしてみてください。その手の速さが重力加速度相当ということなので、重力加速度がアプリに加速度センサーのしきい値を設定する際の参考になるのではないかと思います。
今回のサンプルは、スマホを左右にスナップさせて、その動きを捉える処理を実装してあります。スナップの加速度がプラスマイナス6.0m/s2超過であれば、その方向にロケットが火を吹いて飛び、しばらくすると元に戻る、という動作をします。
今回採用した加速度6.0m/s2というのは、割と力強く手首のスナップを効かせると入力に成功する、という値です。これは説明してもなかなか分かりづらいので、実際に試してもらうのが一番です。
何かの拍子に大きな加速度がデバイスに加わって、それがスナップとして検知されてしまうことを防ぐために、今回のサンプルではある程度の“あそび”を持たせています。センサー起動直後は100回分のサンプリングを取得し、500msで何回通知されるかをおおよそ計算して、その500msの間で平均して6.0m/s2の加速度がなければ入力を受け付けないという工夫をしています。
先ほどで重力加速度の話をしましたが、加速度センサーは重力の影響を常に受けるため、静止している状態ではZ軸プラス方向に常に重力加速度が働いています。静止状態は重力に反して静止している状態、つまり重力加速度分を相殺する上方向に加速している、という考え方になります。
この重力加速度の影響を受けた状態だと、期待通りの加速度が取得できないため、実際の加速度から重力加速度を取り除く必要があります。その方法についてはAndroidのドキュメント「SensorEvent」に説明が記載されており、今回のサンプルでも、その説明に従って実装してあります。
/** * 加速度から重力加速度を取り除く。 * * @param values センサーの加速度 * @param gravity 前回の重力加速度が渡され、今回の重力加速度が格納される配列 * @param linearAccelatation 加速度から重力加速度が取り除かれた値が格納される配列 */ static void extractGravity(float[] values, float[] gravity, float[] linearAccelatation) { // 加速度から重力の影響を取り除く。以下参照。 // http://developer.android.com/intl/ja/reference/android/hardware/SensorEvent.html#values final float alpha = 0.8f; gravity[0] = alpha * gravity[0] + (1 - alpha) * values[0]; gravity[1] = alpha * gravity[1] + (1 - alpha) * values[1]; gravity[2] = alpha * gravity[2] + (1 - alpha) * values[2]; linearAccelatation[0] = values[0] - gravity[0]; linearAccelatation[1] = values[1] - gravity[1]; linearAccelatation[2] = values[2] - gravity[2]; }
Androidの公式ドキュメントだと分かりづらいですが、この処理のポイントは引数gravityの内容をフィールドに保持しておき、前回の値を入力として使用することにあります。そして、センサーから高頻度で呼び出されるため、メソッド内でオブジェクトを生成しないようにする、というのもポイントになると思います。
SensorManagerにセンサーのリスナーを登録するメソッド「registerListener(SensorEventListener listener, Sensor sensor, int rate)」の第2引数は、センサーイベントが通知される頻度に関するヒントです。速い順に以下の通りです。
値 | 説明 |
---|---|
SENSOR_DELAY_FASTEST | センサーデータを可能な限り速く取得する |
SENSOR_DELAY_GAME | ゲームに適した速度 |
SENSOR_DELAY_UI | UIに適した速度 |
SENSOR_DELAY_NORMAL | 画面方向切り替えに適した速度(デフォルト) |
加速度センサーで幾つかのデバイスを用いて、ヒントとイベントの頻度に関して調査してみました。
Name | Version | API Level | FASTEST | GAME | UI | NORMAL |
---|---|---|---|---|---|---|
Galaxy Tab | 2.3.3 | 10 | 10.23 | 20.37 | 60.17 | 200.1 |
Galaxy Nexus | 4.3 | 18 | 8.21 | 16.44 | 65.79 | 65.8 |
Galaxy 7 (2012) | 4.4.2 | 19 | 4.9 | 4.97 | 4.97 | 4.98 |
Nexus 5 | 4.4 | 19 | 5 | 5 | 65.22 | 200.58 |
目安 | 0 | 20 | 60 | 200 | ||
値はイベント通知間隔の平均時間(ミリ秒)です。手元のデバイスは速くて平均5ミリ秒、遅くても平均200ミリ秒間隔でイベントが通知されるようです。
「Galaxy 7」(2012)は全てのヒントで同じ頻度でイベントを通知してくるようです。「Galaxy Tab」はヒントに従って段階を踏んでおり、「Galaxy Nexus」はUIとNORMALが同じ、「Nexus 5」はFASTESTとGAMEが同じ頻度のようです。
「Galaxy Tab」「Nexus 5」はNORMALが200ミリ秒と同じように見えますが、「Nexus 5」が最小183ms、最大218msとぶれ幅が少ないのに対し、「Galaxy Tab」は最小22ms、最大238msとぶれ幅が大きいので、同じ平均200msでも安定度はかなり違ってきます。ただし、公式ドキュメント「Sensors Overview」に記載されている目安頻度に最も準拠しているのは「Galaxy Tab」です。
今回のサンプルアプリでは、加速度センサー以外のデバイスに搭載しているセンサーの実際のイベント通知頻度を確認できるので、気になったら手持ちのデバイスで確認してみてください。
Copyright © ITmedia, Inc. All Rights Reserved.