Android平台上使用气压传感器计算海拔高度
气压传感器两年前已经开始被手机制造商运用在其设备上,但貌似没有引起开发者足够的重视。像Galaxy S III 、Galaxy Note 2和小米2手机上都有,不过大家对于气压传感器比较陌生。其实大气压无处不在,我们可以利用它来为我们完成诸如海拔高度测量甚至是空间定位的任务。
先说些题外话,舒缓一下工作学习的疲惫。前些天跟朋友一起去户外活动,登山到半山腰,突然朋友问我,现在海拔大概多少?我脑子灵光一闪,前些天一个在小米工作的朋友在其小米2手机上打开指南针应用对我说现在海拔多少多少,而我现在手头正有一台小米4手机,赶紧拿出来打开指南针应用,结果气压是出来了,海拔计算却需要联网,真是让人扫兴。也正是这一点让我萌生了自己来计算的想法。
既然说做,那就做吧,反正应该不会太难。首先网上查询相关资料,计算自己的海拔高度通常有两种方法,一是通过GPS全球定位系统,二是通过测出大气压,然后根据气压值计算出海拔高度。
使用GPS全球定位系统获取海拔简单是简单,只要获取到Android系统提供LoctionManager服务,将提供者设置为LocationManager.GPS_PROVIDER,在写个GPS状态监听器GpsStatus.Listener,最后在实现一个LocationListener来实时监听位置的变化,在onLocationChanged回调函数中取出location参数,里面就包含了海拔高度值(getAltitude())。关键代码如下
1 private LocationManager lm; 2 lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); 3 if(!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)){ 4 Log.i(TAG, "请先开启GPS"); 5 showAlertDialog(context, "开启GPS,定位更准确;取消则使用网络定位,粗略定位"); 6 } 7 if(!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)){ 8 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 9 context.startActivity(intent); 10 } 11 lm.addGpsStatusListener(listener); 12 lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
其中listener和locationListener分别为StatusListener和LocationListener的实例,使用起来也不难,主要代码框架已经为你生成了,只要查查android SDK的API就会明白的,就不说了。这种方式去测海拔,需要接收GPS信号。如果你在丛林或者洞穴或建筑物内,极有可能是接收不到GPS卫星信号的。这时候,可以考虑使用压力传感器来测海拔高度。
先说说使用压力传感器来测海拔高度的原理,其实非常简单,一些基本原理你必须要明白的:一般来说海拔越高,气压越低,他们之间存在某种关系,下文会讲到的。有不少学者对海拔与气压做了研究,回归了不少海拔与气压的数据,他们的变化关系大概服从下面的表达式。
因为我们要计算海拔(A),所以略作变化,可以知道A的计算公式如下。
其中P为当前的大气压,P0为标准大气压。这样,我们只要获取Android手机内置气压传感器的值,就可以初步估算出海拔高度了。实现起来也不难,关键代码如下。
1 private SensorManager sensorManager = null; 2 sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); 3 mPressure = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); 4 if(mPressure == null) 5 { 6 mPressureVal.setText("您的手机不支持气压传感器,无法使用本软件功能."); 7 return; 8 } 9 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),代码很简单。
1 SensorEventListener pressureListener = new SensorEventListener() { 2 3 @Override 4 public void onSensorChanged(SensorEvent event) { 5 // TODO Auto-generated method stub 6 float sPV = event.values[0]; 7 mPressureVal.setText(String.valueOf(sPV)); 8 DecimalFormat df = new DecimalFormat("0.00"); 9 df.getRoundingMode(); 10 // 计算海拔 11 double height = 44330000*(1-(Math.pow((Double.parseDouble(df.format(sPV))/1013.25), 12 (float)1.0/5255.0))); 13 mAltitude.setText(df.format(height)); 14 } 15 16 @Override 17 public void onAccuracyChanged(Sensor sensor, int accuracy) { 18 // TODO Auto-generated method stub 19 20 } 21 };
海拔计算公式的实现自然也不是难事,基本上是翻译一下就出来了。
其实海拔和气压的这种关系比较复杂,受多方面的因素影响,最为显著的是温度的影响。大气压通俗来讲是大气对其他物体的压力,与空气分子的密度和动能相关,所以同一海拔高度,温度越高,气压越高。正是因为这个影响因素,使得气压测海拔有较明显的误差。如果是时隔不久,即温度变化不大,测高度差还是比较准确的,我做过实验,利用气压能较为准确的测出7层楼的高度,哈哈,是不是感觉很灵敏呢?只是影响因素带来的误差还得想办法消除。刚接触Android不久,也没写过什么博客,这个纯属扯扯,没什么技术难度,仅仅是为了总结一下android开发的一些事儿,顺便练练笔而已。