marunomaruno-memo

marunomaruno-memo

Android センサー (1) 光センサーと加速度センサー

2011年08月28日 | Android
センサー (1) 光センサーと加速度センサー
================================================================================

各種センサーを使うことができる。

■ センサーのタイプ

Sensor クラスの定数で定義してある。以下にまとめる。

センサー名           定数                        単位   値の次元  可
------------------- --------------------------- ------- -------- ------
加速度               TYPE_ACCELEROMETER          m/s^2     3      ○
重力                 TYPE_GRAVITY                m/s^2     3      ※ 
ジャイロスコープ     TYPE_GYROSCOPE              rad/s     3      × 
光                   TYPE_LIGHT                  lux       1      ○ 
線形加速             TYPE_LINEAR_ACCELERATION    m/s^2     3      ※ 
地磁気               TYPE_MAGNETIC_FIELD                   3      ○ 
圧力                 TYPE_PRESSURE               Pa        1      × 
近接                 TYPE_PROXIMITY              cm        1      ○ 
回転ベクトル         TYPE_ROTATION_VECTOR        -         4      ※ 
温度                 TYPE_TEMPERATURE            ℃        1      ○ 
傾き                 TYPE_ORIENTATION            deg       3     非推奨
(○あり、×なし、※Android2.2では対象外)


■ センサーのタイプと値の取得方法

センサーの値を取得するには、つぎの手順が必要。

1. SensorManager のオブジェクトを取得する
2. SensorManager オブジェクトにセンサーのリスナーを登録する
3. センサーの値を取得する

ここでは、値の取得について補足する。
どのセンサーでも、センサーのリスナーの void onSensorChanged(SensorEvent event) 
メソッドの event に、そのときの値が入っている。これのインスタンス変数 values が
配列になっており、センサーからの取得値の次元によって、要素数が決まる。

以下にそれぞれのセンサーについての values について補足する。


□ TYPE_ACCELEROMETER 加速度センサー
    values[0]: X 軸方向の加速度
    values[1]: Y 軸方向の加速度
    values[2]: Z 軸方向の加速度

    X 軸: 実機の横方向(右方向が正)
    Y 軸: 実機のたて方向(上方向が正)
    Z 軸: 実機の前面方向(前面方向が正)

SensorEvent クラスの API に図入りで説明がある。


□ TYPE_GRAVITY 重力センサー
※Android2.2 にはない


□ TYPE_GYROSCOPE ジャイロスコープ・センサー
    values[0]: X 軸方向の角速度
    values[1]: Y 軸方向の角速度
    values[2]: Z 軸方向の角速度


□ TYPE_LIGHT 光センサー
    values[0]: 照度


□ TYPE_LINEAR_ACCELERATION 線形加速センサー
※Android2.2 にはない


□ TYPE_MAGNETIC_FIELD 地磁気センサー
    values[0]: X 軸方向の磁気密度
    values[1]: Y 軸方向の磁気密度
    values[2]: Z 軸方向の磁気密度


□ TYPE_PRESSURE 圧力センサー

□ TYPE_PROXIMITY 近接センサー
    values[0]: 距離


□ TYPE_ROTATION_VECTOR 回転ベクトル・センサー
※Android2.2 にはない


□ TYPE_TEMPERATURE 温度センサー
APIには特に記述はないが、摂氏で取得される。


□ TYPE_ORIENTATION 傾きセンサー
ただし、この定数は非推奨になったので、このセンサーの値は、この定数を使うのではな
く、SensorManager.getOrientation() メソッドを使う。


■ 光センサーの値を表示する

光センサーの値を取得して、表示する。
    単位: lux (ルクス)
    values[0]: 照度

センサーの値を取得するには、つぎの手順が必要。

1. SensorManager のオブジェクトを取得する
2. SensorManager オブジェクトにセンサーのリスナーを登録する
3. センサーの値を取得する


これにしたがって、プログラムを作る。


□ LightSensor01Activity.java
---
package jp.marunomaruno.android.sample;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

/**
 * 光センサーの値を表示する。
 * @author marunomaruno
 * @version 1.0, 2011-06-25
 */
public class LightSensor01Activity extends Activity {

    // TextView
    private TextView lightTextView; // 光センサー

