0
点赞
收藏
分享

微信扫一扫

android 传感器使用与开发----方向传感器

ZMXQQ233 2023-04-13 阅读 116



指南针 ,导航


一般情况下,在android系统中获取手机的方位信息azimuth似乎是很简单的事情,在api中有TYPE_ORIENTATION常量,可以像得到加速度传感器那样得到方向传感器sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);然而,这一方法目前已不再使用。


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

values[0]  :azimuth 方向角,但用(磁场+加速度)得到的数据范围是(-180~180),也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。而直接通过方向感应器数据范围是(0~359)360/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[]数组。




Code :

public class Orientation extends Activity implements
 
private SensorManager sm;
private ImageView orientation;
private Sensor aSensor;
private Sensor mSensor;
 
float[] accelerometerValues = new float[3];
float[] magneticFieldValues = new float[3];
float[] values =  new float[3];
float[] rotate =  new float[9];
 
@Override
protected void
//  TODO
super.onCreate(savedInstanceState);
setContentView(R.layout.orientation);
orientation = (ImageView) findViewById(R.id.orientation);
orientation.setKeepScreenOn(true);
 
}
 
@Override
protected void
super.onResume();
sm = (SensorManager) this.getSystemService(SENSOR_SERVICE);
aSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
 
if (aSensor != null && mSensor != null) {
sm.registerListener(this, aSensor,
SensorManager.SENSOR_DELAY_NORMAL);
sm.registerListener(this, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
}
 
@Override
protected void
super.onPause();
sm.unregisterListener(this, aSensor);
sm.unregisterListener(this, mSensor);
}
 
private float predegree = 0;
 
@Override
public  void
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
accelerometerValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
magneticFieldValues = event.values;
}
 
SensorManager.getRotationMatrix(rotate, null, accelerometerValues,
magneticFieldValues);
/* 经过SensorManager.getOrientation(rotate, values);得到的values值为弧度 */
SensorManager.getOrientation(rotate, values);
/* 转换为角度 */
values[0] = (float) Math.toDegrees(values[0]);
float degree = values[0];
Log.i("jarlen", " degree = " + degree + "  values[0] =  " + values[0]);
if (Math.abs(degree + predegree) > 1) {
/** 动画效果 */
RotateAnimation animation =  new RotateAnimation(predegree, degree,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(200);
orientation.startAnimation(animation);
}
predegree
}
 
@Override
public  void onAccuracyChanged(Sensor sensor, int
//  TODO
 
}
 }




举报

相关推荐

0 条评论