氣壓傳感器兩年前已經開始被手機制造商運用在其設備上,但貌似沒有引起開發者足夠的重視。像Galaxy S III 、Galaxy Note 2和小米2手機上都有,不過大家對於氣壓傳感器比較陌生。其實大氣壓無處不在,我們可以利用它來為我們完成諸如海拔高度測量甚至是空間定位的任務。
先說些題外話,舒緩一下工作學習的疲憊。前些天跟朋友一起去戶外活動,登山到半山腰,突然朋友問我,現在海拔大概多少?我腦子靈光一閃,前些天一個在小米工作的朋友在其小米2手機上打開指南針應用對我說現在海拔多少多少,而我現在手頭正有一台小米4手機,趕緊拿出來打開指南針應用,結果氣壓是出來了,海拔計算卻需要聯網,真是讓人掃興。也正是這一點讓我萌生了自己來計算的想法。
既然說做,那就做吧,反正應該不會太難。首先網上查詢相關資料,計算自己的海拔高度通常有兩種方法,一是通過GPS全球定位系統,二是通過測出大氣壓,然後根據氣壓值計算出海拔高度。
使用GPS全球定位系統獲取海拔簡單是簡單,只要獲取到Android系統提供LoctionManager服務,將提供者設置為LocationManager.GPS_PROVIDER,在寫個GPS狀態監聽器GpsStatus.Listener,最後在實現一個LocationListener來實時監聽位置的變化,在onLocationChanged回調函數中取出location參數,裡面就包含了海拔高度值(getAltitude())。
關鍵代碼如下
private LocationManager lm;
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
if(!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Log.i(TAG, "請先開啟GPS");
showAlertDialog(context, "開啟GPS,定位更准確;取消則使用網絡定位,粗略定位");
}
if(!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(intent);
}
lm.addGpsStatusListener(listener);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
其中listener和locationListener分別為StatusListener和LocationListener的實例,使用起來也不難,主要代碼框架已經為你生成了,只要查查android SDK的API就會明白的,就不說了。這種方式去測海拔,需要接收GPS信號。如果你在叢林或者洞穴或建築物內,極有可能是接收不到GPS衛星信號的。這時候,可以考慮使用壓力傳感器來測海拔高度。
先說說使用壓力傳感器來測海拔高度的原理,其實非常簡單,一些基本原理你必須要明白的:一般來說海拔越高,氣壓越低,他們之間存在某種關系,下文會講到的。有不少學者對海拔與氣壓做了研究,回歸了不少海拔與氣壓的數據,他們的變化關系大概服從下面的表達式。
因為我們要計算海拔(A),所以略作變化,可以知道A的計算公式如下。
其中P為當前的大氣壓,P0為標准大氣壓。這樣,我們只要獲取Android手機內置氣壓傳感器的值,就可以初步估算出海拔高度了。實現起來也不難,關鍵代碼如下。
private SensorManager sensorManager = null;
sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mPressure = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
if(mPressure == null)
{
mPressureVal.setText("您的手機不支持氣壓傳感器,無法使用本軟件功能.");
return;
}
mAccelerate = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
然後在onResume()函數裡面注冊氣壓傳感器,在onPause()中注銷,這樣做當然是為了節約用電嘛。
sensorManager.registerListener(pressureListener, mPressure,
SensorManager.SENSOR_DELAY_NORMAL);
if(pressureListener!=null){
sensorManager.unregisterListener(pressureListener);
}
還有一點必須獲取氣壓傳感器的值嘛,必須要有一個SensorEventListener對象(SensorManager注冊語句的pressureListener),代碼很簡單。
SensorEventListener pressureListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
float sPV = event.values[0];
mPressureVal.setText(String.valueOf(sPV));
DecimalFormat df = new DecimalFormat("0.00");
df.getRoundingMode();
// 計算海拔
double height = 44330000*(1-(Math.pow((Double.parseDouble(df.format(sPV))/1013.25),
(float)1.0/5255.0)));
mAltitude.setText(df.format(height));
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
海拔計算公式的實現自然也不是難事,基本上是翻譯一下就出來了。
其實海拔和氣壓的這種關系比較復雜,受多方面的因素影響,最為顯著的是溫度的影響。大氣壓通俗來講是大氣對其他物體的壓力,與空氣分子的密度和動能相關,所以同一海拔高度,溫度越高,氣壓越高。正是因為這個影響因素,使得氣壓測海拔有較明顯的誤差。如果是時隔不久,即溫度變化不大,測高度差還是比較准確的,我做過實驗,利用氣壓能較為准確的測出7層樓的高度,哈哈,是不是感覺很靈敏呢?只是影響因素帶來的誤差還得想辦法消除。剛接觸Android不久,也沒寫過什麼博客,這個純屬扯扯,沒什麼技術難度,僅僅是為了總結一下android開發的一些事兒,順便練練筆而已。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11