web-dev-qa-db-ja.com

オイラー角を方向ベクトルに変換する方法は?

ピッチ、ロール、ヨー角があります。これらを方向ベクトルに変換するにはどうすればよいですか?

これの四元数および/または行列表現を見せていただければ特にクールです!

46
Polaris878

残念ながら、これらのことを定義する方法にはさまざまな規則があります(そして、ロール、ピッチ、ヨーはオイラー角とまったく同じではありません)ので、注意する必要があります。

Pitch = 0を水平(z = 0)として定義し、ヨーをx軸から反時計回りとして定義すると、方向ベクトルは

 x = cos(yaw)* cos(pitch)
 y = sin(yaw)* cos(pitch)
 z = sin(pitch)

ロールを使用していないことに注意してください。これは方向単位ベクトルであり、姿勢を指定しません。飛行物体のフレームに物を運ぶ回転行列を書くのは簡単です(たとえば、左の翼の先端がどこを指しているのか知りたい場合)が、最初に規約を指定することは本当に良い考えです。問題について詳しく教えてください。

編集:(私は2年半この質問に戻るつもりでした。)

完全な回転行列の場合、上記の規則を使用し、ベクトルを最初にヨー、次にピッチ、次にロールさせ、世界座標フレームの最終座標を取得するために、逆の順序で回転行列を適用する必要があります。

最初のロール:

| 1    0          0      |
| 0 cos(roll) -sin(roll) |
| 0 sin(roll)  cos(roll) |

ピッチ:

| cos(pitch) 0 -sin(pitch) |
|     0      1      0      |
| sin(pitch) 0  cos(pitch) |

ヨー:

| cos(yaw) -sin(yaw) 0 |
| sin(yaw)  cos(yaw) 0 |
|    0         0     1 |

それらを組み合わせると、合計回転行列は次のようになります。

| cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)|
| sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)|
| sin(pitch)          cos(pitch)sin(roll)                            cos(pitch)sin(roll)|

したがって、x軸から始まる単位ベクトルの場合、最終的な座標は次のようになります。

x = cos(yaw)cos(pitch)
y = sin(yaw)cos(pitch)
z = sin(pitch)

また、y軸(左の翼端)から始まる単位ベクトルの場合、最終的な座標は次のようになります。

x = -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll)
y = -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll)
z =  cos(pitch)sin(roll)
72
Beta

3つのオイラー角を適用する順序に応じて、マトリックスに変換する6つの異なる方法があります。

typedef float Matrix[3][3];
struct EulerAngle { float X,Y,Z; };

// Euler Order enum.
enum EEulerOrder
{
    ORDER_XYZ,
    ORDER_YZX,
    ORDER_ZXY,
    ORDER_ZYX,
    ORDER_YXZ,
    ORDER_XZY
};


