讀古今文學網 > Android程序設計:第2版 > 傳感器 >

傳感器

現代智能手機承載的功能已遠遠超出了通信這一傳統功能。外部傳感器可以報告手機所處的環境,這使得手機對於用戶及開發人員都更強大和有用。從Android 1.5(API level 3)開始,提供了標準的傳感器集合。物理傳感器包括但是不限於加速度計,它衡量沿著各條軸的加速度;測量某些軸的旋轉變化的陀螺儀;沿著某條軸感應磁場強度的磁場傳感器;衡量環境光強度的光傳感器;衡量外部對像到設備的距離的距離傳感器;測量環境溫度的溫度傳感器;以及作為晴雨表的壓力傳感器等。每個傳感器的直接輸出測量值可以認為是原始指標,因此關聯的傳感器是原始傳感器(raw sensor)。通過某些傳感器,可以組合或彙集多個衡量指標,在這些指標上可以執行計算,形成更複雜的指標。例如,通過整合隨時間推移旋轉變化的陀螺儀指標,可以生成旋轉向量。這類複雜的衡量指標往往來自組合的傳感器。

Android提供了SensorManager系統服務來支持對一個或一組傳感器的訪問。該系統服務可以通過Context的getSystemService方法訪問,其參數是Context.SENSOR_SERVICE。使用SensorManager,可以通過getDefaultSensor方法獲取特定的傳感器。

但是,有時可以返回組合的傳感器,因此,如果想訪問原始傳感器及其關聯的數據,應該使用getSensorList方法:


SensorManager mngr =
    (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
// getting the default accelerometer
Sensor accel = mngr.getDefaultSensor (Sensor.TYPE_ACCELEROMETER);
// getting the raw accelerometer
List<Sensor> list = mngr.getSensorList(Sensor.TYPE_ACCELEROMETER);
  

一旦獲取到了一個或一組傳感器,就可以啟用這些傳感器,首先需要在傳感器上註冊數據。數據應該是按照參數中提供的速率獲取,數據獲取速率值可以是SENSOR_DELAY_NORMAL、SENSOR_DELAY_UI(用於基礎的UI交互的速率)、SENSOR_DELAY_GAME(適用於有些高速率),SENSOR_DELAY_FASTEST(速率越快越好),或者以ms表示的事件之間的具體延遲:


SensorEventListener listener = new SensorEventListener {
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) { }
    @Override
    public void onSensorChanged(SensorEvent event) { }
};
// registering a listener
mngr.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
  

SensorEventListener中提供的兩個方法,onAccuracyChanged和onSensorChanged是當數據在傳感器中可用時調用的。當傳感器錯誤或準確度級別變動時,會調用onAccuracyChanged方法。onSensorChanged方法可能是更有意思的方法,在該方法中,傳感器所收集的數據是封裝在SensorEvent對像中傳遞的。

註銷監聽器並且在不需要的時候禁用傳感器是非常重要的(例如暫停活動);否則,設備會繼續運轉,消耗電源。即使關閉屏幕,系統也不會替你執行註銷操作:


mngr.unregisterListener(listener);
  

當打開傳感器時,SensorEvent是通過onSensorChanged方法傳遞給傳感器的。每種傳感器類型的SensorEvent值不同。

位置

手機的坐標系統是基於屏幕和手機屏幕的默認方向。x軸、y軸和z軸如圖17-1所示,工作機理如下:

x軸

水平方向,取值向右遞增,向左遞減。

y軸

垂直方向,取值向上遞增,向下遞減。

z軸

和屏幕垂直的軸,從屏幕向前值為正,向後值為負(z軸的零點落在屏幕上)。

當用戶移動手機時,軸會隨著手機運動,不會變換位置。

圖17-1:手機的坐標系統

各種傳感器的精度和方差取決於硬件的質量。在很多情況下,需要消除顯著的抖動/噪聲數據(例如使用低音濾波器)。過濾器及其構建類型取決於設計和構建的開發人員。

加速度計