    private SensorManager sensorManager;                                // (1)
    private SensorEventListener sensorEventListener; 
        // onPause()が呼ばれたときに、すべてのリスナーを解除するため    // (2)

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        lightTextView = (TextView) findViewById(R.id.sensor_value);
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);// (3)
    }

    @Override
    protected void onResume() {
        super.onResume();

        // 光センサーを取得して登録する
        sensorEventListener = new LightSensorListener(lightTextView);   // (4)

        for (Sensor sensor : sensorManager.getSensorList(Sensor.TYPE_LIGHT)) {// (5)
            sensorManager.registerListener(sensorEventListener, sensor,
                    SensorManager.SENSOR_DELAY_NORMAL);                 // (6)
        }
    }

    @Override
    public void onPause() {                                             // (7)
        super.onPause();

        // すべてのリスナーを解除する
        sensorManager.unregisterListener(sensorEventListener);          // (8)
    }
}
---


(1)(3) SensorManager を宣言する。

    private SensorManager sensorManager;                             // (1)  
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);// (3)

SensorManager は、センサーにアクセスするためのクラス。


・クラス階層
java.lang.Object
   + android.hardware.SensorManager

public なコンストラクターはない。オブジェクトの取得は、(3) のように、
    getSystemService(SENSOR_SERVICE)
を使う。

実際は、
    Context.getSystemService(Context.SENSOR_SERVICE)
だが、Activity クラスのサブクラスの中から取得しているため、「Context.」部分は必
要ない。


・主なメソッド
---
List<Sensor> getSensorList(int type)
boolean      registerListener(SensorEventListener listener, Sensor sensor, 
                                int rate, Handler handler)
boolean      registerListener(SensorEventListener listener, Sensor sensor, 
                                int rate)
void         unregisterListener(SensorEventListener listener, Sensor sensor)
void         unregisterListener(SensorEventListener listener)
---

メソッドとしては、次のような使い方の構成になっている。

・Android 実機から、使えるセンサーのリストを getSensorList() メソッドで取得する。
・それを、registerListener() メソッドを使って、センサーと、そのリスナーとを紐付
ける。
・センサーが必要なくなったら、unregisterListener() で、紐付けを解除する。


(2)(8) onPause()が呼ばれたときに、すべてのリスナーを解除するために、センサーのリ
スナーを登録しておくリストを宣言する。

    private SensorEventListener sensorEventListener; 
        // onPause()が呼ばれたときに、すべてのリスナーを解除するため    // (2)

リスナーの解除は、(8) にあるように、SensorManager クラスの 
unregisterListener(listener) メソッドを使う。

    sensorManager.unregisterListener(sensorEventListener);            // (8)


(4) 光センサーのリスナーを宣言する

    sensorEventListener = new LightSensorListener(lightTextView);    // (4)

光センサー・リスナーは、別クラスとして作っている。
別クラスとして作ることで、単体テストなどはしやすくなる。また、他のアプリケーショ
ンでの再利用もしやすくなる利点がある。


(5) for (Sensor sensor : sensorManager.getSensorList(Sensor.TYPE_LIGHT)) {// (5)

光センサーのディバイスを取得する。1台の実機に、複数の光センサーがついている可能
性があるので、戻り値はリストになっている。

List<Sensor> getSensorList(int type)

引数の type は、センサーの種類を表す定数で、Sensor クラスに、つぎのような定数が
定義されている。

センサー名           定数                        単位   値の次元  可
------------------- --------------------------- ------- -------- ------
加速度               TYPE_ACCELEROMETER          m/s^2     3      ○
重力                 TYPE_GRAVITY                m/s^2     3      ※ 
ジャイロスコープ     TYPE_GYROSCOPE              rad/s     3      × 
光                   TYPE_LIGHT                  lux       1      ○ 
線形加速             TYPE_LINEAR_ACCELERATION    m/s^2     3      ※ 
地磁気               TYPE_MAGNETIC_FIELD                   3      ○ 
圧力                 TYPE_PRESSURE               Pa        1      × 
近接                 TYPE_PROXIMITY              cm        1      ○ 
回転ベクトル         TYPE_ROTATION_VECTOR        -         4      ※ 
温度                 TYPE_TEMPERATURE            ℃        1      ○ 
傾き                 TYPE_ORIENTATION            deg       3     非推奨
(○あり、×なし、※Android2.2では対象外)

また、TYPE_ALL という定数があり、これですべてのセンサーのオブジェクトを取得でき
る。


Sensor クラス

・クラス階層
java.lang.Object
   + android.hardware.Sensor

・主なメソッド
---
float   getMaximumRange()
int     getMinDelay()
String  getName()
float   getPower()
float   getResolution()
int     getType()
String  getVendor()
int     getVersion()
---


(6) センサーのリスナーをセンサーに登録する

    sensorManager.registerListener(sensorEventListener, sensor,
                SensorManager.SENSOR_DELAY_NORMAL);                    // (6)

つぎのメソッドがある。
---
boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
                         Handler handler)
boolean registerListener(SensorEventListener listener, Sensor sensor, int rate)
---

今回は、光センサーに、光センサーのリスナーを登録する。登録は、紐付けしていること
になる。

rate は、SensorManager クラスでつぎの 4 つの定数が定義されている。

SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, SENSOR_DELAY_FASTEST

これらは、定数の値としては 3, 2, 1, 0 なので、直接遅延時間になっているわけではな
い。

実際の遅延時間の値を確認するには、Sensor クラスに 
    int     getMinDelay()
があるが、これは API レベル 9 なので、Android2.2 では使えない。
SensorManager クラスのソースで見てみると、次のような値になっている(実際はμ秒
値)。

    SENSOR_DELAY_FASTEST      0 ms (     0 μs)
    SENSOR_DELAY_GAME        20 ms ( 20000 μs)
    SENSOR_DELAY_UI          60 ms ( 60000 μs)
    SENSOR_DELAY_NORMAL     200 ms (200000 μs)

そして、0~3 以外の値であれば、その値が直接遅延時間として採用される。


(7)(8) アクティビティがバックグランドに隠れる直前に、センサーのリスナーを解除す
る

    public void onPause() {                                            // (7)

onPause() メソッドは、アクティビティがバックグランドに隠れる直前(他のアクティビ
ティが起動、たとえば、着信があった、電話をかける)に呼ばれる。
センサーが動いていれば、その分、電池が消耗するので、隠れるときにはセンサーをいっ
たん停止させる。

    sensorManager.unregisterListener(sensorEventListener);            // (8)

解除には、
void unregisterListener(SensorEventListener listener, Sensor sensor)
void unregisterListener(SensorEventListener listener)
を使う。sensor の指定がなければ、リスナーが登録されているすべてのセンサーから解
除する。


□ LightSensorListener.java
---
package jp.marunomaruno.android.sample;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.widget.TextView;

/**
 * 光センサーのリスナー
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public class LightSensorListener implements SensorEventListener {       // (1)

    protected TextView textView;

    public LightSensorListener(TextView textView) {
        this.textView = textView;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {                    // (2)
        // 値を取得する
        float x = event.values[0];                                      // (3)

        // TextViewに表示する
        textView.setText(String.format(
                textView.getResources().getString(R.string.sensor_value_format),
 
                textView.getResources().getString(R.string.light), 
                event.sensor.getName(), 
                x, 
                textView.getResources().getString(R.string.lightUnit)
        ));
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {        // (4)
        assert true; // 何もしない
    }
}
---

(1) 光センサーのリスナーの定義

public class LightSensorListener implements SensorEventListener {       // (1)


センサーに変化があったときに使うリスナー・クラスを定義する。

SensorEventListener

センサーの値が変わったときに呼び出されるリスナーのインターフェース

・メソッド
---
abstract void onAccuracyChanged(Sensor sensor, int accuracy)    
    センサーの精度が変わったとき
abstract void onSensorChanged(SensorEvent event)                
    センサーからの値が変わったとき
---


(2)(3) センサーの値が変化したときに呼ばれるハンドラー・メソッドとそのときの値の取
得

    public void onSensorChanged(SensorEvent event) {                // (2)
    float x = event.values[0];                                      // (3)

引数の event から、値を取得する。
光センサーは、1次元の値を取得するので、values は、要素数 1 である。

SensorEvent

センサーから生成されたイベントを表すクラス。

・クラス階層
java.lang.Object
   + android.hardware.SensorEvent

・public フィールド
---
public       int      accuracy     精度
public       Sensor   sensor       このイベントを生成したセンサー
public       long     timestamp    イベントが起きたタイムスタンプ
public final float[]  values       値。配列の長さは、値の次元数
---


(4) センサーの精度が変更されると呼ばれるハンドラー・メソッド

    public void onAccuracyChanged(Sensor sensor, int accuracy) {        // (4)

通常は、このメソッドが使われることはない(らしい)。


□ res/layout/main.xml
---
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
<!-- センサー値 -->    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/light"
    android:id="@+id/sensor_value"
    />
    
</LinearLayout>
---


□ res/values/strings.xml
---
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">LightSensor01</string>
    <string name="light">光</string>
    <string name="lightUnit">lux</string>
    <string name="sensor_value_format">%1$s: %2$s = %3$.2f (%4$s)</string>
</resources>
---

センサーの値は、次の形式で表示する。
    センサー名: オブジェクトの情報 = 値 (単位)


■ 加速度センサーの値を表示する

加速度センサーの値を取得して、表示する。

加速度センサーは、3 次元の値として取得する。単位は、m/s^2。
値は、SensorEvent の次のフィールドを使って取得する。
    values[0]: X 軸方向の加速度
    values[1]: Y 軸方向の加速度
    values[2]: Z 軸方向の加速度

    X 軸: 実機の横方向(右方向が正)
    Y 軸: 実機のたて方向(上方向が正)
    Z 軸: 実機の前面方向(前面方向が正)

なお、SensorEvent クラスの API に図入りで説明がある。


□ AcceleraterSensor01Activity.java
---
package jp.marunomaruno.android.sample;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

/**
 * 加速度センサーの値を表示する。
 * 
 * @author marunomaruno
 * @version 1.0, 2011-06-25
 */
public class AcceleraterSensor01Activity extends Activity {

    // TextView
    private TextView acceleraterTextView; // 加速度センサー

    private SensorManager sensorManager;
    private SensorEventListener sensorEventListener; 
                // onPause()が呼ばれたときに、すべてのリスナーを解除するため

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        acceleraterTextView = (TextView) findViewById(R.id.sensor_value);
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // 加速度センサーを取得して登録する
        sensorEventListener = new AcceleraterSensorListener(
                                                    acceleraterTextView); // (1)

        for (Sensor sensor : sensorManager.getSensorList(
                    Sensor.TYPE_ACCELEROMETER)) {                         // (2)
            sensorManager.registerListener(sensorEventListener, sensor,
                    SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    @Override
    public void onPause() {
        super.onPause();

        // すべてのリスナーを解除する
        sensorManager.unregisterListener(sensorEventListener);
    }
}
---

(1)(2) 加速度センサーを取得して登録

    sensorEventListener = new AcceleraterSensorListener(acceleraterTextView);
 // (1)

加速度センサーのオブジェクトを生成する。

    for (Sensor sensor : sensorManager.getSensorList(
                            Sensor.TYPE_ACCELEROMETER)) { // (2)

加速度センサーのデバイスのオブジェクトを取得する。これには、定数 
TYPE_ACCELEROMETER を使う。


□ AcceleraterSensorListener.java
---
package jp.marunomaruno.android.sample;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.widget.TextView;

/**
 * 加速度センサーのリスナー
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public class AcceleraterSensorListener implements SensorEventListener {

    protected TextView textView;

    public AcceleraterSensorListener(TextView textView) {
        this.textView = textView;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // 値を取得する
        float x = event.values[0];                            // (1)
        float y = event.values[1];                            // (2)
        float z = event.values[2];                            // (3)

        // TextViewに表示する
        textView.setText(String.format(
                textView.getResources().getString(R.string.sensor_value_format),
 
                textView.getResources().getString(R.string.accelerater), 
                event.sensor.getName(), 
                x, y, z, 
                textView.getResources().getString(R.string.acceleraterUnit)
                ));
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        assert true; // 何もしない
    }
}
---

(1)(2)(3) センサーの値を取得

        float x = event.values[0];                            // (1)
        float y = event.values[1];                            // (2)
        float z = event.values[2];                            // (3)

加速度センサーは 3 次元の値を持つので、values は要素数 3 の配列になる。それぞれ、
x, y, z として取得する。


□ res/layout/main.xml
---
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
<!-- センサー値 -->    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/accelerater"
    android:id="@+id/sensor_value"
    />
    
</LinearLayout>
---


□ res/values/strings.xml
---
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">AcceleraterSensor01</string>
    <string name="accelerater">加速度</string>
    <string name="acceleraterUnit">m/s^2</string>
    <string name="sensor_value_format">%1$s: %2$s = (X, Y, Z) = (%3$.2f, %4$.2f,
 %5$.2f) (%6$s)</string>
</resources>
---



最新の画像もっと見る

コメントを投稿