goo blog サービス終了のお知らせ 

marunomaruno-memo

marunomaruno-memo

[Android] センサー (2) いろいろなセンサー

2011年09月17日 | Android
センサー (2) いろいろなセンサー
================================================================================

■ 各種センサーの値を取得する

Android2.2 と DELL の実機で使えるセンサーをすべて確認する。これは、センサー(1) 
http://blog.goo.ne.jp/marunomarunogoo/d/20110828 
の「○」がついているセンサーの値を取得して表示するアプリケーション。

ソースは以下のとおり。
SensorValue01Activity.java    
    各種センサーの値を表示するアクティビティ・クラス

SensorEventListenerAdapter.java
    TextViewを保持するセンサー・リスナーのアダプタークラス
OneDimensionalSensorListenerAdapter.java    
    1 次元の値を取得するセンサー・リスナーのアダプタークラス
ThreeDimensionalSensorListenerAdapter.java    
    3 次元の値を取得するセンサー・リスナーのアダプタークラス

AcceleraterSensorListener.java      加速度センサーリスナー       3 次元値
GyroscopeSensorListener.java        ジャイロ・センサー・リスナー   3 次元値
LightSensorListener.java            光センサー・リスナー          1 次元値
MagneticFieldSensorListener.java    地磁気センサー・リスナー      3 次元値
PressureSensorListener.java         圧力センサー・リスナー        1 次元値
ProximitySensorListener.java        近接センサー・リスナー        1 次元値
TemperatureSensorListener.java      温度センサー・リスナー        1 次元値


少し複雑な階層の関係になっているが、基本は、1 次元の値を取得するセンサー系と、3 
次元の値を取得するセンサー系に分かれる。これらに対するリスナーのアダプタークラス
を用意して、それぞれのセンサー・リスナーは、このアダプター・クラスのサブクラスとし
て作る。なお、1次元系と3次元系もほぼ同じ形式になっているので、このスーパークラス
 SensorEventListenerAdapter を準備する。


◆ アクティビティのクラス。

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

import java.util.ArrayList;
import java.util.List;

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

/**
 * Android2.2でサポートされているセンサーの状態を表示する。
 * @author marunomaruno
 * @version 1.0, 2011-06-25
 */
public class SensorValue01Activity extends Activity {

    // TextView
    private TextView acceleraterTextView; // 加速度センサー   // (1)
    private TextView gravityTextView; // 重力センサー
    private TextView gyroscopeTextView; // ジャイロスコープセンサー
    private TextView lightTextView; // 光センサー
    private TextView linearAccelerationTextView; // 線形加速度センサー
    private TextView magneticFieldTextView; // 地磁気センサー
    private TextView pressureTextView; // 圧力センサー
    private TextView proximityTextView; // 近接センサー
    private TextView rotationVectorTextView; // 回転ベクトルセンサー
    private TextView temperatureTextView; // 温度センサー

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

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

