連載
» 2014年05月22日 18時00分 公開

Androidで動く携帯Javaアプリ作成入門(51):ウェアラブル時代に見直したいAndroidの加速度/重力センサー、ジャイロスコープ (2/3)

[緒方聡,株式会社イーフロー]

デバイスが物理的に移動したことを検知する「加速度センサー」

 Androidデバイスが物理的に移動したことを検知したいのであれば、このセンサーを使用します。

加速度センサーのサンプルアプリを動かす動画(クリックすると再生が始まります)

 イベントで通知される値はfloat[3]で、それぞれX軸、Y軸、Z軸に対応しています。

図1 加速度センサーの軸方向

 センサーのイベントは「SensorEvent」という共通のデータ構造で通知されます。特に「SensorEvent#values」という値は、センサーのデータそのものが含まれるフィールドなのですが、センサーごとに配列のサイズやその意味が異なります。

 加速度センサーでは、サイズ3の配列で、以下のような意味になります。

  • values[0]:X軸の加速度
  • values[1]:Y軸の加速度
  • values[2]:Z軸の加速度

そもそも、「加速度」って何だ

 話が少し戻りますが、加速度とは一体何でしょうか。加速度は速度ではありません。

 加速度とは、単位時間当たりの速度の変化率であり、具体的には物体が自由落下する際の加速度は約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超過であれば、その方向にロケットが火を吹いて飛び、しばらくすると元に戻る、という動作をします。

 今回採用した加速度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引数は、センサーイベントが通知される頻度に関するヒントです。速い順に以下の通りです。

表2 イベント頻度に関するヒント
説明
SENSOR_DELAY_FASTEST センサーデータを可能な限り速く取得する
SENSOR_DELAY_GAME ゲームに適した速度
SENSOR_DELAY_UI UIに適した速度
SENSOR_DELAY_NORMAL 画面方向切り替えに適した速度(デフォルト)

 加速度センサーで幾つかのデバイスを用いて、ヒントとイベントの頻度に関して調査してみました。

表3 デバイスごとのイベント頻度
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ミリ秒間隔でイベントが通知されるようです。

図2 デバイスごとのイベント頻度

 「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」です。

 今回のサンプルアプリでは、加速度センサー以外のデバイスに搭載しているセンサーの実際のイベント通知頻度を確認できるので、気になったら手持ちのデバイスで確認してみてください。

図3 「Galaxy Nexus」のセンサー一覧

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。