关闭

Android 方向传感器与磁力计和加速度传感器之间的关系

247人阅读 评论(0) 收藏 举报
分类:

        一般情况下,在android系统中获取手机的方位信息azimuth似乎是很简单的事情,在api中有TYPE_ORIENTATION常量,可以像得到加速度传感器那样得到方向传感器sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);然而我们这样做的话在最新版的SDK中就会看到这么一句话:“TYPE_ORIENTATION   This constant is deprecated. use SensorManager.getOrientation() instead. ”即这种方式也过期,不建议使用!Google建议我们在应用程序中使用SensorManager.getOrientation()来获得原始数据。

   其实,Android中的方向传感器也是是通过磁力计magnetometer和加速度传感器accelerometer抽象出来的。因此我们可以通过磁力计magnetometer和加速度传感器accelerometer来获得方位信息。由磁场和加速度如何得到方位信息的算法在api中已被封装好了。通过这种方式比直接获得方向传感器获得的信息更准确。

values[0]  :azimuth 方向角,但用(磁场+加速度)得到的数据范围是(-180180,也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。而直接通过方向感应器数据范围是(0359360/0表示正北,90表示正东,180表示正南,270表示正西。

values[1]  pitch 倾斜   即由静止状态开始,前后翻转

values[2]  roll 旋转角  即由静止状态开始,左右翻转

//api中源码

 public static float[] getOrientation(float[] R, float values[]) {
        /*
         * 4x4 (length=16) case:
         *   /  R[ 0]   R[ 1]   R[ 2]   0  \
         *   |  R[ 4]   R[ 5]   R[ 6]   0  |
         *   |  R[ 8]   R[ 9]   R[10]   0  |
         *   \      0       0       0   1  /
         *   
         * 3x3 (length=9) case:
         *   /  R[ 0]   R[ 1]   R[ 2]  \
         *   |  R[ 3]   R[ 4]   R[ 5]  |
         *   \  R[ 6]   R[ 7]   R[ 8]  /
         * 
         */
        if (R.length == 9) {
            values[0] = (float)Math.atan2(R[1], R[4]);
            values[1] = (float)Math.asin(-R[7]);
            values[2] = (float)Math.atan2(-R[6], R[8]);
        } else {
            values[0] = (float)Math.atan2(R[1], R[5]);
            values[1] = (float)Math.asin(-R[9]);
            values[2] = (float)Math.atan2(-R[8], R[10]);
        }
        return values;
    }

//getRotaionMatrix源码

 public static boolean getRotationMatrix(float[] R, float[] I,
            float[] gravity, float[] geomagnetic) {
        // TODO: move this to native code for efficiency
        float Ax = gravity[0];
        float Ay = gravity[1];
        float Az = gravity[2];
        final float Ex = geomagnetic[0];
        final float Ey = geomagnetic[1];
        final float Ez = geomagnetic[2];
        float Hx = Ey*Az - Ez*Ay;
        float Hy = Ez*Ax - Ex*Az;
        float Hz = Ex*Ay - Ey*Ax;
        final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
        if (normH < 0.1f) {
            // device is close to free fall (or in space?), or close to
            // magnetic north pole. Typical values are  > 100.
            return false;
        }
        final float invH = 1.0f / normH;
        Hx *= invH;
        Hy *= invH;
        Hz *= invH;
        final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
        Ax *= invA;
        Ay *= invA;
        Az *= invA;
        final float Mx = Ay*Hz - Az*Hy;
        final float My = Az*Hx - Ax*Hz;
        final float Mz = Ax*Hy - Ay*Hx;
        if (R != null) {
            if (R.length == 9) {
                R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
                R[3] = Mx;     R[4] = My;     R[5] = Mz;
                R[6] = Ax;     R[7] = Ay;     R[8] = Az;
            } else if (R.length == 16) {
                R[0]  = Hx;    R[1]  = Hy;    R[2]  = Hz;   R[3]  = 0;
                R[4]  = Mx;    R[5]  = My;    R[6]  = Mz;   R[7]  = 0;
                R[8]  = Ax;    R[9]  = Ay;    R[10] = Az;   R[11] = 0;
                R[12] = 0;     R[13] = 0;     R[14] = 0;    R[15] = 1;
            }
        }
        if (I != null) {
            // compute the inclination matrix by projecting the geomagnetic
            // vector onto the Z (gravity) and X (horizontal component
            // of geomagnetic vector) axes.
            final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
            final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
            final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
            if (I.length == 9) {
                I[0] = 1;     I[1] = 0;     I[2] = 0;
                I[3] = 0;     I[4] = c;     I[5] = s;
                I[6] = 0;     I[7] =-s;     I[8] = c;
            } else if (I.length == 16) {
                I[0] = 1;     I[1] = 0;     I[2] = 0;
                I[4] = 0;     I[5] = c;     I[6] = s;
                I[8] = 0;     I[9] =-s;     I[10]= c;
                I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
                I[15] = 1;
            }
        }
        return true;
    }

其中R[]数据是旋转数组,用来存放磁场和加速度的数据。之后在通过getOrientation方法通过一定的算法利用R[]得到方位信息values[]数组。

编写的代码如下:

[java] view plaincopy
  1. package xuan.android.orientation;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Context;  
  5. import android.hardware.Sensor;  
  6. import android.hardware.SensorEvent;  
  7. import android.hardware.SensorEventListener;  
  8. import android.hardware.SensorManager;  
  9. import android.os.Bundle;  
  10. import android.widget.TextView;  
  11.   
  12. public class OrientationActivity extends Activity {  
  13.     /** Called when the activity is first created. */  
  14.     TextView textview=null;  
  15.     private SensorManager sm=null;  
  16.     private Sensor aSensor=null;  
  17.     private Sensor mSensor=null;  
  18.        
  19.     float[] accelerometerValues=new float[3];  
  20.     float[] magneticFieldValues=new float[3];  
  21.     float[] values=new float[3];  
  22.     float[] rotate=new float[9];  
  23.       
  24.     @Override  
  25.     public void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.main);  
  28.         textview=(TextView)findViewById(R.id.view0);  
  29.         sm=(SensorManager)getSystemService(Context.SENSOR_SERVICE);  
  30.         aSensor=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);  
  31.         mSensor=sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);  
  32.         sm.registerListener(myListener, aSensor, SensorManager.SENSOR_DELAY_GAME);  
  33.         sm.registerListener(myListener, mSensor, SensorManager.SENSOR_DELAY_GAME);  
  34.           
  35.           
  36.     }  
  37.   
  38.     @Override  
  39.     protected void onPause() {  
  40.         // TODO Auto-generated method stub  
  41.         super.onPause();  
  42.         sm.unregisterListener(myListener);  
  43.     }  
  44.     final SensorEventListener myListener=new SensorEventListener(){  
  45.   
  46.         @Override  
  47.         public void onAccuracyChanged(Sensor sensor, int accuracy) {  
  48.             // TODO Auto-generated method stub  
  49.               
  50.         }  
  51.   
  52.         @Override  
  53.         public void onSensorChanged(SensorEvent event) {  
  54.             // TODO Auto-generated method stub  
  55.             if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){  
  56.                 accelerometerValues=event.values;  
  57.             }  
  58.             if(event.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD){  
  59.                 magneticFieldValues=event.values;  
  60.             }  
  61.               
  62.             SensorManager.getRotationMatrix(rotate, null, accelerometerValues, magneticFieldValues);  
  63.             SensorManager.getOrientation(rotate, values);  
  64.             //经过SensorManager.getOrientation(rotate, values);得到的values值为弧度  
  65.             //转换为角度  
  66.             values[0]=(float)Math.toDegrees(values[0]);  
  67.             textview.setText("x="+values[0]);  
  68.         }};  
  69.           
  70.       
  71.       
  72. }  
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:13636次
    • 积分:240
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:29篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档