我正在实现一个指南针,从中获取读数SensorManager.getRotationMatrix
(参见下面的代码)。
我有一个imageView
使用RotateAnimation
. 指南针和动画工作正常,除了一个问题:
通过SensorManager.getOrientation
我得到一个包含三个值的数组——方位角、俯仰角和滚动角。我只使用array[0]
持有方位角值的
如果我将手机平放并在 Z 轴(方位角)上转动它 - 它可以完美运行。但是,当我在 X 或 Y 轴(俯仰或滚动)上倾斜手机的那一刻 - 指南针会偏离正确的测量值。换句话说 - 当倾斜俯仰或滚动时 - 它会严重影响方位角的读数。
所以,总结一下我的问题 - 我将如何阻止来自 Pitch/Roll 读数的干扰(尽管我根本没有在代码中解决它们) - 或者,我做错了什么?
提前致谢!
这是我的大部分代码:
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor accelerometer;
private Sensor magnetometer;
private float[] mGravity;
private float[] mGeomagnetic;
float avgRead[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private TextView tvCurrAzim;
private ImageView ivCompass;
private float currentDegree = 0f;
private float azimuth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
tvCurrAzim = (TextView) findViewById(R.id.tvaz);
ivCompass = (ImageView) findViewById(R.id.imageView1);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
// Compass Sensor Methods:
@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)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
//Creating a running smooth average of readings
avgRead[0] = avgRead[1];
avgRead[1] = avgRead[2];
avgRead[2] = avgRead[3];
avgRead[3] = avgRead[4];
avgRead[4] = avgRead[5];
avgRead[5] = avgRead[6];
avgRead[6] = avgRead[7];
avgRead[7] = avgRead[8];
avgRead[8] = orientation[0]; // orientation contains: azimuth, pitch and roll
azimuth = (avgRead[0] + avgRead[1] + avgRead[2] + avgRead[3]
+ avgRead[4] + avgRead[5] + avgRead[6] + avgRead[7] + avgRead[8]) / 9;
azimuth = Math.round(azimuth * 360 / (2 * 3.14159f));
if (azimuth < 0 && azimuth > -180)
azimuth += 360;
}
}
tvCurrAzim.setText(Float.toString(azimuth));
// get the angle around the z-axis rotated
// create a rotation animation (reverse turn degree degrees)
if (-azimuth - currentDegree > 180)
azimuth = azimuth - 360;
RotateAnimation ra = new RotateAnimation(currentDegree, -azimuth,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
// how long the animation will take place
ra.setDuration(50);
// set the animation after the end of the reservation status
ra.setFillAfter(true);
// Start the animation
ivCompass.startAnimation(ra);
currentDegree = -azimuth;
}
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
}