2012-02-26 39 views
3

我正在为Android安装倾斜应用程序。我有肖像问题&风景模式。当间距= 90度(手机结束)时,甚至在滚动值没有发生物理变化时滚动值变得疯狂。我一直无法找到解决这个问题的办法。如果任何人都可以指出我正确的方向,将不胜感激。Android Pitch and Roll问题

下面是一个简短代码转储,因此您知道这不是加速度计错误。

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; 
        } 

回答

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; 
} 
+0

我有同样的问题,虽然我也使用旋转矩阵。我使用getRotationMatrixFromVector()而不是getRotationMatrix(),因为我使用的是TYPE_ROTATION_VECTOR。这两种方法有什么区别吗? 第二个问题是你在代码 这是什么if(mAzimuth <0){0} {0} {0} {0} {0} }? – Nazerke 2013-03-14 11:31:33

+0

无法对矢量进行评论,但mAzimuth是罗盘标题,它不会将其作为干净的0-360阅读提供,您需要将负值转换回360,并加上其他许多调整想要正确计算。你会认为你可以问设备的俯仰,滚动和指南针的标题,并把它拿回来,没有办法,你可以弄明白,一个主要的PITA应该是简单的。 – user1234051 2013-03-14 15:00:52

+0

那些其他的调整是什么?你最终用mInclination做什么?这是矫正的一部分吗?我也使用getRotationMatrixFromVector(),并且看到方位角随着音高而变化,我不想这样做,而Google地图在罗盘模式下也不适用。 – Flyview 2016-03-16 18:03:57

2

我不会用欧拉角(滚动,俯仰,偏航)。正如你已经注意到的那样,它几乎把你的应用的稳定性搞砸了。

看到这里为什么,以及如何做:Strange behavior with android orientation sensor

+0

谢谢,我检查了后,我清楚地明白为什么欧拉天使是不好的选择,但我不熟悉旋转矩阵,并找不到有关在Android中实现它们的任何好信息。任何其他参考? – user1234051 2012-02-26 22:22:04

+0

您不必实施它,它由SensorManager实施。我将从[SensorManager.getRotationMatrix](http://developer.android.com/reference/android/hardware/SensorManager.html#getRotationMatrix)开始。 – Ali 2012-02-26 23:07:41

+0

谢谢,我已经看过。不幸的是,我从Google的理论示例中学得不好。我通过查看工作代码来了解情况,这些代码是新的旋转矩阵和Android的概念。现在就是一次艰难的攀登。 – user1234051 2012-02-26 23:48:22

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);