您的位置:首页 > 移动开发 > Android开发

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

2012-04-12 16:43 477 查看
一般情况下,在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 方向角,但用(磁场+加速度)得到的数据范围是(-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[]数组。
编写的代码如下:
package xuan.android.orientation;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class OrientationActivity extends Activity {
    /** Called when the activity is first created. */
	TextView textview=null;
	private SensorManager sm=null;
	private Sensor aSensor=null;
	private Sensor mSensor=null;
	 
	float[] accelerometerValues=new float[3];
	float[] magneticFieldValues=new float[3];
	float[] values=new float[3];
	float[] rotate=new float[9];
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textview=(TextView)findViewById(R.id.view0);
        sm=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
        aSensor=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensor=sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        sm.registerListener(myListener, aSensor, SensorManager.SENSOR_DELAY_GAME);
        sm.registerListener(myListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
        
        
    }

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		sm.unregisterListener(myListener);
	}
	final SensorEventListener myListener=new SensorEventListener(){

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onSensorChanged(SensorEvent event) {
			// TODO Auto-generated method stub
			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);
			//经过SensorManager.getOrientation(rotate, values);得到的values值为弧度
			//转换为角度
			values[0]=(float)Math.toDegrees(values[0]);
			textview.setText("x="+values[0]);
		}};
		
	
    
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: