« Android SDK 1.1 リリース - APIレベルについて | メイン | Software Design3月号 »

Android - 加速度センサー再び

私が以前書いた、これ、や、これ、などのセンサーの投稿は、結構内容が古くなってしまいました。

 これを調べていた頃はまだG1が出る前(9月)だったので、その当時のOpenIntentsのSensorSimulatorの振る舞いや、当時のAPIリファレンスを見ながら書いたものです。しかし、実際にDev Phoneを購入して試してみるとDev Phoneで実際に取得できるセンサーの値がちょっと違っていることがわかりました。また加えてAPIに拡張や変更があったことも原因で、前に書いた記事を鵜呑みにすると、うまくいかないことがあります。ググってもAndroid SDKの加速度センサーを使った日本語の情報があまり出てこないようで、私のこのBLOGに辿り着かれる方が結構いらっしゃるので、ずっと修正したいと思っていました。

 全て網羅するわけではないのですが、いくつかの差異をここに示そうと思います。もしかすると、G1特有の挙動かもしれず、別機種ではまた別の値となるかもしれませんが、ご参考までに。


加速度センサーの値:
 以前は、1Gのときに1.0fを示すと書きましたが、仕様が変更になったようで、m/s^2のままです。なので、1Gのときは9.82fになるのだと思います。1Gのときに1.0にしたい場合はSensorManager.GRAVITY_EARTHで割ると出てきます。地球以外で使う場合は別の値で割ればいいと思います。


傾度センサーの値:
 以前は、0番目からyaw, pitch, rollと思っていましたが、違うようです。通常のロールピッチヨー角の考え方とは異なります。0番目はyawでなく、代わりにAzimuthという方位を示す値が入ります。この値は0以上360未満の範囲を取ります。0は北、90は東、180は南、270は西です。この値を使うことで、方位だけなら磁気センサーの値を計算せずとも簡単に取ることが出来ます。傾きはpitchとrollのみで判断します。多分以前よりも簡単です。ロールピッチヨーの3つの値の組み合わせだと、どのような経緯を経て、今の傾きになったのかを追跡することが出来ます。それは確かに必要な局面はあるかもしれませんが、通常はその時点の傾きのスナップショットのみが欲しいことが殆どでしょうから、pitchとrollだけでも判断できますし、そのように判断した方が簡単だと思います。でも、加速度センサーの値から傾きは判断できますので、(方位は楽かもですが)傾度センサーの値は別に要らないかなあ、とも思います。


サンプル:
先日、Android SDK WGで、加速度センサーを使った簡単なサンプルを皆で作って遊びました。

作ったアプリの仕様は

・端末を振っているときに、背景の色を変えてください
・振るのを止めたら、背景の色を元(黒)に戻してください
・端末の傾きに応じて、画面に(縦、横、水平などの)文字を表示してください


という感じです。実装したアプリは、例えばこんな動きをします。

多分実装の方法は無数に考えられるのですが、Activityのひとつの実装例を丸ごと載せておきます。

package net.grandnature.android.sdkwg.examples.sensor;

import java.text.DecimalFormat;

import android.app.Activity;
import android.graphics.Color;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class Main extends Activity implements SensorListener {
    View layout;
    TextView accelerometerValue;
    TextView orientationValue;
    TextView filteredAccelerationValue;
    TextView filteredOrientationValue;
    TextView orientation;
    SensorManager sensorManager;
    static DecimalFormat format;
    static {
        format = new DecimalFormat();
        format.applyLocalizedPattern("#0.000");
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // --- views
        setContentView(R.layout.main);
        layout = findViewById(R.id.layout);
        accelerometerValue = (TextView)findViewById(R.id.accelerometer_value);
        orientationValue = (TextView)findViewById(R.id.orientation_value);
        filteredAccelerationValue = (TextView)findViewById(R.id.filtered_acceleration_value);
        filteredOrientationValue = (TextView)findViewById(R.id.filtered_orientation_value);
        orientation = (TextView)findViewById(R.id.orientation);
        // --- sensors
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    }
    @Override
    protected void onStop() {
        sensorManager.unregisterListener(this);
        super.onStop();
    }
    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, 
                SensorManager.SENSOR_ACCELEROMETER | 
                SensorManager.SENSOR_ORIENTATION,
                SensorManager.SENSOR_DELAY_FASTEST);
    }
    private float[] currentOrientationValues = {0.0f, 0.0f, 0.0f};
    private float[] currentAccelerationValues = {0.0f, 0.0f, 0.0f};
    public void onSensorChanged(int sensor, float[] values) {
        switch(sensor) {
        case SensorManager.SENSOR_ACCELEROMETER:
            accelerometerValue.setText(convertFloatsToString(values));
            // 傾き(ハイカット)
            currentOrientationValues[0] = values[0] * 0.1f + currentOrientationValues[0] * (1.0f - 0.1f);
            currentOrientationValues[1] = values[1] * 0.1f + currentOrientationValues[1] * (1.0f - 0.1f);
            currentOrientationValues[2] = values[2] * 0.1f + currentOrientationValues[2] * (1.0f - 0.1f);
            // 加速度(ローカット)
            currentAccelerationValues[0] = values[0] - currentOrientationValues[0];
            currentAccelerationValues[1] = values[1] - currentOrientationValues[1];
            currentAccelerationValues[2] = values[2] - currentOrientationValues[2];
            filteredAccelerationValue.setText(convertFloatsToString(currentAccelerationValues));
            filteredOrientationValue.setText(convertFloatsToString(currentOrientationValues));
            // 振ってる? 絶対値(あるいは2乗の平方根)の合計がいくつ以上か?
            // 実装例
            float targetValue = 
                Math.abs(currentAccelerationValues[0]) + 
                Math.abs(currentAccelerationValues[1]) +
                Math.abs(currentAccelerationValues[2]);
            if(targetValue > 22.0f) 
                layout.setBackgroundColor(Color.YELLOW);
            else if(targetValue < 10.0f) 
                layout.setBackgroundColor(Color.BLACK);
            // かたむきは?3つの絶対値(あるいは2乗の平方根)のうちどれがいちばんでかいか?
            // 実装例
            if(Math.abs(currentOrientationValues[0]) > 7.0f) {
                orientation.setText("横");
            } else if(Math.abs(currentOrientationValues[1]) > 7.0f) {
                orientation.setText("縦");
            } else if(Math.abs(currentOrientationValues[2]) > 7.0f) {
                orientation.setText("水平");
            } else {
                orientation.setText("");
            }
            break;
        case SensorManager.SENSOR_ORIENTATION:
            orientationValue.setText(convertFloatsToString(values));
            break;
        default:
        }
    }
    private String convertFloatsToString(float[] values) {
        return 
        String.valueOf(format.format(values[0])) + ", " + 
        String.valueOf(format.format(values[1])) + ", " + 
        String.valueOf(format.format(values[2]));
        
    }
    public void onAccuracyChanged(int sensor, int accuracy) {
        
    }

}

サンプルのEclipseプロジェクト:
Eclipseのプロジェクトごと圧縮してここに置いています。
SensorExample.zip

トラックバック

このエントリーのトラックバックURL:
http://www.grandnature.net/bin/mt-tb.cgi/106

この一覧は、次のエントリーを参照しています: Android - 加速度センサー再び:

» Android Hackathon に参加してきた 送信元 tmty.jp
3/19, 20 に開催された Android Hackathon に参加してきました。参加者は 2 日間いずれかへの参加を選ぶ形式で、僕が参加してきたの... [詳しくはこちら]

» Android Hackathon に参加してきた 送信元 tmty.jp
3/19, 20 に開催された Android Hackathon に参加してきました。参加者は 2 日間いずれかへの参加を選ぶ形式で、僕が参加してきたの... [詳しくはこちら]

» シャカシャカシェイクリスナー 送信元 BuGcloUd.com
「Android端末をフンッ!って振ったら、今いる場所の住所をtwitterでつぶやく」っていう機能を実装したときのメモ。GPSから逆ジオコーディングとか... [詳しくはこちら]

コメント (5)

こんばんは。

加速度センサのサンプル、非常に参考になりました。

拙ブログにて引用し違う機能も実装したりしつつ公開させて頂いたのですが、もし何か問題がありましたら即刻削除いたしますのでお手数ですがご連絡頂ければと思います。

よろしくお願いいたします。

egg:

コメントありがとうございます。
どうぞお使い下さい!

aki:

androidでセンサー対応するのに参考になりました。

自作のアプリをセンサー対応させるのサンプルが役立ちました。
コード付きでしたので、動かして試すことができました。

ありがとうございました。

Hola,
ЎGracias! Ahora me irй en este blog cada dнa!

Ilias

yuichi:

本に書いてる内容以上に参考になりました汗
すごいです。

コメントを投稿

About

2009年02月14日 02:22に投稿されたエントリーのページです。

ひとつ前の投稿は「Android SDK 1.1 リリース - APIレベルについて」です。

次の投稿は「Software Design3月号」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。