デバイスMagnetometerとAccelerometerに基づいてrotationMatrix
を返すセンサーマネージャーがあります。ユーザーのデバイスのヨーピッチとロールも計算しようとしていますが、そのピッチとロールが互いに干渉し、不正確な結果が得られます。 rotationMatrix
からデバイスのヨーピッチとロールを抽出する方法はありますか?
[〜#〜] edit [〜#〜]下記のブレンダーの答えを解釈しようとしています。これはありがたいことにまだ感謝していませんが、次のような回転行列から角度を取得しようとしています。
float R[] = phoneOri.getMatrix();
double rmYaw = Math.atan2(R[4], R[0]);
double rmPitch = Math.acos(-R[8]);
double rmRoll = Math.atan2(R[9], R[10]);
マトリックスの間違った部分を参照しているかどうかはわかりませんが、思い通りの結果が得られません。
度単位の値を取得することを望んでいましたが、奇妙な整数を取得しています。
私の行列は、次のようなsensorManager
から取得されます。
public void onSensorChanged(SensorEvent evt) {
int type=evt.sensor.getType();
if(type == Sensor.TYPE_ORIENTATION){
yaw = evt.values[0];
pitch = evt.values[1];
roll = evt.values[2];
}
if (type == Sensor.TYPE_MAGNETIC_FIELD) {
orientation[0]=(orientation[0]*1+evt.values[0])*0.5f;
orientation[1]=(orientation[1]*1+evt.values[1])*0.5f;
orientation[2]=(orientation[2]*1+evt.values[2])*0.5f;
} else if (type == Sensor.TYPE_ACCELEROMETER) {
acceleration[0]=(acceleration[0]*2+evt.values[0])*0.33334f;
acceleration[1]=(acceleration[1]*2+evt.values[1])*0.33334f;
acceleration[2]=(acceleration[2]*2+evt.values[2])*0.33334f;
}
if ((type==Sensor.TYPE_MAGNETIC_FIELD) || (type==Sensor.TYPE_ACCELEROMETER)) {
float newMat[]=new float[16];
SensorManager.getRotationMatrix(newMat, null, acceleration, orientation);
if(displayOri==0||displayOri==2){
SensorManager.remapCoordinateSystem(newMat,SensorManager.AXIS_X*-1, SensorManager.AXIS_MINUS_Y*-1,newMat);
}else{
SensorManager.remapCoordinateSystem(newMat,SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X,newMat);
}
matrix=newMat;
デバイスが表を上にして置いているときのサンプルマトリックス
0.9916188, -0.12448014, -0.03459576, 0.0
0.12525482, 0.9918981, 0.021199778, 0.0
0.031676512,-0.025355382, 0.9991765, 0.0
0.0, 0.0, 0.0, 1
[〜#〜]回答[〜#〜]
double rmPitch = Math.toDegrees( Math.acos(R[10]));
ヨー、ピッチ、ロールはオイラー角に対応します。 変換行列をオイラー角に変換する は非常に簡単です。
ブレンダーは、回転行列からオイラー角(z-x-z外因性)への変換を行い、ロールピッチヨーは別の種類のオイラー角(z-y-x外因性)であるため、答えは正しくないと私は思います。
実際の変換式は次のようになります。
yaw=atan2(R(2,1),R(1,1));
pitch=atan2(-R(3,1),sqrt(R(3,2)^2+R(3,3)^2)));
roll=atan2(R(3,2),R(3,3));
フィードバック:この実装は、表現の特異点(ジンバルロック)の近くで数値の安定性に欠けることが明らかになりました。したがって、C++では、次のコード行でEigenライブラリを使用することをお勧めします。
R.eulerAngles(2,1,0).reverse();
(詳細 ここ )
センサーマネージャーは、3つの角度すべてを取得する SensorManager.getOrientation を提供します。