技术开发 频道

Android应用开发实战:GPS与加速度传感器

       【IT168 技术文档】本文将为读者详细介绍Android中增强现实应用程序的两个关键元素:GPS与加速度传感器。

  在前一篇文章《编程实现谷歌Android摄像头拍照》中,我们介绍了在增强现实技术(AR)引擎中Android SDK的两种基本构件即摄像头的用法。在本文中,我们将继续介绍另外两种基础构件,即GPS与加速度传感器。我们首先介绍所需的工具,然后讲解如何请求位置更新,并说明加速度传感器的工作机制。

  所需工具

  下面是本文中将用到的工具:

  •  Android SDK 1.5
  •  T-Mobile G1手机或其模拟器
  •  安装了Android Development Tools (ADT)插件、 NetBeans的Eclipse,或您喜欢的其它集成开发环境

  如何与卫星通信

  在实现了Android增强现实引擎的前两个元素即摄像头与指南针之后,下一步要做的就是确定位置。为了完成这项任务,我们主要用到Android的LocationManager对象。不过在此之前,我们还需首先解决一些其他问题,其中权限是我们首先要扫除的第一个障碍。

  Android的LocationManager支持两种权限请求:

  1. 需要告知系统您希望取得用户的位置。

  2. 需要告诉它您想要十分详细的地理信息。

  您需要在AndroidManifest.xmlxml 文件<manifest>标签内的<permission>标签中请求这两种权限,如下所示:

<uses-permission android:name="android.permission.LOCATION"/>

       对于细粒度的位置更新,也就是近距离显示有关对象,还需要添加以下内容:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

  如果没有这两行,当您试图注册位置更新时,Android就将返回一个安全异常,从而导致您的应用关闭。

        获取位置管理器

  获得位置管理器看起来好像挺简单的,但是还是得牢记一些事项。首先,我们也许只能在UI主线程中请求位置管理器。我们要么在有关动作的onCreate调用中请求LocationManager对象,要么使用LocationManager请求创建一个运行于主线程的可执行对象。

  为简单起见,下面的示例代码将从一个动作的onCreate方法中注册LocationManager更新。

public void onCreate(Bundle savedInstanceState)
{
   LocationManager locMan;
   locMan
=
      (LocationManager)getSystemService(Context.LOCATION_SERVICE);
   locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                          
100, 1, gpsListener);  
}

  如您所见,这里声明了一个LocationManager对象,使用getSystemService获得您的对象,然后调用了requestLocationUpdates。

  您可能想知道位置更新时需要哪些参数。首先,您告诉系统,您想使用系统中GPS装置的位置更新功能。然后,您告诉它您希望多长时间更新一次(本例时间间隔为100ms),并且每当移动一米以上时就更新。这样,就能迅速识别他们的移动情况并调整它们与其他对象的位置关系。最后,传入实现LocationListener接口的类的实例。

      位置更新的侦听艺术

  为位置更新传递请求后,LocationListener类将收到初始位置,继之以后来位置的改变情况。下面是我们的LocationListener:

LocationListener gpsListener = new LocationListener(){
      Location curLocation;
      
boolean locationChanged = false;
      
public void onLocationChanged(Location location)
      {
        
if(curLocation == null)
         {
            curLocation
= location;
            locationChanged
= true;
         }
        
        
if(curLocation.getLatitude() == location.getLatitude() &&
               curLocation.getLongitude()
== location.getLongitude())
            locationChanged
= false;
        
else
            locationChanged
= true;
        
         curLocation
= location;
      }
      
public void onProviderDisabled(String provider){}
      
public void onProviderEnabled(String provider){}
      
public void onStatusChanged(String provider, int status, Bundle extras){}
};

  在上面的代码中,我们唯一需要关心的就是onLocationChanged这个方法。然而,我们还会介绍这个对象的其它方法,以便您将这个对象复制到您自己的代码中时能够了解它们。 一旦卫星锁定了这个设备,方法onLocationChanged就会被调用,之后每经过在请求更新时指定的时间间隔(本例中为100ms)后,就会调用一次。

  每当位置更新时,都会带来一个Location对象。我们通过这个类可以获得目标的经纬度,并完成许多重要事情。这里我们最感兴趣的方法是getLatitude()、getLongitude()、bearingTo()与distanceTo()。使用这四个函数,我们可以计算出任何随后的位置的方位角,并确定出离您的距离有多远。

  

        请求加速度传感器数据

  为了实现我们的增强现实引擎,最后还需要用到加速度传感器数据。不过,Android已经为我们简化了这些数据的收集工作。在上一篇介绍增强现实技术的文章中,我们的示例程序可以请求手机的方位,并调用位置管理器对象中的registerListener来检索指南针数据。我们也可以使用同样的技术来请求加速度传感器数据,我们用来请求加速度传感器数据的代码如下所示:

