2012-02-26 11 views
3

私はAndroid用の傾斜アプリケーションに取り組んでいます。ポートレート&ランドスケープモードで問題が発生しています。ロールの物理的な変化がない場合、ロールの値が狂ってしまう前に、ピッチ= 90度(終わりの時に電話する)と少し前にさえ。私はこの問題の解決策を見つけることができませんでした。誰かが私を正しい方向に向けることができれば、それは感謝します。Androidピッチとロールの問題

ここに短いコードダンプがあるので、加速度計エラーではありません。私はオイラー(ロール、ピッチ、ヨー)の角度を使用しないであろう

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

私は同じ問題を抱えていますが、回転行列も使用しています。私はTYPE_ROTATION_VECTORを使用しているため、getRotationMatrix()の代わりにgetRotationMatrixFromVector()を使用しています。これら2つの方法に違いはありますか? 2番目の質問はあなたのコードでthisforです if(mAzimuth <0){ mAzimuth + = 360.0f; }? – Nazerke

+0

ベクトルにはコメントできませんが、mAzimuthはコンパスの見出しです。クリーンな0-360の読み値ではないので、ネガティブ値を360に戻す必要があります。正しく計算したい。あなたは、ピッチ、ロール、およびコンパスの見出しをデバイスに尋ねて、それを元に戻すことはできないと思います。単純であったはずの主なPITAを理解することができます。 – user1234051

+0

他の調整方法は?あなたは何が起きているのですか?その部分は修正の部分ですか?私はgetRotationMatrixFromVector()も使用していますし、方位角がピッチで変わっているのを見ています。私は欲しくなく、Googleマップはコンパスモードではありません。 – Flyview

2

。既に気付いたように、アプリの安定性をかなり悪化させます。

ここをクリックして、代わりに何をすればいいですか:Strange behavior with android orientation sensor

+0

おかげで、私はポストをチェックアウトしたオイラーの天使がある理由、私は明確に理解します悪い選択肢ですが、私は回転行列に慣れておらず、Androidでそれらを実装するための良い情報を見つけることができません。その他の参考資料? – user1234051

+0

これは実装する必要はなく、SensorManagerによって実装されます。私は[SensorManager.getRotationMatrix](http://developer.android.com/reference/android/hardware/SensorManager.html#getRotationMatrix)から始めます。 – Ali

+0

ありがとう、私はそれを見てきました。残念ながら、私はGoogleの理論的な例からうまく学ばない。私は、作業用コードを見て、回転行列とAndroidのコンセプトを初めて見て物事を理解します。今は上り坂の1つです。 – user1234051

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

何あなたはジンバルロックと呼ばれています。ピッチ+/- 90で、ヨー - (+)ロールは完全に定義されていません。ピッチが+/- 90近辺になると、実際の姿勢に大きな変化がないにもかかわらず、小さな騒音/姿勢誤差がヨーとロールの大きな変動を個別に引き起こす可能性があります。ここでは(多くのプラットフォームでも実装されていないとどのように持ち運びにくい)、ヨー、ピッチロール上の偉大な書き込みアップです:

http://www.sensorplatforms.com/understanding-orientation-conventions-mobile-platforms/

関連する問題