        acceleraterTextView = (TextView) findViewById(R.id.accelerater); // (4)
        gravityTextView = (TextView) findViewById(R.id.gravity);
        gyroscopeTextView = (TextView) findViewById(R.id.gyroscope);
        lightTextView = (TextView) findViewById(R.id.light);
        linearAccelerationTextView = (TextView) findViewById(R.id.linearAcceleration);
        magneticFieldTextView = (TextView) findViewById(R.id.magneticField);
        pressureTextView = (TextView) findViewById(R.id.pressure);
        proximityTextView = (TextView) findViewById(R.id.proximity);
        rotationVectorTextView = (TextView) findViewById(R.id.rotationVector);
        temperatureTextView = (TextView) findViewById(R.id.temperature);

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);// (5)
        sensorEventListenerList = new ArrayList<SensorEventListener>();  // (6)
    }

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

        // 加速度センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_ACCELEROMETER,
                new AcceleraterSensorListener(acceleraterTextView),
                R.string.accelerater);                                  // (7)

        // ジャイロスコープ・センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_GYROSCOPE,
                new GyroscopeSensorListener(gyroscopeTextView),
                R.string.gyroscope);

        // 光センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_LIGHT, new LightSensorListener(
                lightTextView), R.string.light);

        // 地磁気センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_MAGNETIC_FIELD,
                new MagneticFieldSensorListener(magneticFieldTextView),
                R.string.magneticField);

        // 圧力センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_PRESSURE,
                new PressureSensorListener(pressureTextView), R.string.pressure);

        // 近接センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_PROXIMITY,
                new ProximitySensorListener(proximityTextView),
                R.string.proximity);

        // 温度センサーを取得して登録する
        getSensorAndAddToListener(Sensor.TYPE_TEMPERATURE,
                new TemperatureSensorListener(temperatureTextView),
                R.string.temperature);

        // Android2.2での未サポートセンサー
        gravityTextView.setText(String.format(
                getString(R.string.not_support_format) + "\n",
                getString(R.string.gravity)));                         // (8)
        linearAccelerationTextView.setText(String.format(
                getString(R.string.not_support_format) + "\n",
                getString(R.string.linearAcceleration)));
        rotationVectorTextView.setText(String.format(
                getString(R.string.not_support_format) + "\n",
                getString(R.string.rotationVector)));
    }

    /**
     * センサーを取得して、リスナーを設定する。
     * @param type センサーのタイプ
     * @param listener 設定するべきリスナー
     * @param name センサー名のID
     */
    private void getSensorAndAddToListener(int type,
            SensorEventListenerAdapter listener, int name) {           // (9)
        List<Sensor> sensors = sensorManager.getSensorList(type);      // (10)
        if (sensors.size() > 0) {
            sensorEventListenerList.add(listener);                     // (11)
            for (Sensor sensor : sensors) {
                sensorManager.registerListener(listener, sensor,
                        SensorManager.SENSOR_DELAY_NORMAL);            // (12)
            }

        } else {
            listener.getTextView().setText(
                    String.format(getString(R.string.no_sensor_format) + "\n",
                            getString(name)));                        // (13)
        }
    }

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

        // すべてのリスナーを解除する
        for (SensorEventListener listener : sensorEventListenerList) {
            sensorManager.unregisterListener(listener);               // (14)
        }
    }

}
---

(1)(4) 各種センサーから取得した値を表示するためのテキストビューを宣言する。

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

    acceleraterTextView = (TextView) findViewById(R.id.accelerater); // (4)


(2)(5) SensorManager を宣言する。

    private SensorManager sensorManager;                             // (2)
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);// (5)


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

    private List<SensorEventListener> sensorEventListenerList; 
        // onPause()が呼ばれたときに、すべてのリスナーを解除するため // (3)
    sensorEventListenerList = new ArrayList<SensorEventListener>();  // (6)


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

    sensorManager.unregisterListener(listener);               // (14)


(7)、(9)~(13) センサーのデバイスを取得して、そのリスナーと紐付ける

    getSensorAndAddToListener(Sensor.TYPE_ACCELEROMETER,
                new AcceleraterSensorListener(acceleraterTextView),
                R.string.accelerater);                               // (7)

これは、自分で定義したプライベート・メソッドを呼び出す。
メソッドの詳細は、(9)~(13) を参照のこと。


    private void getSensorAndAddToListener(int type,
            SensorEventListenerAdapter listener, int name) {           // (9)

メソッドの宣言。センサーのタイプ type を受け取り、そのタイプのリスナーをリスト 
listener に入れて戻す。そのとき、そのセンサーが実機にない場合は、センサー名の ID
 name を基に、メッセージを出す。


    List<Sensor> sensors = sensorManager.getSensorList(type);      // (10)

センサーのタイプ type を基に、センサーを取得する。引数の type は、センサーの種類
を表す定数で、Sensor クラスに定数が定義されている。


    sensorEventListenerList.add(listener);                     // (11)

(10) で取得したセンサーをリストに登録する。このとき、センサーがなければ、リスト
には登録しないので、まずはリスナーを登録する。

    sensorManager.registerListener(listener, sensor,
             SensorManager.SENSOR_DELAY_NORMAL);            // (12)

センサーをリスナーに登録する。

    getString(name)));                        // (13)