sensorMan = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
sensorMan.registerListener(listener,
   sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
   SensorManager.SENSOR_DELAY_FASTEST);

  我们调用了上下文对象(上述代码中为ctx)的getSystemService方法。下面是用于方向监听器与加速度传感器监听器的完整代码。

private SensorEventListener listener = new SensorEventListener(){
  
public static volatile float direction = (float) 0;
  
public static volatile float inclination;
  
public static volatile float rollingZ = (float)0;

  
public static volatile float kFilteringFactor = (float)0.05;
  
public static float aboveOrBelow = (float)0;

  
public void onAccuracyChanged(Sensor arg0, int arg1){}

  
public void onSensorChanged(SensorEvent evt)
   {
      
float vals[] = evt.values;
      
      
if(evt.sensor.getType() == Sensor.TYPE_ORIENTATION)
      {
        
float rawDirection = vals[0];

         direction
=(float) ((rawDirection * kFilteringFactor) +
            (direction
* (1.0 - kFilteringFactor)));

          inclination
=
            (
float) ((vals[2] * kFilteringFactor) +
            (inclination
* (1.0 - kFilteringFactor)));

                
          
if(aboveOrBelow > 0)
             inclination
= inclination * -1;
          
        
if(evt.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
         {
            aboveOrBelow
=
               (
float) ((vals[2] * kFilteringFactor) +
               (aboveOrBelow
* (1.0 - kFilteringFactor)));
         }
      }
   }
};

  

         呵呵,这里的代码稍微有点多,下面我们来了解一下。首先,要为监听器设置所有的值。这意味着,您可以随时可以向监听器查询指南针方位与手机倾角。这些值会随着您请求的更新的类型的不同而有所变化。

         然后,我们会收到传感器信息,这时需要确定出两种主要信息:

  1. 手机指向

  2. 屏幕相对于水平面的倾角

  第一种信息称为方位角;第二种信息称为倾角。为了确定这些值,第一个计算任务就是过滤出摄像头的指南针运动。这称为翻转过滤器(rolling filter)。变量direction用于指出手机顶部指向哪里,而非摄像头本身指向哪里,所以我们需要进行一些校正。

  第二个数学计算任务是利用翻转过滤器对斜度进行处理,从而得到一个以度为单位的度量值,其中水平的度量值为90,向上或向下半倾的度量值为45,垂直向上或垂直向下的度量值为0。注意,当得数为45的时候,我们无法确定手机到底是向上倾斜,还是向下倾斜。 这时加速度传感器就派上用场了。它能够确定出倾角的正负,正值表示从水平线向上,复制表示从水平线向下。

  简言之,我们需要的东西都能从加速度传感器那里得到。

  增强现实技术的构件

  到目前为止,打造自己增强现实技术引擎所需的工具我们已经全部介绍过了,您还需要的就是少许数学知识、一些Android版面布局和大量的精力了。如果您对打造增强现实应用程序的兴趣远胜于打造增强现实引擎本身的话,可以关注我当前正在为Android开发的一个开源的增强现实技术引擎。为了获得更多的进展情况,可以在Twitter上跟随twitter.com/androidarkit。

  虽然我喜欢尽可能把所有的数学和绘图代码放在一起,并将三种信息统一叠放到摄像头上,但是这些已经超出了本文的讨论范围。然而,本文加上上一篇文章,已经构成了对Android的指南针、摄像头预览、加速度传感器与GPS子系统进行了全面的介绍。现在,您已经具备了创建大型增强现实技术应用程序所需的全部构件。

0
相关文章