Matrix EulerAnglesToMatrix(const EulerAngle &inEulerAngle,EEulerOrder EulerOrder)
{
    // Convert Euler Angles passed in a vector of Radians
    // into a rotation matrix.  The individual Euler Angles are
    // processed in the order requested.
    Matrix Mx;

    const FLOAT    Sx    = sinf(inEulerAngle.X);
    const FLOAT    Sy    = sinf(inEulerAngle.Y);
    const FLOAT    Sz    = sinf(inEulerAngle.Z);
    const FLOAT    Cx    = cosf(inEulerAngle.X);
    const FLOAT    Cy    = cosf(inEulerAngle.Y);
    const FLOAT    Cz    = cosf(inEulerAngle.Z);

    switch(EulerOrder)
    {
    case ORDER_XYZ:
        Mx.M[0][0]=Cy*Cz;
        Mx.M[0][1]=-Cy*Sz;
        Mx.M[0][2]=Sy;
        Mx.M[1][0]=Cz*Sx*Sy+Cx*Sz;
        Mx.M[1][1]=Cx*Cz-Sx*Sy*Sz;
        Mx.M[1][2]=-Cy*Sx;
        Mx.M[2][0]=-Cx*Cz*Sy+Sx*Sz;
        Mx.M[2][1]=Cz*Sx+Cx*Sy*Sz;
        Mx.M[2][2]=Cx*Cy;
        break;

    case ORDER_YZX:
        Mx.M[0][0]=Cy*Cz;
        Mx.M[0][1]=Sx*Sy-Cx*Cy*Sz;
        Mx.M[0][2]=Cx*Sy+Cy*Sx*Sz;
        Mx.M[1][0]=Sz;
        Mx.M[1][1]=Cx*Cz;
        Mx.M[1][2]=-Cz*Sx;
        Mx.M[2][0]=-Cz*Sy;
        Mx.M[2][1]=Cy*Sx+Cx*Sy*Sz;
        Mx.M[2][2]=Cx*Cy-Sx*Sy*Sz;
        break;

    case ORDER_ZXY:
        Mx.M[0][0]=Cy*Cz-Sx*Sy*Sz;
        Mx.M[0][1]=-Cx*Sz;
        Mx.M[0][2]=Cz*Sy+Cy*Sx*Sz;
        Mx.M[1][0]=Cz*Sx*Sy+Cy*Sz;
        Mx.M[1][1]=Cx*Cz;
        Mx.M[1][2]=-Cy*Cz*Sx+Sy*Sz;
        Mx.M[2][0]=-Cx*Sy;
        Mx.M[2][1]=Sx;
        Mx.M[2][2]=Cx*Cy;
        break;

    case ORDER_ZYX:
        Mx.M[0][0]=Cy*Cz;
        Mx.M[0][1]=Cz*Sx*Sy-Cx*Sz;
        Mx.M[0][2]=Cx*Cz*Sy+Sx*Sz;
        Mx.M[1][0]=Cy*Sz;
        Mx.M[1][1]=Cx*Cz+Sx*Sy*Sz;
        Mx.M[1][2]=-Cz*Sx+Cx*Sy*Sz;
        Mx.M[2][0]=-Sy;
        Mx.M[2][1]=Cy*Sx;
        Mx.M[2][2]=Cx*Cy;
        break;

    case ORDER_YXZ:
        Mx.M[0][0]=Cy*Cz+Sx*Sy*Sz;
        Mx.M[0][1]=Cz*Sx*Sy-Cy*Sz;
        Mx.M[0][2]=Cx*Sy;
        Mx.M[1][0]=Cx*Sz;
        Mx.M[1][1]=Cx*Cz;
        Mx.M[1][2]=-Sx;
        Mx.M[2][0]=-Cz*Sy+Cy*Sx*Sz;
        Mx.M[2][1]=Cy*Cz*Sx+Sy*Sz;
        Mx.M[2][2]=Cx*Cy;
        break;

    case ORDER_XZY:
        Mx.M[0][0]=Cy*Cz;
        Mx.M[0][1]=-Sz;
        Mx.M[0][2]=Cz*Sy;
        Mx.M[1][0]=Sx*Sy+Cx*Cy*Sz;
        Mx.M[1][1]=Cx*Cz;
        Mx.M[1][2]=-Cy*Sx+Cx*Sy*Sz;
        Mx.M[2][0]=-Cx*Sy+Cy*Sx*Sz;
        Mx.M[2][1]=Cz*Sx;
        Mx.M[2][2]=Cx*Cy+Sx*Sy*Sz;
        break;
    }
    return(Mx);
}

FWIW、一部のCPUはSin&Cosを同時に計算できます(x86のfsincosなど)。これを行うと、初期のsin&cos値を計算するために、6回ではなく3回の呼び出しで少し速くすることができます。

更新:右利きの結果か左利きの結果かによって、実際には12の方法があります。角度を無効にすることで、「利き手」を変更できます。

19
Adisak

ベータ版は私の一日を救った。しかし、私はわずかに異なる基準座標系を使用しており、ピッチの私の定義は上下です(同意して頭をうなずきます)ピッチは yになります-成分。私の参照ベクトルはOpenGlスタイル(-z軸に沿って)であるため、yaw = 0、pitch = 0の場合、結果の単位ベクトルは(0、0、-1)に等しくなります。誰かがこの投稿に出くわし、ベータの公式をこの特定のシステムに変換するのが難しい場合、私が使用する方程式は次のとおりです。

vDir->X = sin(yaw);
vDir->Y = -(sin(pitch)*cos(yaw));
vDir->Z = -(cos(pitch)*cos(yaw));

符号の変更とヨー<->ピッチスワップに注意してください。これが誰かの時間を節約することを願っています。

8
pauluss86

ここであなたの定義について明確にする必要があります-特に、あなたが望むベクトルは何ですか?航空機が向いている方向の場合、ロールはそれにも影響を与えず、あなたはただ 球座標 (おそらく軸/角度を入れ替えた状態)を使用しています。

一方、特定のベクトルを取得してこれらの角度で変換する場合は、回転行列を探しています。回転行列の wiki記事 には、xyz回転行列に基づいたヨーピッチロール回転の式が含まれています。ギリシャ文字とマトリックスが関係しているので、ここに入力しようとはしません。

1
Cascabel

FreeCADでの実装を探しているときに誰かがつまずいた場合。

import FreeCAD, FreeCADGui
from FreeCAD import Vector
from math import sin, cos, pi

cr = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().toEuler()
crx = cr[2] # Roll
cry = cr[1] # Pitch
crz = cr[0] # Yaw

crx = crx * pi / 180.0
cry = cry * pi / 180.0
crz = crz * pi / 180.0

x = sin(crz)
y = -(sin(crx) * cos(crz))
z = cos(crx) * cos(cry)

view = Vector(x, y, z)
0
nvd