Как преобразовать углы Эйлера в вектор направления?

У меня есть угол тангажа, крена и рыскания. Как бы я преобразовать их в вектор направления?

Было бы особенно здорово, если бы вы могли показать мне кватернион и / или матричное представление этого!

5 ответов

Решение

К сожалению, существуют разные соглашения о том, как определять эти вещи (и крен, наклон, рыскание не совсем совпадают с углами Эйлера), поэтому вам нужно быть осторожным.

Если мы определим шаг =0 как горизонтальный (z=0) и отклонение от оси против часовой стрелки против часовой стрелки, то вектор направления будет

x = cos(рыскание)*cos(шаг)
у = грех (рыскание) * соз (шаг)
z = грех (шаг)

Обратите внимание, что я не использовал рулон; это вектор единицы направления, он не определяет ориентацию. Достаточно просто написать матрицу вращения, которая будет переносить вещи в кадр летающего объекта (если вы хотите знать, скажем, куда указывает левый кончик крыла), но это действительно хорошая идея - сначала указать условные обозначения. Можете ли вы рассказать нам больше о проблеме?

РЕДАКТИРОВАТЬ:(Я хотел вернуться к этому вопросу в течение двух с половиной лет.)

Для полной матрицы вращения, если мы используем вышеупомянутое соглашение и хотим, чтобы вектор сначала отклонялся, затем качался, а затем вращался, чтобы получить окончательные координаты в системе координат мира, мы должны применить матрицы вращения в обратном порядке.

Первый бросок:

| 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 = cos(yaw)cos(pitch)
y = sin(yaw)cos(pitch)
z = sin(pitch)

А для единичного вектора, который начинается на оси у (левый кончик крыла), окончательные координаты будут:

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)

Существует шесть различных способов преобразования трех углов Эйлера в матрицу в зависимости от применяемого порядка:

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

Кстати, некоторые процессоры могут одновременно вычислять Sin & Cos (например, fsincos на x86). Если вы сделаете это, вы можете сделать это немного быстрее с помощью трех вызовов вместо 6, чтобы вычислить начальные значения sin & cos.

Обновление: на самом деле существует 12 способов, в зависимости от того, хотите ли вы получить результаты для правой или левой руки - вы можете изменить "руку", отрицая углы.

Бета спасла мой день. Однако я использую немного иную систему координат, и мое определение высоты тона вверх / вниз (кивая головой в согласии), где положительный шаг приводит к отрицательному 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));

Обратите внимание на изменение знака и сдвиг рыскания <->. Надеюсь, это сэкономит кому-то время.

Вы должны уточнить ваши определения здесь - в частности, какой вектор вы хотите? Если это направление, которое указывает самолет, крен даже не влияет на него, и вы просто используете сферические координаты (возможно, с переставленными осями / углами).

Если, с другой стороны, вы хотите взять данный вектор и преобразовать его под эти углы, вы ищете матрицу вращения. Статья вики о матрицах вращения содержит формулу для вращения вращения рысканья, основанную на матрицах вращения XYZ. Я не буду пытаться ввести его здесь, учитывая греческие буквы и матрицы.

Если кто-то натыкается на поиск реализации во 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)
Другие вопросы по тегам