モーションセンサーを利用するプログラムについて

2,720 views
Skip to first unread message

into

unread,
Oct 5, 2011, 5:01:49 AM10/5/11
to Android-SDK-Japan
はじめまして。intoと申します。

今読んでいるAndroidプログラミングの入門書のサンプルコードでよくわからないところがあります。
以下がそのわからないコードです(抜粋。変数名を一部変えています)。

-----
private final static float F = 0.1f; // FILTERING

public void onSensorChanged(SensorEvent event) {
// 加速度の処理
if (event.sensor == accelerometer) {
val[0] = (event.values[0] * F) + (val[0] * (1.0f - F));
val[1] = (event.values[1] * F) + (val[1] * (1.0f - F));
val[2] = (event.values[2] * F) + (val[2] * (1.0f - F));
}
// 方向の取得
if (event.sensor == orientation) {
val[3] = (event.values[0] * F) + (val[3] * (1.0f - F));
val[4] = (event.values[1] * F) + (val[4] * (1.0f - F));
val[5] = (event.values[2] * F) + (val[5] * (1.0f - F));
}
}
-----

モーションセンサーを利用するコードの一部ですが、
「加速度の処理」という部分は
今回の値=(SensorEventから取得した値 * 0.1) + (前回の値 * 0.9)
という計算をしていますが、これはローパスフィルタで重力加速度を取り出しているのでしょうか。
また、「方向の取得」の部分の計算はどういう意味なんでしょうか。サンプルコードでは「加速度の処理」と同じような計算をしています。
方位、ピッチ、ロールを取得には単純にSensorEventの値をそのまま使えばよくて、上記のような計算は必要ないと思うのですが。
自分の理解は合っているでしょうか。
詳しい方教えてください。よろしくお願いします。

Aska

unread,
Oct 6, 2011, 11:34:37 AM10/6/11
to Android-SDK-Japan
Askaです.

センサで検出した信号にはノイズなどでデータのバラツキが含まれるので,
測定値の平滑化を行っています.
http://ja.wikipedia.org/wiki/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87

into

unread,
Oct 7, 2011, 5:04:15 AM10/7/11
to Android-SDK-Japan
Aska様

回答ありがとうございます。

ご提示されたURLのところを読み自分なりに考えましたが、サンプルコードの計算はノイズを除去して平滑化する処理であり問題はない、とは思えませ
ん。

APIリファレンスのSensorEvent<クラスのTYPE_ACCELEROMETERに
「デバイスの実際の加速度を測定するために、重力の力の寄与を排除しなければならないことは明白である。これはハイパスフィルターを適用することに
よって達成できる。逆に、ローパスフィルタは、重力の力を分離するために使用することができます。」
とあります。
ご提示いただいたwikipediaの加重平均の説明には、加重平均はローパスフィルタの一種と書いてあります。
ということは、サンプルコードの処理は加速度センサーの生の値にローパスフィルタを適用しているということで、ノイズの影響は減るのでしょうが、それ以
上に値の急激な変化が取り除かれて重力加速度の影響が強く残ると思います。
「加速度の処理」と行ったら普通はデバイスを振ったり投げたりしたときの加速度を取得する処理だと思うので、ローパスフィルタを適用するのはサンプル
コードとしては不適切な気がします。

また、方位・ピッチ・ロールについてはもサンプルコードでは同じ計算をしている、つまりローパスフィルタを適用しているように思います。
デバイスを動かすとこれらの値は結構激しく動くので、ローパスフィルタを適用したらその動きに追随できなくなると思います。
実際にサンプルコードを実装したアプリをデバイスにインストールして実行すると、計算の結果出てくる値はセンサーの生の値にかなりゆっくり追随し(動か
さなければいずれはセンサーの生の値に収束しますが)、方位を取得する処理としては実用的ではないと思いました。

自分は数学や物理の素養がないので何か勘違いしているのかもしれませんが、現状ではサンプルコードは加速度や方位の処理としては不適切に思えます。

たろサ

unread,
Oct 7, 2011, 5:50:15 AM10/7/11
to android-...@googlegroups.com
 初めまして、たろサといいます。

> という計算をしていますが、これはローパスフィルタで重力加速度を取り出し
ているのでしょうか。

 違うと思います。サンプルは余り深く考えていないと思います。式を見る限
り、単純に0.9の一次IIRフィルタを掛けて速い周波数成分をきっているだけだと
思います。
 これだと、センサの実変化に追随しないもっさりとした変化になるだけだと思
います。

> また、「方向の取得」の部分の計算はどういう意味なんでしょうか。サンプル
コードでは「加速度の処理」と同じような計算をしています。

 これも同じで、深く考えずに速い周波数成分をきっているだけだと思います。

> 方位、ピッチ、ロールを取得には単純にSensorEventの値をそのまま使えばよ
くて、上記のような計算は必要ないと思うのですが。
> 自分の理解は合っているでしょうか。

 orientationは、event.values[0]は磁気センサの演算結果から出力して、
event.values[1]とevent.values[2]は加速度センサの値を出しているだけではな
かったかなと記憶しています。以前、調べたときにそんな感じだった記憶が残っ
ています。

 なので、静止状態のピッチ、ロールは生の値で大丈夫だと思います(センサが
暴れるので移動平均を少し掛けた方がいいと思いますが)が、動いている状態で
は、ピッチやロールは固体の振動や遠心力も加速度として拾うので、それらを
キャンセルする必要があります。
 

--
山本三七男 (Minao Yamamoto) ---------------- ハンドル:たろサ -----
E-Mail: taro...@gmail.com

into

unread,
Oct 7, 2011, 8:14:54 AM10/7/11
to Android-SDK-Japan
たろサ様

回答ありがとうございます。

回答の内容を完全に理解できたわけではありませんが、要するに「高い周波数成分を落としているだけ」という風に理解しました。

たろサ様のおっしゃるとおり、サンプルのコードを実機で動かすとセンサの生の値にゆっくりと追随して、落ち着くまで結構待たされます。

自分が本のサンプルコードは計算が重力加速度を求めているんだと考えた理由は、APIリファレンスのSensorEventのところに載っているコード


final float alpha = 0.8;
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];

という部分があって、これは本に載っていたサンプルコードと重みが違うだけで式としては一緒だったので本のサンプルコードも重力を算出しているのかなと
思った次第です。

完全に理解したわけではありませんが、なんとなくわかったような気がします。
ありがとうございました。

大和田 健一

unread,
Oct 7, 2011, 8:04:10 AM10/7/11
to android-...@googlegroups.com
はじめまして。 大和田 です。

> 今回の値=(SensorEventから取得した値 * 0.1) + (前回の値 * 0.9)

この式はよく使われていますが、
これが何をするものかの説明がほとんどなかったので、
簡単な説明をブログに書いています。

加速度センサ と ローパスフィルタ
http://android.ohwada.jp/archives/334

---
大和田 健一 <ml.o...@gmail.com>

into

unread,
Oct 8, 2011, 2:06:54 AM10/8/11
to Android-SDK-Japan
大和田様

回答ありがとうございます。

ブログ、参考にさせて頂きます。
Reply all
Reply to author
Forward
0 new messages