弊社で『鮭 – Shake』というアプリをAndroid Marketにリリースしました。
端末を振ることで起動中のアプリケーションを切り替える、というアプリです。
機能の実現には加速度センサーを使用しています。
そこで今回は加速度センサーを使用する際のポイントについて書きたいと思います。
<ポイント>
1.機種によって加速度センサーの閾値が違う。
2.機種によって加速度センサーの搭載位置が違う。
→同じくらいの強さで振っても機種によって取得できる値がまったく違う。
3.端末持つ位置でも当然変わってくる。
これらの問題を解決するために加速度センサーの感度を調整する機能を設けました。
また、開発当時に販売されていたいくつかの端末を使用して、数十人に実際に端末を振ってもらって
サンプルを収集。収集した実測値の標準偏差を算出して調整幅のMAX値とMIN値を決定しています。
以下は加速度センサーを用いた測定部分の実際のソースコード抜粋です。
/**
* 加速度センサからモーションを検知するための基礎値のワーク領域
**/
private float[] m_fCurrentOrientationValues = { 0.0f, 0.0f };
/**
* 加速度センサからモーションを検知するための基礎値のワーク領域
**/
private float[] m_fCurrentAccelerationValues = { 0.0f, 0.0f };
public void onSensorChanged(SensorEvent clEvent) {
float targetValue = 0;
if (clEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// 加速度センサの値が更新された場合
// clEvent.values[0-2]は加速度センサの値が設定される。
/* 加速度からモーションを検知するための基礎値の算出 */
// intにすると丸め処理が多くてfloat演算との誤差が大きくなりすぎるのでfloat演算をします。
// ローパス(ハイカット)フィルター
// 重力の影響だけが残る=>傾き
// “前回のローパスフィルター処理した値の x%”
// + “生の(フィルター処理していない)値の (100 - x) %”
m_fCurrentOrientationValues[0] = clEvent.values[0] * 0.1f + m_fCurrentOrientationValues[0] * 0.9f;
// ハイパス(ローカット)フィルター
// 重力の影響が取り除かれる=>(瞬間的な)加速度
// “生の(フィルター処理していない)値”
// - “ローパスフィルタ処理済の値”
m_fCurrentAccelerationValues[0] = clEvent.values[0] - m_fCurrentOrientationValues[0];
if ((ShakeOptionManager.getHand() == ShakeOptionManager.SHAKE_LEFT_HAND) &&
(m_fCurrentAccelerationValues[0] <= 0)) {
targetValue = Math.abs(m_fCurrentAccelerationValues[0]);
} else if((ShakeOptionManager.getHand() == ShakeOptionManager.SHAKE_RIGHT_HAND) &&
(m_fCurrentAccelerationValues[0] >= 0)) {
targetValue = m_fCurrentAccelerationValues[0];
}
}
if (targetValue > (float)ShakeOptionManager.getStrong()) {
if(!m_blWaitFlag) {
// 待機フラグをON
m_blWaitFlag = true;
// 300ミリ秒後にハンドラに登録されたスレッド起動する
processHandler.postDelayed( processRunnable, DELAYD_TIME );
}
}
}
最後の忘れてはいけないポイントは、
『加速度センサーから取得できた値には重力加速度の値も含まれている。』
ということです。
端末を振った強さだけを純粋に測定したい場合は、取得した値から『重力加速度』を除く必要があります。