Android平臺(tái)提供了兩種傳感器讓我們可以確定設(shè)備的位置: 地磁傳感器和方向傳感器。 Android還提供了一種傳感器讓我們可以決定人臉離手機(jī)多近的時(shí)候關(guān)閉屏幕(距離傳感器proximity sensor)。 地磁傳感器和距離傳感器都是基于硬件的。 大多數(shù)手持設(shè)備供應(yīng)商都有提供一個(gè)地磁傳感器。 同樣, 手持設(shè)備制造商通常包含一個(gè)距離傳感器來(lái)在通話的時(shí)候決定何時(shí)關(guān)閉屏幕。 方向傳感器(orientation sensor)是基于軟件的, 它通過(guò)加速度傳感器和地磁傳感器來(lái)計(jì)算數(shù)據(jù)。 但是方向傳感器在Android2.2中已經(jīng)不推薦使用。
位置傳感器在確定設(shè)備在世界中所處的位置時(shí)會(huì)很有用。 比如我們可以使用地磁傳感器跟加速傳感器合作來(lái)決定設(shè)備相對(duì)于地磁北極的位置。 我們還可以使用方向傳感器(或者基于傳感器的方向方法)來(lái)確定設(shè)備相對(duì)于APP框架為參考的位置。 位置傳感器通常不用于監(jiān)測(cè)設(shè)備移動(dòng)或者運(yùn)動(dòng), 比如搖動(dòng), 傾斜等。
地磁傳感器和方向傳感器通過(guò)SensorEvent的多維數(shù)組返回?cái)?shù)據(jù)。 栗如, 方向傳感器在每次返回傳感器事件的時(shí)候提供了地磁力在三維空間的強(qiáng)度值。 同樣方向傳感器則提供了方位角(Yaw偏航角), 俯仰角(pitch)和翻滾角(roll)。 下表提供了Android平臺(tái)各位置傳感器的信息:
SensorEvent.values[0]
沿x軸旋轉(zhuǎn)矢量分量(x*sin(θ/2 ))。
無(wú)單位
SensorEvent.values[1]
沿y軸旋轉(zhuǎn)矢量分量(y*sin(θ/2 ))。
SensorEvent.values[2]
沿z軸旋轉(zhuǎn)矢量分量(z*sin(θ/2 ))。
TYPE_GEOMAGNETIC_ROTATION_VECTOR
SensorEvent.values[0]
沿x軸旋轉(zhuǎn)矢量分量(x*sin(θ/2 ))。
無(wú)單位
SensorEvent.values[1]
沿y軸旋轉(zhuǎn)矢量分量(y*sin(θ/2 ))。
SensorEvent.values[2]
沿z軸旋轉(zhuǎn)矢量分量(z*sin(θ/2 ))。
TYPE_MAGNETIC_FIELD
SensorEvent.values[0]
沿x軸的地磁強(qiáng)度
μT
SensorEvent.values[1]
沿y軸的地磁強(qiáng)度
SensorEvent.values[2]
沿z軸的地磁強(qiáng)度
TYPE_MAGNETIC_FIELD_UNCALIBRATED
SensorEvent.values[0]
沿x軸的地磁強(qiáng)度(無(wú)硬鐵校準(zhǔn)hard iron calibration)
μT
SensorEvent.values[1]
沿y軸的地磁強(qiáng)度(無(wú)硬鐵校準(zhǔn)hard iron calibration)
SensorEvent.values[2]
沿z軸的地磁強(qiáng)度(無(wú)硬鐵校準(zhǔn)hard iron calibration)
SensorEvent.values[3]
沿x軸鐵偏差校準(zhǔn)(Iron bias estimation)
SensorEvent.values[4]
沿y軸鐵偏差校準(zhǔn)(Iron bias estimation)
SensorEvent.values[5]
沿z軸鐵偏差校準(zhǔn)(Iron bias estimation)
TYPE_ORIENTATION①
SensorEvent.values[0]
方位角(繞z軸的角度)
度
SensorEvent.values[1]
俯仰角(pitch) (繞x軸的角度)
SensorEvent.values[2]
翻滾角(roll) (繞y軸的角度)
TYPE_PROXIMITY
SensorEvent.values[0]
與對(duì)象的距離②
cm
?、?該傳感器在Android2.2版本中不再推薦使用。 Sensor framework提供了備用的方法, 下文會(huì)有介紹。
?、?一些距離傳感器只提供二進(jìn)制數(shù)據(jù)代表遠(yuǎn)和近。
使用游戲旋轉(zhuǎn)矢量傳感器:
游戲旋轉(zhuǎn)矢量傳感器跟旋轉(zhuǎn)矢量傳感器是相同的, 除了它不使用地磁場(chǎng)。 因此Y軸不指向北邊而是一些別的參考系。
因?yàn)橛螒蛐D(zhuǎn)矢量傳感器不使用地磁場(chǎng), 相關(guān)的方向因不受磁場(chǎng)影響而更加準(zhǔn)確。 如果不在意北邊在哪的話可以在游戲中使用該傳感器, 這時(shí)候普通的旋轉(zhuǎn)矢量就不合適了, 因?yàn)樗蕾囉诖艌?chǎng)。 下面的代碼演示了如何獲取一個(gè)該傳感器的實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
使用地磁旋轉(zhuǎn)矢量傳感器:
地磁旋轉(zhuǎn)矢量傳感器跟旋轉(zhuǎn)矢量傳感器一樣, 但是它使用地磁代替陀螺儀。 所以它的精確度會(huì)比普通旋轉(zhuǎn)矢量傳感器要低, 但是功耗也降低了。 應(yīng)該只有當(dāng)需要在后臺(tái)獲取旋轉(zhuǎn)信息而不想要消耗太多電量的時(shí)候才使用它。 該傳感器當(dāng)與批處理(batching)一起是最有用的。
下面的代碼演示了如何獲取實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
方向傳感器:
方向傳感器讓我們可以監(jiān)測(cè)設(shè)備相對(duì)于地球參考系的位置(特指地磁北極)。 下面代碼演示了如何獲取該傳感器實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
方向傳感器通過(guò)使用設(shè)備的地磁場(chǎng)傳感器和設(shè)備的加速度計(jì)合作獲得它的數(shù)據(jù)。 通過(guò)使用這倆硬件傳感器, 方向傳感器可以提供這三個(gè)維度的數(shù)據(jù):
l 方位角(繞z軸的角度)。 這個(gè)角度在地磁北極和設(shè)備的y軸之間。 比如如果設(shè)備的y軸對(duì)準(zhǔn)地磁北極, 那么該值是0, 如果設(shè)備的y軸對(duì)準(zhǔn)南極, 則該值為180. 同樣的, 當(dāng)y軸指向東邊, 該值是90, 指向西邊則為270.
l 俯仰角(pitch) (繞x軸的角度)。 處于z軸正方向和y軸正方向之間的時(shí)候該值是正的, z軸正方向和y軸負(fù)方向的時(shí)候, 該值是負(fù)的。 范圍是180度~-180度。
l 翻滾角(roll) (繞y軸的角度)。 當(dāng)處于z軸正方向和x軸正方向時(shí)該值為正。 Z軸正方向和x軸負(fù)方向的時(shí)候, 該值為負(fù)。 取值范圍是90~-90度。
這個(gè)定義跟航空學(xué)中的方位角, 俯仰角和翻滾角是不一樣的, 航空學(xué)中x軸表示沿飛機(jī)的長(zhǎng)邊(飛機(jī)尾部到頭部)。 此外由于歷史原因, 翻滾角在順時(shí)針?lè)较驗(yàn)檎〝?shù)學(xué)上講, 它應(yīng)該在逆時(shí)針?lè)较驗(yàn)檎?/p>
方向傳感器通過(guò)處理加速度計(jì)和地磁場(chǎng)傳感器的數(shù)據(jù)來(lái)得到它自己的數(shù)據(jù)。 因?yàn)樯婕暗奶幚砣蝿?wù)比較繁重, 所以精度和準(zhǔn)確度被減少(只有當(dāng)翻滾角分量為0的時(shí)候它的數(shù)據(jù)才可靠)。 因此, 方向傳感器在Android2.2中就不推薦使用了。 官方推薦使用getRotationMatrix()方法和getOrientation()方法結(jié)合來(lái)計(jì)算方向值, 代替方向傳感器。 我們還可以使用remapCoordinateSystem()方法來(lái)映射方向值到APP參考框架。 下面的代碼演示了如何從方向傳感器直接獲得方向數(shù)據(jù), 只有幾乎沒(méi)有翻滾角的時(shí)候才推薦這樣使用:
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mOrientation;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
// You must implement this callback in your code.
}
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mOrientation, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
float azimuth_angle = event.values[0];
float pitch_angle = event.values[1];
float roll_angle = event.values[2];
// Do something with these orientation angles.
}
}
我們并不會(huì)經(jīng)常用到處理方向傳感器的原始數(shù)據(jù)。
使用地磁場(chǎng)傳感器:
地磁場(chǎng)傳感器讓我們可以監(jiān)測(cè)地球磁場(chǎng)的變化。 下面的代碼展示如何獲取它的實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
該傳感器提供了三維磁場(chǎng)的原始數(shù)據(jù)。 通常我們不需要直接使用該傳感器, 而是使用旋轉(zhuǎn)矢量傳感器來(lái)確定旋轉(zhuǎn)運(yùn)動(dòng)的原始數(shù)據(jù), 或者我們還可以使用加速度計(jì)和地磁場(chǎng)傳感器跟getRotationMatrix()方法合作獲取旋轉(zhuǎn)矩陣和傾角矩陣。 然后可以使用這些矩陣同getOrientation()和getInclination()方法來(lái)獲得方位角和地磁傾角數(shù)據(jù)。
使用未校正的磁力計(jì):
未校正的磁力計(jì)跟地磁場(chǎng)傳感器相似, 但是它沒(méi)有”硬鐵校正”(hard iron calibration)。 工廠校正和溫度校正依然應(yīng)用于磁場(chǎng)。 未校正的磁力計(jì)在處理壞硬鐵估計(jì)(bad hard iron estimations)的時(shí)候有用。 通常geomagneticsensor_event.value[0]將會(huì)接近uncalibrated_magnetometer_event.values[0]- uncalibrated_magnetometer_event.values[3]。 也就是, calibrated_x ~= uncalibrated_x - bias_estimate_x.
注意: 未校正傳感器提供更多的原始結(jié)果并可能包括一些偏差, 但是它們的測(cè)量值包含更少的校正導(dǎo)致的跳變。 一些APP可能會(huì)更想這些未校正的原始數(shù)據(jù), 因?yàn)樗麄兏悠交涂煽俊?比如當(dāng)APP想要實(shí)現(xiàn)自己的傳感器合成, 則他們可能更喜歡沒(méi)有矯正過(guò)的數(shù)據(jù)。
除了磁場(chǎng), 未校正磁力計(jì)還會(huì)提供硬鐵校正在每個(gè)軸的估計(jì)值。 下面代碼演示了如何獲取該傳感器實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
使用距離傳感器(Proximity Sensor):
距離傳感器讓我們可以確定一個(gè)目標(biāo)與設(shè)備的距離。 下面代碼演示了如何獲取它的實(shí)例:
private SensorManager mSensorManager;
private Sensor mSensor;
。..
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
距離傳感器通常用來(lái)確定手持設(shè)備跟人臉的距離(比如用戶接到電話或者在打電話的時(shí)候)。 大多數(shù)距離傳感器返回絕對(duì)距離, 但是它們中的個(gè)別分子會(huì)返回”遠(yuǎn)/近”這樣的信息。 下面的代碼展示給我們?nèi)绾问褂眠@玩意兒:
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mProximity;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get an instance of the sensor service, and use that to get an instance of
// a particular sensor.
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
}
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
@Override
public final void onSensorChanged(SensorEvent event) {
float distance = event.values[0];
// Do something with this sensor data.
}
@Override
protected void onResume() {
// Register a listener for the sensor.
super.onResume();
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
// Be sure to unregister the sensor when the activity pauses.
super.onPause();
mSensorManager.unregisterListener(this);
}
}