我正在开发适用于Android的倾斜应用。我对Portrait&景观模式。当音高= 90度(电话结束)时,甚至在滚动值没有发生任何物理变化时,滚动值变得疯狂之前。我一直无法找到解决这个问题的方法。如果有人能指出我正确的方向,我们将不胜感激。
这是一个简短的代码转储,因此您知道它不是加速度计错误。
final SensorEventListener mEventListener = new SensorEventListener(){
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event) {
setListners(sensorManager, mEventListener);
SensorManager.getRotationMatrix(mRotationMatrix, null, mValuesAccel, mValuesMagnet);
SensorManager.getOrientation(mRotationMatrix, mValuesOrientation);
synchronized (this) {
switch (event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
System.arraycopy(event.values, 0, mValuesAccel, 0, 3);
long actualTime = System.currentTimeMillis();
//Sensitivity delay
if (actualTime - lastUpdate < 250) {
return;
}
else {
sysAzimuth = (int)Math.toDegrees(mValuesOrientation[0]);
sysPitch = (int)Math.toDegrees(mValuesOrientation[1]);
sysRoll = (int)Math.toDegrees(mValuesOrientation[2]);
//invert direction with -1
pitch = (sysPitch - pitchCal)*-1;
roll = (sysRoll - rollCal);
azimuth = sysAzimuth;
lastUpdate = actualTime;
}
答案 0 :(得分:8)
我找到了我要找的东西,旋转矩阵。
我使用欧拉角(滚动,俯仰,偏航)进行俯仰和滚转。当手机结束90度时,x和z平原是相同的,手机变得疯狂,这是欧拉角的一个根本缺陷。
我需要通过getRotationMatrix使用旋转矩阵来获得俯仰和滚动度数
这是为了所有人;)
XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- This file is res/layout/main.xml -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button android:id="@+id/update" android:text="Update Values"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doUpdate" />
<Button android:id="@+id/show" android:text="Show Me!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doShow" android:layout_toRightOf="@id/update" />
<TextView android:id="@+id/preferred" android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/update" />
<TextView android:id="@+id/orientation" android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/preferred" />
</RelativeLayout>
代码:
package YOURPACKAGE;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class YOURCLASS extends Activity implements SensorEventListener {
private static final String TAG = "VirtualJax";
private SensorManager mgr;
private Sensor accel;
private Sensor compass;
private Sensor orient;
private TextView preferred;
private TextView orientation;
private boolean ready = false;
private float[] accelValues = new float[3];
private float[] compassValues = new float[3];
private float[] inR = new float[9];
private float[] inclineMatrix = new float[9];
private float[] orientationValues = new float[3];
private float[] prefValues = new float[3];
private float mAzimuth;
private double mInclination;
private int counter;
private int mRotation;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preferred = (TextView)findViewById(R.id.preferred);
orientation = (TextView)findViewById(R.id.orientation);
mgr = (SensorManager) this.getSystemService(SENSOR_SERVICE);
accel = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
compass = mgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
orient = mgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
WindowManager window = (WindowManager) this.getSystemService(WINDOW_SERVICE);
int apiLevel = Integer.parseInt(Build.VERSION.SDK);
if(apiLevel <8) {
mRotation = window.getDefaultDisplay().getOrientation();
}
else {
mRotation = window.getDefaultDisplay().getRotation();
}
}
@Override
protected void onResume() {
mgr.registerListener(this, accel, SensorManager.SENSOR_DELAY_GAME);
mgr.registerListener(this, compass, SensorManager.SENSOR_DELAY_GAME);
mgr.registerListener(this, orient, SensorManager.SENSOR_DELAY_GAME);
super.onResume();
}
@Override
protected void onPause() {
mgr.unregisterListener(this, accel);
mgr.unregisterListener(this, compass);
mgr.unregisterListener(this, orient);
super.onPause();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}
public void onSensorChanged(SensorEvent event) {
// Need to get both accelerometer and compass
// before we can determine our orientationValues
switch(event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
for(int i=0; i<3; i++) {
accelValues[i] = event.values[i];
}
if(compassValues[0] != 0)
ready = true;
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i=0; i<3; i++) {
compassValues[i] = event.values[i];
}
if(accelValues[2] != 0)
ready = true;
break;
case Sensor.TYPE_ORIENTATION:
for(int i=0; i<3; i++) {
orientationValues[i] = event.values[i];
}
break;
}
if(!ready)
return;
if(SensorManager.getRotationMatrix(inR, inclineMatrix, accelValues, compassValues)) {
// got a good rotation matrix
SensorManager.getOrientation(inR, prefValues);
mInclination = SensorManager.getInclination(inclineMatrix);
// Display every 10th value
if(counter++ % 10 == 0) {
doUpdate(null);
counter = 1;
}
}
}
public void doUpdate(View view) {
if(!ready)
return;
mAzimuth = (float) Math.toDegrees(prefValues[0]);
if(mAzimuth < 0) {
mAzimuth += 360.0f;
}
String msg = String.format(
"Preferred:\nazimuth (Z): %7.3f \npitch (X): %7.3f\nroll (Y): %7.3f",
mAzimuth, Math.toDegrees(prefValues[1]),
Math.toDegrees(prefValues[2]));
preferred.setText(msg);
msg = String.format(
"Orientation Sensor:\nazimuth (Z): %7.3f\npitch (X): %7.3f\nroll (Y): %7.3f",
orientationValues[0],
orientationValues[1],
orientationValues[2]);
orientation.setText(msg);
preferred.invalidate();
orientation.invalidate();
}
public void doShow(View view) {
// google.streetview:cbll=30.32454,-81.6584&cbp=1,yaw,,pitch,1.0
// yaw = degrees clockwise from North
// For yaw we can use either mAzimuth or orientationValues[0].
//
// pitch = degrees up or down. -90 is looking straight up,
// +90 is looking straight down
// except that pitch doesn't work properly
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.parse(
"google.streetview:cbll=30.32454,-81.6584&cbp=1," +
Math.round(orientationValues[0]) + ",,0,1.0"
));
startActivity(intent);
return;
}
答案 1 :(得分:2)
我不会使用欧拉角(滚动,俯仰,偏航)。正如您已经注意到的那样,它几乎搞砸了您应用的稳定性。
请参阅此处的原因,以及该怎么做:Strange behavior with android orientation sensor。
答案 2 :(得分:0)
通过实验,我发现当你从纵向模式切换到横向模式时,你的旋转矩阵不会改变,但你必须手动更改它才能正确使用OpenGL
copyMat(mRotationMatrixP, mRotationMatrix);
// permute and negate columns 0, 1
mRotationMatrixP[0] = -mRotationMatrix[1];
mRotationMatrixP[4] = -mRotationMatrix[5];
mRotationMatrixP[8] = -mRotationMatrix[9];
// permute 1, 0
mRotationMatrixP[1] = mRotationMatrix[0];
mRotationMatrixP[5] = mRotationMatrix[4];
mRotationMatrixP[9] = mRotationMatrix[8];
此外,我希望您首先正确获取旋转矩阵:
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(
mRotationMatrix , event.values);
SensorManager.getOrientation (mRotationMatrix, values);
答案 3 :(得分:0)
你所描述的是万向节锁。在音高+/- 90时,偏航 - (+)滚动完全未定义。近距离+/- 90,即使实际方向没有大的变化,小的噪声/姿态误差也会导致偏航和滚动的大幅波动。这是关于偏航,俯仰滚动的一个很好的记录(以及在许多平台上如何很好地实现):
http://www.sensorplatforms.com/understanding-orientation-conventions-mobile-platforms/