センサーがない場合に、センサー名を取得する。name はりソース ID。


(8) センサーがサポートされていないとき、その旨のメッセージを表示する。

    gravityTextView.setText(String.format(
            getString(R.string.not_support_format) + "\n",
            getString(R.string.gravity)));                         // (8)


◆ センサーのリスナーに対するアダプターのクラス。

SensorEventListener インターフェースを実装する。これは、
SensorEventListenerAdapter クラスとするが、実際にはセンサーから取得する値は、1次
元のパターンと3次元のパターンがある。そのため、共通のメンバーを持つスーパークラ
ス SensorEventListenerAdapter をつくり、それぞれの次元の値を表示する用のサブクラ
スとして、OneDimensionalSensorListenerAdapter クラスと 
ThreeDimensionalSensorListenerAdapter クラスをつくる。実際のセンサーに対するリス
ナー・クラスは、このいずれかのクラスを継承する。

SensorEventListenerAdapter クラスは、インスタンス変数として、センサーから取得し
た値を表示するテキスト・ビューを持つ。
また、実装すべきメソッドのうち、onAccuracyChanged() を実装するが、中は何もしてい
ない。

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

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

/**
 * リスナー用アダプター
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public abstract class SensorEventListenerAdapter implements SensorEventListener {    // (1)

    protected TextView textView;    // (2)

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

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

    public TextView getTextView() {
        return textView;
    }
}
---

(1) センサー・リスナー・インターフェースのアダプター・クラス

SensorEventListener インターフェースを実装する。

    public abstract class SensorEventListenerAdapter implements SensorEventListener {    // (1)


(2) 取得した値を表示するためのテキストビュー・オブジェクト

    protected TextView textView;    // (2)


(3)、(4) センサーの精度が変わったときのハンドラー・メソッドの実装

メソッドとしては、何もしない。ここでは、何もしないことを明記するため、
    assert true;
を使っている。

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


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

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

/**
 * 1次元の値のリスナー用アダプター
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public abstract class OneDimensionalSensorListenerAdapter extends
        SensorEventListenerAdapter {    // (1)

    public OneDimensionalSensorListenerAdapter(TextView textView) {
        super(textView);
    }

    /**
     * センサーの値をTextViewに表示する。
     * @param event センサー・イベント
     * @param name センサー名のリソースID
     * @param unit 単位名のリソースID
     */
    public void out(SensorEvent event, int name, int unit) {
        // 値を取得する
        float x = event.values[0];    // (2)

        // TextViewに表示する
        textView.setText(String.format(
                textView.getResources().getString(R.string.sensor_1d_value_format) + "\n", 
                textView.getResources().getString(name), 
                event.sensor.getName(), 
                textView.getResources().getString(unit),
                event.sensor.getPower(),
                x
                ));
    }
}
---

(1) 1次元用のアダプター・クラス