加速度計用於檢測設備的加速度,返回沿著3條軸的值(value[0]表示x軸值,value[1]表示y軸值,value[2]表示z軸值)。這些值的單位是SI(m/S 2)。注意,重力沒有從返回的值中排除。因此,當設備放置在桌子上時,value[2]的值為9.81 m/S 2。

因為排除各個軸的重力影響是相當普遍的需要,因此Android 2.3(API level 9)也支持線性加速傳感器及重力傳感器,本章後面將探討。

陀螺儀

陀螺儀衡量角速度或圍繞3條軸的旋轉速度。所有值的單位都是弧度/秒。旋轉值沿逆時針方向是正值。也就是說,當一個人正常查看設備屏幕時(在設備的0,0,100坐標),如果設備看起來是逆時針旋轉時,則其旋轉值為正值。因為旋轉速度是個角速度,要計算角度,必須整合一段時間的旋轉值:


private static final float NS2S = 1.0f / 1000000000.0f;
private float timestamp;
private float angle;
@Override
public void onSensorChanged(SensorEvent event) {
    float gyrox = event.values[0];
    float gyroy = event.values[1];
    float gyroz = event.values[2];
    // here we integrate over time to figure out the rotational angle around each axis
    if (timestamp != 0) {
        final float dT = (event.timestamp - timestamp) * NS2S;
        angle[0] += gyrox * dT;
        angle[1] += gyroy * dT;
        angle[2] += gyroz * dT;
    }
    timestamp = event.timestamp;
}
  

由於這是一種常見情況,故Android 2.3(API level 9)也支持旋轉向量傳感器,我們將在下一節探討它。

旋轉向量

在Android 2.3及更高的版本中,旋轉向量表示設備的方向,其以角度和軸的組合形式表示,即設備沿著軸<x,y,z>旋轉角度Θ。雖然可以通過陀螺儀計算旋轉角度,但很多開發人員覺得該計算太煩瑣了,因而Google提供了旋轉向量來簡化使用方式。

旋轉向量的3個元素分別是x*sin(Θ/2),y*sin(Θ/2)和z*sin(Θ/2),因此旋轉向量的矢量值為sin(Θ/2),旋轉向量的方向就相當於旋轉軸的方向。旋轉向量的3個元素相當於單位4元素<cos(Θ/2),x*sin(Θ/2),y*sin(Θ/2)和z*sin(Θ/2)>的最後3個元素。旋轉向量的元素是無單位的。

線性加速

Android 2.3(API level 9)支持的另一種簡化了常用計算的傳感器類型是加速度計。發送的加速度值是個三維向量,是沿著每個設備軸的加速度,已經排除了重力。這意味著其值是每條軸上的線性加速度減去重力在該軸上導致的線性加速度。這使得對於在地球上使用手機,更易於排除重力的常數影響。所有加速度值的單位都是m/S 2。

重力

傳感器的三維矢量表示重力的方向和幅度。Android 2.3(API level 9)傳感器提供了它的計算方式,其單位是m/S 2。

其他傳感器

Android還支持以下傳感器:

該傳感器提供單一值的數組(value[0]),它檢測的是環境中的光的級別,單位是SI lux(lx)。

該傳感器檢測環境中x軸、y軸和z軸的磁場,單位是microteslas(T)。

壓力

提供該傳感器的設備不多,其值單位是千帕斯卡(kPa)。

距離

該傳感器提供單一值的數組(value[0]),表示到傳感器的距離,單位是厘米(cm)。在某些情況下,proximity傳感器可能只提供二進制形式的near(0)值和far(1)值。在這種情況下,大於等於傳感器的getMaximumRange方法所返回的值將返回far,反之則返回near。

溫度

提供該傳感器的設備也不多。其單位是攝氏度()。

周圍環境溫度

能夠識別周圍環境溫度的傳感器的設備不多,其數值單位是攝氏度()。在Android 4.0(API Level 14)以及更新版本中支持。

相對濕度

能夠識別相對濕度的傳感器的設備不多,其數值是百分比(%)表示。在Android 4.0(API Level 14)以及更新版本中支持。