Android* 開発者向けラーニングシリーズ 4: Android* タブレットセンサー
この記事は、インテル® デベロッパー・ゾーンに掲載されている「Intel for Android* Developers Learning Series #4: Android Tablet Sensors」の日本語参考訳です。
概要
このガイドは、アプリケーション開発者に Android* センサー・フレームワークを紹介し、インテル® Atom™ プロセッサー・ベースのタブレットで一般的に利用可能なセンサーの使用法について詳しく述べます。ここでは、モーションセンサー、ポジションセンサー、および環境センサーについて説明します。GPS は厳密にはセンサーではありませんが、ここでは GPS ベースの位置情報サービスについても紹介します。
1. インテル® Atom™ プロセッサー・ベースの Android* タブレットのセンサー
インテル® Atom™ プロセッサー・ベースのタブレットは、さまざまなハードウェア・センサーをサポートすることができます。これらのセンサーを使用して、動きや位置の変化を検出したり、周辺環境パラメーターが得られます。図 1 のブロック図は、一般的なインテル® Atom™ プロセッサー・ベースのAndroid* タブレットで利用可能なセンサーの設定を示したものです。
タブレットセンサーは、センサーデータに基づいて、表 4.1 のクラスとタイプに分類することができます。
表 4.1 Android* プラットフォームでサポートされるセンサーのタイプ
ポジションセンサー
|
(TYPE_ACCELEROMETER) |
デバイスの加速度を m/s2 単位で計測します。 |
動き検出 |
ジャイロスコープ (TYPE_GYROSCOPE) |
デバイスの回転速度を計測します。 |
回転検出 |
|
磁力計 (TYPE_MAGNETIC_FIELD) |
磁力の大きさを µT 単位で計測します。 |
コンパス |
|
近接 (TYPE_PROXIMITY) |
オブジェクトの近接度合いを cm 単位で計測します。 |
近接オブジェクト検出 |
|
GPS (android.hardware.Sensor のタイプではない) |
デバイスの正確な地理的位置を取得します。 |
正確な地理的位置検出 |
|
環境センサー |
ALS (TYPE_LIGHT) |
環境光レベルを lx 単位で計測します。 |
画面の自動明るさ制御 |
2. Android* センサー・フレームワーク
Android* センサー・フレームワークは、GPS を除くセンサーとそのデータを利用するためのメカニズムを提供します。GPS は、Android* の位置情報サービスを通して利用できます。詳しくは後述します。センサー・フレームワークは、android.hardware パッケージに含まれています。表 4.2 は、センサー・フレームワークの主なクラスとインターフェイスのリストです。
表 4.2 Android* プラットフォームのセンサー・フレームワーク
名前 |
タイプ |
説明 |
SensorManager |
クラス |
センサーサービスのインスタンスの作成に使用します。センサーへのアクセス、センサーのイベントリスナーの登録/登録解除など、さまざまなメソッドを提供します。 |
Sensor |
クラス |
特定のセンサーのインスタンスの作成に使用します。 |
SensorEvent |
クラス |
センサーデータを公開するため、システムによって使用されます。センサーからのローデータ、センサータイプ、データ精度、タイムスタンプが含まれます。 |
SensorEventListener |
インターフェイス |
センサーデータまたはセンサー精度が変更された場合、SensorManager から通知を受け取るためのコールバック・メソッドを提供します。 |
2.1. センサー設定の取得
デバイスで利用可能なセンサーは、デバイスメーカーによって決定されます。センサー・フレームワークを使用して、ランタイムにパラメーター ‘Sensor.TYPE_ALL’ を指定して SensorManager getSensorList() メソッドを呼び出すことで、利用可能なセンサーを特定できます。サンプルコード 1 は、利用可能なセンサーのリストと各センサーのベンダー、消費電力、精度を表示します。
package com.intel.deviceinfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Fragment;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
public class SensorInfoFragment extends Fragment {
private View mContentView;
private ListView mSensorInfoList;
SimpleAdapter mSensorInfoListAdapter;
private List
サンプルコード 1: センサーのリストを表示するためのコード**出典: インテル コーポレーション (2012 年)
2.2. センサーの座標系
センサー・フレームワークは、一般的な 3 軸の座標系によるセンサーデータをレポートします。SensorEvent オブジェクトにおいて、X、Y、Z はそれぞれ values[0]、values[1]、values[2] で表されます。
0 0 1 95 544 intel 4 1 638 14.0
光センサー、温度センサー、近接センサーのように一部のセンサーは、1 つの値のみ返します。これらのセンサーは、SensorEvent オブジェクトで values[0] のみ使用します。
その他のセンサーは、標準の 3 軸の座標系でセンサーデータをレポートします。以下は、3 軸の座標系を使用するセンサーの例です。
- 加速度計
- 重力センサー
- ジャイロスコープ
- 磁力計
3 軸のセンサー座標系は、デバイスのデフォルトの向きの画面に対する相対値で定義されます。通常、デフォルトの向きは、タブレットの場合は横、携帯電話の場合は縦です。デフォルトの向きの場合、x 軸は水平方向に右へ、y 軸は垂直方向に上へ、z 軸は画面の奥から手前方向にとります。図 4.2 にタブレットのセンサーの座標系を示します。
図 4.2: センサーの座標系 出典: インテル コーポレーション (2012 年)
センサーの座標系で最も重要なのは、デバイスを動かしたり、デバイスの向きを変えても座標系が変わらないことです。
2.3. センサーイベントのモニタリング
センサー・フレームワークは、SensorEvent オブジェクトを使用してセンサーデータをレポートします。SensorEventListener インターフェイスを実装し、センサーを SensorManager に登録することで、クラスは特定のセンサーのデータをモニタリングすることができます。センサー・フレームワークは、クラスで実装されている次の 2 つの SensorEventListener コールバック・メソッドを使用して、クラスにセンサー状態の変化を通知します。
onAccuracyChanged()
および
onSensorChanged()
サンプルコード 2 は、「センサー設定の取得」セクションの SensorInfoFragment (サンプルコード 1 ) で使用した SensorDialog を実装します。
ckage com.intel.deviceinfo;
import android.app.Dialog;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;
public class SensorDialog extends Dialog implements SensorEventListener {
Sensor mSensor;
TextView mDataTxt;
private SensorManager mSensorManager;
public SensorDialog(Context ctx, Sensor sensor) {
this(ctx);
mSensor = sensor;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDataTxt = (TextView) findViewById(R.id.sensorDataTxt);
mDataTxt.setText("...");
setTitle(mSensor.getName());
}
@Override
protected void onStart() {
super.onStart();
mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_FASTEST);
}
@Override
protected void onStop() {
super.onStop();
mSensorManager.unregisterListener(this, mSensor);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != mSensor.getType()) {
return;
}
StringBuilder dataStrBuilder = new StringBuilder();
if ((event.sensor.getType() == Sensor.TYPE_LIGHT)||
(event.sensor.getType() == Sensor.TYPE_TEMPERATURE)) {
dataStrBuilder.append(String.format("Data: %.3fn", event.values[0]));
}
else{
dataStrBuilder.append(
String.format("Data: %.3f, %.3f, %.3fn",
event.values[0], event.values[1], event.values[2] ));
}
mDataTxt.setText(dataStrBuilder.toString());
}
}
サンプルコード 2: センサーの値を表示するダイアログ**
2.4. モーションセンサー
モーションセンサーは、振動、回転、スイング、傾きなどのデバイスの動きをモニタリングするのに使用されます。加速度計とジャイロスコープは、多くのタブレットと携帯電話で利用可能なモーションセンサーです。
モーションセンサーは、センサー座標系を使用してデータをレポートします。SensorEvent オブジェクトの 3 軸 (x、y、z) の値はそれぞれ values[0]、values[1]、values[2] で表されます。
モーションセンサーを理解し、そのデータをアプリケーションで利用するには、力、質量、加速度、ニュートンの運動の法則、およびこれらの関係の時間的変化に関連する物理式を使用する必要があります。詳細は、物理のテキストや一般に公開されている資料を参照してください。
加速度計は、デバイスの加速度を計測します。
表 4.3 加速度計 出典: インテル コーポレーション (2012 年)
センサー |
タイプ |
SensorEvent データ (m/s2) |
説明 |
加速度計 |
TYPE_ACCELEROMETER |
values[0] values[1] values[2] |
x 軸の加速度 y 軸の加速度 z 軸の加速度 |
加速度計の概念は、ニュートンの運動の第 2 法則に由来しています。
a = F/m
オブジェクトの加速度は、オブジェクトに外力の合力が加えられた結果を表します。外力には、地球上のすべてのオブジェクトに加えられる重力も含まれます。重力は、オブジェクトに加えられた合力 F に比例し、オブジェクトの質量 m に反比例します。
ここで紹介するコードは、上記の式をそのまま使用する代わりに、期間内のデバイスの速度と位置の加速度に注目しています。次の式は、オブジェクトの速度 v1、オリジナルの速度 v0、加速度 a、時間 t の関係を表しています。
v1 = v0 + at
オブジェクトの変位 s の計算には、次の式を使用します。
s = v0t + (1/2)at2
多くの場合、v0 が 0 (デバイスを動かす前) の状態から開始するため、式は次のようになります。
s = at2/2
重力があるため、地球上のすべてのオブジェクトには重力加速度 g がかかります。オブジェクトの質量に関係なく、g はオブジェクトのロケーションの緯度に依存し、その値は 9.78 ~ 9.82 (m/s2) の範囲になります。ここでは、便宜上 g を次の基準値としています。
g = 9.80665 (m/s2)
加速度計は多次元の座標系を使用して値を返すため、このサンプルコードでは次の式を使用して x、y、z 軸の距離を計算できます。
Sx = AxT2/2
Sy=AyT2/2
Sz=AzT2/2
ここで、Sx、Sy、Sz はそれぞれ x 軸、y 軸、z 軸の変位を表し、Ax、Ay、Az はそれぞれ x 軸、y 軸、z 軸の加速度を表します。T は計測期間を表します。
サンプルコード 3 は、加速度計のインスタンスの作成方法を示します。
public class SensorDialog extends Dialog implements SensorEventListener { … private Sensor mSensor; private SensorManager mSensorManager; public SensorDialog(Context context) { super(context); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); … }
サンプルコード 3: 加速度計のインスタンス化 (**) 出典: インテル コーポレーション (2012 年)
場合によっては、3 次元すべてのデータを使用しないこともあります。また、デバイスの向きを考慮しなければならない場合もあります。例えば、迷路アプリケーションを開発する場合、x 軸と y 軸の重力加速度のみを使用し、デバイスの向きに基づいて進行方向と距離を計算することができます。次のサンプルコード 4 はこのロジックの概要を示します。
@Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) { return; } float accelX, accelY; … //WindowManager を使用して "デフォルトの向き" から //現在の向き currentRotation を検出します。 switch (currentRotation) { case Surface.ROTATION_0: accelX = event.values[0]; accelY = event.values[1]; break; case Surface.ROTATION_90: accelX = -event.values[0]; accelY = event.values[1]; break; case Surface.ROTATION_180: accelX = -event.values[0]; accelY = -event.values[1]; break; case Surface.ROTATION_270: accelX = event.values[0]; accelY = -event.values[1]; break; } //accelX、accelY、時間差を使用して x 軸および y 軸における移動距離を計算します。 … } }
サンプルコード 4: 迷路ゲームで加速度データを使用する場合はデバイスの向きを考慮**
出典: インテル コーポレーション (2012 年)
ジャイロスコープ (あるいは単にジャイロとも言う) は、表 4.4 に示すようにデバイスの x 軸、y 軸、z 軸の回転速度を計測します。ジャイロスコープのデータは正数または負数になります。軸の正の部分にある位置から原点を見たときに、回転が軸を中心に反時計回りの場合データは正数となり、時計回りの場合データは負数となります。図 4.3 のように、“右手の法則” を使用してジャイロスコープのデータが正数か負数かを判断することもできます。
表 4.4 ジャイロスコープ 出典: インテル コーポレーション (2012 年)
センサー |
タイプ |
SensorEvent データ (rad/s) |
説明 |
ジャイロスコープ |
TYPE_GYROSCOPE |
values[0] values[1] values[2] |
x 軸の回転速度 y 軸の回転速度 z 軸の回転速度 |
サンプルコード 5 は、ジャイロスコープのインスタンスの作成方法を示します。
public class SensorDialog extends Dialog implements SensorEventListener { … private Sensor mGyro; private SensorManager mSensorManager; public SensorDialog(Context context) { super(context); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mGyro = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); … }
サンプルコード 5: ジャイロスコープのインスタンス化**
出典: インテル コーポレーション (2012 年)
2.5. ポジションセンサー
多くの Android* タブレットは、磁力計および近接センサーの 2 つのポジションセンサーをサポートしています。磁力計は x、y、z 軸の磁力の大きさを計測し、近接センサーはほかのオブジェクトからデバイスまでの距離を検出します。
2.5.1. 磁力計
Android* システムにおける磁力計の最も重要な使用法はコンパスの実装です (表 4.5 を参照)。
表 4.5 磁力計 出典: インテル コーポレーション (2012 年)
センサー |
タイプ |
SensorEvent データ (µT) |
説明 |
磁力計 |
TYPE_MAGNETIC_FIELD |
values[0] values[1] values[2] |
x 軸の磁力の大きさ y 軸の磁力の大きさ z 軸の磁力の大きさ |
サンプルコード 6 は、磁力計のインスタンスの作成方法を示します。
public class SensorDialog extends Dialog implements SensorEventListener { … private Sensor mMagnetometer; private SensorManager mSensorManager; public SensorDialog(Context context) { super(context); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); … }
サンプルコード 6: 磁力計のインスタンス化**
出典: インテル コーポレーション (2012 年)
2.5.2. 近接
近接センサーは、デバイスとほかのオブジェクト間の距離を示します。近接センサーを使用して、ユーザーとデバイス間の距離を検出し、通話中かどうかを判断することができます (表 4.6 を参照)。
表 4.6 近接センサー 出典: インテル コーポレーション (2012 年)
センサー |
タイプ |
SensorEvent Data |
説明 |
近接 |
TYPE_PROXIMITY |
values[0]
|
オブジェクトからの距離 (cm)。一部の近接センサーは、オブジェクトが十分に接近しているかどうかを示すブール値のみを返します。 |
サンプルコード 7 は、近接センサーのインスタンスの作成方法を示します。
public class SensorDialog extends Dialog implements SensorEventListener { … private Sensor mProximity; private SensorManager mSensorManager; public SensorDialog(Context context) { super(context); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); … }
サンプルコード 7: 近接センサーのインスタンス化**
出典: インテル コーポレーション (2012 年)
2.6. 環境センサー
環境センサーは、光、温度、気圧、湿度などの周辺環境パラメーターを検出し、レポートします。デバイスで利用可能なセンサーは、デバイスメーカーによって決定されます。環境光センサー (ALS) は多くの Android* タブレットで利用できます。
2.6.1. 環境光センサー (ALS)
表 4.7 の環境光センサーは、システムが周辺環境の明るさを検出し、画面の明るさを自動調整するのに使用されます。
表 4.7 環境光センサー 出典: インテル コーポレーション (2012 年)
センサー |
タイプ |
SensorEvent データ (lx) |
説明 |
ALS |
TYPE_LIGHT |
values[0]
|
デバイス周辺の明るさ |
サンプルコード 8 は、環境光センサーのインスタンスの作成方法を示します。
... private Sensor mALS; private SensorManager mSensorManager; ... mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mALS = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); ...
サンプルコード 8: 環境光センサーのインスタンス化**
出典: インテル コーポレーション (2012 年)
2.7. センサーのパフォーマンスと最適化のガイドライン
アプリケーションでセンサーを使用する場合は、次のベストプラクティスに従ってください。
· センサーを使用する前に、そのセンサーが利用可能かどうかを確認する
Android* プラットフォームでは、特定のセンサーへの対応/非対応をデバイスに強制していません。デバイスで利用可能なセンサーは、デバイスメーカーによって決定されます。アプリケーションでセンサーを使用する前に、必ずそのセンサーが実際に利用可能なことを確認してください。
· センサーのリスナーは必ず登録解除する
センサーのリスナーを実装するアクティビティーが終了したり、ダイアログが停止した場合は、センサーのリスナーを登録解除してください。登録解除は、アクティビティーの onPause() メソッドまたはダイアログの onStop() メソッドから行えます。登録解除しないと、センサーは継続してデータを取得し、電池を消耗することになります。
· onSensorChanged() メソッドをブロックしない
センサーデータをレポートするため、onSensorChanged() メソッドはシステムによって頻繁に呼び出されます。このメソッドには最小限のロジックのみ含めるべきです。センサーデータを使用する複雑な計算は、このメソッドの外側に移動する必要があります。
· 必ず実際のデバイスでセンサー・アプリケーションをテストする
ここで説明したセンサーはすべてハードウェア・センサーです。Android* エミュレーターでは、センサーの機能とパフォーマンスを十分にシミュレーションできない可能性があります。
3. GPS および位置情報
GPS (グローバル・ポジショニング・システム) は、衛星を利用して世界中の正確な地理的位置を提供します。GPS は多くの Android* タブレットで利用できます。さまざまな観点から、GPS はポジションセンサーのように動作します。GPS は、デバイスで実行中のアプリケーションに正確な位置情報を提供することができます。Android* プラットフォームでは、GPS はセンサー・フレームワークによって直接管理されていません。代わりに、Android* の位置情報サービスが GPS データにアクセスし、位置情報リスナーのコールバックを利用してアプリケーションへデータを転送します。
3.1. Android* 位置情報サービス
GPS だけが Android* デバイス上で位置情報を取得する唯一の方法ではありません。Wi-Fi*、携帯電話通信網、その他のワイヤレス・ネットワークを使用してデバイスの現在地を取得することもできます。GPS とワイヤレス・ネットワーク (Wi-Fi および携帯電話通信網を含む) は、Android* の位置情報サービスに対して “位置情報プロバイダー” の役割を果たします。表 4.8 は、Android* の位置情報サービスを利用するための主なクラスとインターフェイスのリストです。
表 4.8 Android* プラットフォームの位置情報サービス 出典: (2012 年)
名前 |
タイプ |
説明 |
LocationManager |
クラス |
位置情報サービスを利用する際に使用します。位置情報の定期的な更新を要求したり、近接アラートを送信するためのさまざまなメソッドを提供します。 |
LocationProvider |
抽象クラス |
位置情報プロバイダーの抽象スーパークラスです。 |
Location |
クラス |
位置情報プロバイダーが地理データを要約するために使用します。 |
LocationListener |
インターフェイス |
LocationManager から位置情報の通知を受け取るのに使用します。 |
3.2. GPS 位置情報の更新の取得
センサー・フレームワークを使用してセンサーデータにアクセスするのと同様に、アプリケーションは GPS 位置情報の更新を受け取るため、LocationListener インターフェイスで定義されたコールバック・メソッドを実装します。LocationManager は、これらのコールバックを通して GPS の更新通知をアプリケーションに送信します (“Don’t call us, we will call you (そちらから呼ばないください。必要なときにこちらから呼びます。[ハリウッドの法則]))。
アプリケーションで GPS 位置情報データにアクセスするには、Android* のマニフェスト・ファイルで詳細な位置情報へのアクセス権限を要求する必要があります (サンプルコード 9)。
..
サンプルコード 9: マニフェスト・ファイルで詳細な位置情報へのアクセス権限を要求**
出典: インテル コーポレーション (2012 年)
サンプルコード 10 は、GPS 更新を取得し、ダイアログ・テキスト・ビューで緯度と経度を表示する方法を示します。
package com.intel.deviceinfo; import android.app.Dialog; import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.widget.TextView; public class GpsDialog extends Dialog implements LocationListener { TextView mDataTxt; private LocationManager mLocationManager; public GpsDialog(Context context) { super(context); mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDataTxt = (TextView) findViewById(R.id.sensorDataTxt); mDataTxt.setText("..."); setTitle("Gps Data"); } @Override protected void onStart() { super.onStart(); mLocationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, this); } @Override protected void onStop() { super.onStop(); mLocationManager.removeUpdates(this); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public void onLocationChanged(Location location) { StringBuilder dataStrBuilder = new StringBuilder(); dataStrBuilder.append(String.format("Latitude: %.3f, Logitude%.3fn", location.getLatitude(), location.getLongitude())); mDataTxt.setText(dataStrBuilder.toString()); } }
サンプルコード 10: GPS 位置情報データを表示するダイアログ**
出典: インテル コーポレーション (2012 年)
3.3. GPS および位置情報のパフォーマンスと最適化のガイドライン
GPS は、デバイス上で最も正確な位置情報を提供します。しかし、ハードウェア機能であるため、電力を消費します。また、最初の位置情報の取得にも時間がかかります。ここでは、GPS および位置情報を使用するアプリケーションを開発するガイドラインを示します。
· 利用可能なすべての位置情報プロバイダーを検討する
GPS_PROVIDER のほかにも、NETWORK_PROVIDER があります。アプリケーションで大まかな位置情報データのみ必要な場合は、NETWORK_PROVIDER を使用することを検討してください。
· キャッシュされた位置情報を使用する
GPS は最初の位置情報を取得するのに時間がかかります。GPS が正確な位置情報を取得するまでの間、LocationManager の getlastKnownLocation() メソッドで提供される位置情報を使用して作業を実行することができます。
· 位置情報の更新要求の頻度と時間を最小限に抑える
位置情報の更新要求は必要なときのみ行い、不要になったら直ちに LocationManager で登録解除すべきです。
4. まとめ
Android* プラットフォームは、開発者にデバイスのビルトイン・センサーを利用するための API を提供します。これらのセンサーは、デバイスの現在の動き、位置、周辺環境に関する正確なローデータを提供します。センサー・アプリケーションの開発では、ベストプラクティスに従って、パフォーマンスと電力効率を向上すべきです。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。