public abstract class OneDimensionalSensorListenerAdapter extends
        SensorEventListenerAdapter {    // (1)

(2) センサーからの値を取得

    float x = event.values[0];    // (2)

今回は、1次元の値なので、values[0] のみを取得。


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

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

/**
 * 3次元の値のリスナー用アダプター
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public abstract class ThreeDimensionalSensorListenerAdapter extends
        SensorEventListenerAdapter {    // (1)

    public ThreeDimensionalSensorListenerAdapter(TextView textView) {
        super(textView);
    }

    /**
     * センサーの値をTextViewに表示する。
     * @param event センサー・イベント
     * @param name センサー名のリソースID
     * @param unit 単位名のリソースID
     */
    public void out(SensorEvent event, int name, int unit) {
        // 値を取得する
        float x = event.values[0];    // (2)
        float y = event.values[1];    // (3)
        float z = event.values[2];    // (4)

        // TextViewに表示する
        textView.setText(String.format(
                textView.getResources().getString(R.string.sensor_3d_value_format) + "\n", 
                textView.getResources().getString(name), 
                event.sensor.getName(), 
                textView.getResources().getString(unit),
                event.sensor.getPower(),
                x, y, z
            ));
    }
}
---

(1) 3 次元用のアダプター・クラス

public abstract class ThreeDimensionalSensorListenerAdapter extends
        SensorEventListenerAdapter {    // (1)

(2)~(4) センサーからの値を取得

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

今回は、3 次元の値なので、values[0]~values[2] を取得。


◆ センサーのリスナーのクラス。

それぞれのセンサーに対するリスナーのクラス。
取得する値が 1 次元か、3 次元かによって、OneDimensionalSensorListenerAdapter ク
ラスか ThreeDimensionalSensorListenerAdapter クラスを継承する。


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

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

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

    public AcceleraterSensorListener(TextView textView) {
        super(textView);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {    // (2)
        out(event, R.string.accelerater, R.string.acceleraterUnit);
    }
}
---

(1) 加速度センサーのハンドラー・クラス

    public class AcceleraterSensorListener extends
        ThreeDimensionalSensorListenerAdapter {    // (1)

3次元値なので、ThreeDimensionalSensorListenerAdapter クラスを継承する。


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

    public void onSensorChanged(SensorEvent event) {    // (2)


□ GyroscopeSensorListener.java

3次元の値なので、AcceleraterSensorListener.java と同じパターン


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

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

/**
 * 光センサーのリスナー
 * @author maruno
 * @version 1.0, 2011-06-23
 * @since 1.0
 */
public class LightSensorListener extends OneDimensionalSensorListenerAdapter {

    public LightSensorListener(TextView textView) {
        super(textView);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        out(event, R.string.light, R.string.lightUnit);
    }
}
---

□ MagneticFieldSensorListener.java
3 次元の値なので、AcceleraterSensorListener.java と同じパターン


□ PressureSensorListener.java

1 次元の値なので、LightSensorListener.java と同じパターン


□ ProximitySensorListener.java

1 次元の値なので、LightSensorListener.java と同じパターン


□ TemperatureSensorListener.java

1 次元の値なので、LightSensorListener.java と同じパターン


■ レイアウト

□ res/layout/main.xml
---

<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/accelerater"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/gravity"
    android:id="@+id/gravity"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/gyroscope"
    android:id="@+id/gyroscope"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/light"
    android:id="@+id/light"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/magneticField"
    android:id="@+id/magneticField"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/linearAcceleration"
    android:id="@+id/linearAcceleration"
    />

    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/pressure"
    android:id="@+id/pressure"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/proximity"
    android:id="@+id/proximity"
    />
    

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/rotationVector"
    android:id="@+id/rotationVector"
    />
    
    
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/temperature"
    android:id="@+id/temperature"
    />
    
</LinearLayout>
---


■ 文字列の定数

□ プログラム中での取得

ここに文字列の名前と値を
    <string name="名前">値</string>
というように定義しておくと、プログラムの中では、
    R.string.名前
でその文字列のIDを取得できる。
そのIDをつかって、ActivityクラスのgetString()メソッドを使えば、文字列の値を取得
できる。したがって、Activityクラスのサブクラスでは、
    getString(R.string.名前)
とすれば、名前に対する文字列の値を取得できる。

また、Activityクラスのサブクラスでない場合、たとえば、リスナークラスで使いたいと
きは、Resoucesオブジェクトを取得して、その中のgetString()メソッドを使う。
Resoucesオブジェクトは、resディレクトリーをカプセル化したオブジェクトである。
Resoucesオブジェクトの取得は、たとえば、Viewクラスであれば、
    getResources()
メソッドがある。したがって、
    textView.getResources().getString(R.string.名前)
で、名前に対する文字列の値を取得できる。


□ res/values/string.xml

センサーの名前と合わせて、そのセンサーで取得する値の単位も定義した。

---

<resources>
    <string name="app_name">SensorValue01</string>
    <string name="accelerater">加速度</string>
    <string name="acceleraterUnit">m/s^2</string>
    <string name="gravity">重力</string>
    <string name="gravityUnit">m/s^2</string>
    <string name="gyroscope">ジャイロ</string>
    <string name="gyroscopeUnit">rad/s</string>
    <string name="light">光</string>
    <string name="lightUnit">lux</string>
    <string name="magneticField">地磁気</string>
    <string name="magneticFieldUnit">uT</string>
    <string name="linearAcceleration">線形加速度</string>
    <string name="linearAccelerationUnit">m/s^2</string>
    <string name="pressure">圧力</string>
    <string name="pressureUnit">Pa</string> 
    <string name="proximity">近接</string>
    <string name="proximityUnit">cm</string>
    <string name="rotationVector">回転ベクトル</string>
    <string name="rotationVectorUnit">-</string> 
    <string name="temperature">温度</string>
    <string name="temperatureUnit">℃</string> 
    <string name="sensor_1d_value_format">
                %1$s: %2$s = %5$.2f (%3$s), 消費バッテリー = %4$.6f mA</string>
    <string name="sensor_3d_value_format">
    %1$s: %2$s = (X, Y, Z) = (%5$.2f, %6$.2f, %7$.2f) (%3$s), 消費バッテリー = %4$.6f mA
    </string>
    <string name="not_support_format">
                Android2.2 では、%s センサーはサポートされていません。</string>
    <string name="no_sensor_format">%s センサーはありません。</string>
</resources>
---




leJOS カラーセンサー (0.9)

2011年09月10日 | Android
leJOS カラーセンサー                                                       (0.9)
================================================================================

※ この記事は leJOS 0.9 で確認しています。

LEGO Mindstoms NXT で、カラーセンサーを使うことができます。
ただし、カラーセンサーは別売です。
カラーセンサーを使うのは、他のセンサーと同じく、

1. センサーのオブジェクトを生成

2. センサーのオブジェクトから、値を取得

の手順です。ただし、他のセンサーと違うのは、カラーは、RGB という 3 つの値からな
るので、基本データ型による色の取得ではなく、Color オブジェクトで取得し、それぞれ
の R 値、G 値、B 値、は、この Color オブジェクトからさらに取得する、という点です。

■ ColorSensor01.java
---
import lejos.nxt.Button;
import lejos.nxt.ColorSensor;
import lejos.nxt.SensorPort;
import lejos.nxt.ColorSensor.Color;

/**
 * エンターをたたく度に色を取得する。
 * 
 * @author marunomaruno
 * @version 1.0, 2011/08/27
 * @since 1.0
 */
public class ColorSensor01 {

    /**
     * 色IDに対応した色名の配列。
     * ただし、使用する場合は、IDに1を加える。(NONEが-1なため。)
     */
    public static final String[] COLOR_NAMES = new String[] {     // (1)
            "-",            // NONE
            "RED", 
            "GREEN", 
            "BLUE",
            "YELLOW", 
            "MAGENTA", 
            "ORANGE", 
            "WHITE", 
            "BLACK", 
            "PINK",
            "GRAY", 
            "LIGHT_GRAY", 
            "DARK_GRAY", 
            "CYAN", 
    };

    public static void main(String[] args) throws Exception {

        // 色センサーオブジェクトをポート3で生成する。
        ColorSensor colorSensor = new ColorSensor(SensorPort.S3);    // (2)
        
        // センサー安定化のため、しばらく待つ
        Thread.sleep(500);

        // Enterでループする
        while (Button.waitForPress() == Button.ENTER.getId()) {
            Color color = colorSensor.getColor();    // (3)
            int red = color.getRed();    // (4)
            int blue = color.getBlue();    // (4)
            int green = color.getGreen();    // (4)
            int id = colorSensor.getColorID();    // (5)
            System.out.print(
                      Integer.toHexString(red) + " "
                    + Integer.toHexString(green) + " "
                    + Integer.toHexString(blue) + " " 
                    + id + " " + COLOR_NAMES[id + 1]
            );
            System.out.println();
        }
    }
}
---

■ 実行結果例
---
3b 3f 30 7 BLACK
1c 0 0 7 BLACK
a0 85 d0 2 BLUE
f8 85 9e 0 RED
e4 f1 9b 1 GREEN
115 ee 9b 3 YELLOW
0 0 0 7 BLACK
110 f8 f7 6 WHITE
eb bf 8f 6 WHITE
---
※ 左から、赤、緑、青の値。次が色ID。最後が色ID に対応した色名


(1) センサーで取得できる色に対応する色名の配列

    public static final String[] COLOR_NAMES = new String[] {     // (1)
            "-",                    // NONE
            "RED", 
            "GREEN", 
            "BLUE",
            "YELLOW", 
            "MAGENTA", 
            "ORANGE", 
            "WHITE", 
            "BLACK", 
            "PINK",
            "GRAY", 
            "LIGHT_GRAY", 
            "DARK_GRAY", 
            "CYAN", 
    };


これらの定数は、ColorSensor クラスの内部クラス Color クラスで宣言されています。
実際には、lejos.robotics.Color クラスのものを使っています。
センサーでは、この配列に対するインデックスは、
     int     getColorID() 
メソッドを使って取得します。RED から CYAN まで、0 から 12 で宣言されています。ま
た、NONE は、-1 なので、この配列上では、一番先頭に設定しています。
したがって、この配列を使って色名を取得する場合は、getColorID() メソッドの結果に 
1 を加えたものを使用する必要があります。

lejos.robotics.Color の色を表す定数
---
public static final int BLACK       7
public static final int BLUE        2
public static final int CYAN       12
public static final int DARK_GRAY  11
public static final int GRAY        9
public static final int GREEN       1
public static final int LIGHT_GRAY 10
public static final int MAGENTA     4
public static final int NONE       -1
public static final int ORANGE      5
public static final int PINK        8
public static final int RED         0
public static final int WHITE       6
public static final int YELLOW      3
---


(2) カラーセンサーのオブジェクトを取得

    ColorSensor colorSensor = new ColorSensor(SensorPort.S3);    // (2)

センサーをつなげているポート番号を基に取得します。

・ColorSensor

・クラス階層
java.lang.Object
  extended by lejos.nxt.ColorSensor

・内部クラス
static class  ColorSensor.Color 

・コンストラクター
---
ColorSensor(SensorPort port)
ColorSensor(SensorPort port, int color)
---

・主なメソッド
---
 ColorSensor.Color getColor()                色を取得する
 int               getColorID()              色ID を取得する(-1, 0-12)
 boolean           setFloodlight(int color)  ライトを点灯する
---


(3) センサーから色を取得

    Color color = colorSensor.getColor();    // (3)

色は、ColorSensor.Color クラスのオブジェクトとして取得します。

・ColorSensor.Color クラス

・クラス階層
java.lang.Object
  extended by lejos.robotics.Color
      extended by lejos.nxt.ColorSensor.Color

・定数
---
BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, NONE, 
ORANGE, PINK, RED, WHITE, YELLOW
---

・コンストラクター
---
ColorSensor.Color(int red, int green, int blue, int background, int colorId) 
---

・メソッド
---
 int  getBackground()  背景光のレベルを取得する
 int  getBlue()        RGBのうち、青値を取得する(0-255)
 int  getColor()
 int  getGreen()       RGBのうち、緑値を取得する(0-255)
 int  getRed()         RGBのうち、赤値を取得する(0-255)
---


(4) Color オブジェクトから、それぞれの原色の値を取得

    int red = color.getRed();    // (4)
    int blue = color.getBlue();    // (4)
    int green = color.getGreen();    // (4)


(5) センサーから、色についた ID を取得

    int id = colorSensor.getColorID();    // (5)

この色ID をインデックスとして、(1) で定義している定数の配列 COLOR_NAMES から、色
の名前を取得します。



[C] 可変長引数

2011年09月03日 | C / C++
                                                                2012-08-25 更新
可変長引数
================================================================================

C 言語での可変長引数を持つ関数の定義は、以下のようにする。

1. 仮引数は、最初の引数に続いて、「...」を続ける

2. 次の    va_list 型の変数を定義して、これを使う。
    va_list list;

3. 可変長引数を使う準備する
    va_start(list, 最初の仮引数);

4. 引数を取得する
    va_arg(list, 仮引数のデータ型)

5. 可変長引数の処理を終了する
    va_end(list);


□ va_func.c
---
/*
 * 可変長引数を確認するサンプル。
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int va_func(const char* types, ...);    // (1)

int main(void) {
    va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78);    // (2)

    return EXIT_SUCCESS;
}

/**
 * 可変長引数を受け取り、フォーマットにしたがって表示する。
 * @param types 引数のデータ型
 *                     i: int 型
 *                     d: double 型
 *                     c: char 型
 *                     s: char* 型
 *     @return 正しく表示できた引数の数
 */
int va_func(const char* types, ...) {
    const char* type;
    int count = 0;

    va_list list;    // (3)
    va_start(list, types);    // (4)

    for (type = types; *type != '
2012-08-25 更新
可変長引数
================================================================================

C 言語での可変長引数を持つ関数の定義は、以下のようにする。

1. 仮引数は、最初の引数に続いて、「...」を続ける

2. 次の va_list 型の変数を定義して、これを使う。
va_list list;

3. 可変長引数を使う準備する
va_start(list, 最初の仮引数);

4. 引数を取得する
va_arg(list, 仮引数のデータ型)

5. 可変長引数の処理を終了する
va_end(list);


□ va_func.c
---
/*
* 可変長引数を確認するサンプル。
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

int va_func(const char* types, ...); // (1)

int main(void) {
va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2)

return EXIT_SUCCESS;
}

/**
* 可変長引数を受け取り、フォーマットにしたがって表示する。
* @param types 引数のデータ型
* i: int 型
* d: double 型
* c: char 型
* s: char* 型
* @return 正しく表示できた引数の数
*/
int va_func(const char* types, ...) {
const char* type;
int count = 0;

va_list list; // (3)
va_start(list, types); // (4)

for (type = types; *type != '\0'; type++) {
switch (*type) {
case 'i':
printf(" int: %d\n", va_arg(list, int)); // (5)
count++;
break;

case 'd':
printf("double: %f\n", va_arg(list, double)); // (5)
count++;
break;

case 'c':
printf(" char: %c\n", (char) va_arg(list, int)); // (5)
count++;
break;

case 's':
printf("string: %s\n", va_arg(list, char*)); // (5)
count++;
break;

default:
printf("(bad type)\n");
va_arg(list, void*); // 空読みする // (5)
break;
}
}

va_end(list); // (6)

return count;
}
---

□ 実行結果
---
int: 12
double: 3.140000
char: A
string: Hello
(bad type)
int: -78
---

(1) 可変長引数の関数のプロトタイプ宣言

int va_func(const char* types, ...); // (1)

仮引数は少なくてもひとつは必ず書く。次のように、仮引数がひとつもないとコンパイル
エラーになる。
int va_func2(...); // コンパイルエラー


(2) 関数の呼び出し

va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2)

最初の引数が文字列であれば、あとは任意の型をいくつでも引数に取れる。
ただし、今回は、この va_func() の仕様として、文字列中で使用できる文字は、i, d, c,
s のいずれかで、これに対応した型として、引数の中で使用できるのは、int, double,
char, char* だけである。


(3) va_list 型の変数を定義

va_list list; // (3)

この変数は、これ以降の処理で使う。


(4) 可変長引数の処理の開始

va_start(list, types); // (4)

2番目の引数は、関数宣言の、可変長引数の直前の引数を使う。


(5) 仮引数の取得

printf(" int: %d\n", va_arg(list, int)); // (5)
printf("double: %f\n", va_arg(list, double)); // (5)
printf(" char: %c\n", (char) va_arg(list, int)); // (5)
printf("string: %s\n", va_arg(list, char*)); // (5)
va_arg(list, void*); // 空読みする // (5)

仮引数は、va_arg() を使う。

va_arg(v,l)
v: va_list 型の変数
l: 取得したい仮引数のデータ型

なお、つぎの型char は指定できず、警告が出る。実行すると、プログラムはアボートす
る。したがって、対応する型を指定して、キャストする。
char -> int
short -> int
float -> double

また、空読みするときは void* とする。void だと、読み捨てたい引数すら読まれない。


(6) 可変長引数の処理の終了

va_end(list); // (6)

'; type++) { switch (*type) { case 'i': printf(" int: %d\n", va_arg(list, int)); // (5) count++; break; case 'd': printf("double: %f\n", va_arg(list, double)); // (5) count++; break; case 'c': printf(" char: %c\n", (char) va_arg(list, int)); // (5) count++; break; case 's': printf("string: %s\n", va_arg(list, char*)); // (5) count++; break; default: printf("(bad type)\n"); va_arg(list, void*); // 空読みする // (5) break; } } va_end(list); // (6) return count; } --- □ 実行結果 --- int: 12 double: 3.140000 char: A string: Hello (bad type) int: -78 --- (1) 可変長引数の関数のプロトタイプ宣言 int va_func(const char* types, ...); // (1) 仮引数は少なくてもひとつは必ず書く。次のように、仮引数がひとつもないとコンパイル エラーになる。 int va_func2(...); // コンパイルエラー (2) 関数の呼び出し va_func("idcsxi", 12, 3.14, 'A', "Hello", 56, -78); // (2) 最初の引数が文字列であれば、あとは任意の型をいくつでも引数に取れる。 ただし、今回は、この va_func() の仕様として、文字列中で使用できる文字は、i, d, c, s のいずれかで、これに対応した型として、引数の中で使用できるのは、int, double, char, char* だけである。 (3) va_list 型の変数を定義 va_list list; // (3) この変数は、これ以降の処理で使う。 (4) 可変長引数の処理の開始 va_start(list, types); // (4) 2番目の引数は、関数宣言の、可変長引数の直前の引数を使う。 (5) 仮引数の取得 printf(" int: %d\n", va_arg(list, int)); // (5) printf("double: %f\n", va_arg(list, double)); // (5) printf(" char: %c\n", (char) va_arg(list, int)); // (5) printf("string: %s\n", va_arg(list, char*)); // (5) va_arg(list, void*); // 空読みする // (5) 仮引数は、va_arg() を使う。 va_arg(v,l) v: va_list 型の変数 l: 取得したい仮引数のデータ型 なお、つぎの型char は指定できず、警告が出る。実行すると、プログラムはアボートす る。したがって、対応する型を指定して、キャストする。 char -> int short -> int float -> double また、空読みするときは void* とする。void だと、読み捨てたい引数すら読まれない。 (6) 可変長引数の処理の終了 va_end(list); // (6)