web-dev-qa-db-fra.com

Comment convertir les angles d'Euler en vecteur directionnel?

J'ai des angles de tangage, de roulis et de lacet. Comment pourrais-je les convertir en un vecteur directionnel?

Ce serait particulièrement bien si vous pouviez me montrer une représentation quaternion et/ou matricielle de ceci! 

41
Polaris878

Malheureusement, il existe différentes conventions sur la façon de définir ces éléments (et le roulis, la tangence et le lacet ne sont pas tout à fait identiques aux angles d'Euler), vous devez donc faire attention.

Si nous définissons pitch = 0 en horizontal (z = 0) et en lacet dans le sens anti-horaire à partir de l'axe des x, le vecteur de direction sera alors

 x = cos (lacet) * cos (tangage) 
 y = sin (lacet) * cos (tangage) 
 z = sin (tang) 

Notez que je n'ai pas utilisé le rouleau; c'est un vecteur d'unité de direction, il ne spécifie pas l'attitude. Il est assez facile d’écrire une matrice de rotation qui transportera des objets dans le cadre de l’objet volant (si vous voulez savoir, par exemple, où pointe le bout de l’aile gauche), mais c’est vraiment une bonne idée de spécifier d’abord les conventions. Pouvez-vous nous en dire plus sur le problème?

EDIT: (Je voulais revenir à cette question depuis deux ans et demi.)

Pour la matrice de rotation complète, si nous utilisons la convention ci-dessus et que nous voulons que le vecteur se mette en lacet, puis tangte, puis roule, pour obtenir les coordonnées finales dans le cadre de coordonnées mondial, nous devons appliquer les matrices de rotation dans l'ordre inverse.

Premier rouleau:

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

puis tangez:

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

alors lacet:

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

Combinez-les et la matrice de rotation totale est:

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

Donc, pour un vecteur unitaire qui commence sur l’axe des x, les coordonnées finales seront:

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

Et pour le vecteur unitaire qui commence sur l’axe des y (les extrémités de l’aile gauche), les coordonnées finales seront:

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)
65
Beta

Il existe six manières différentes de convertir trois angles d'Euler en une matrice en fonction de l'ordre dans lequel ils sont appliqués:

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, certains processeurs peuvent calculer Sin & Cos simultanément (par exemple, fsincos sur x86). Si vous faites cela, vous pouvez accélérer un peu plus avec trois appels plutôt que 6 pour calculer les valeurs initiales de sin & cos.

Mise à jour: Il existe en fait 12 façons de choisir si vous voulez obtenir des résultats avec droitier ou gaucher - vous pouvez modifier la "précision" en inversant les angles.

19
Adisak

Beta a sauvé ma journée. Cependant, j'utilise un système de coordonnées de référence légèrement différent et ma définition de la hauteur est haut/bas (acquiesce de la tête en accord), où un positif hauteur donne un négatif y-composante. Mon vecteur de référence est le style OpenGl (en bas de l'axe -z). Ainsi, avec yaw = 0, pitch = 0, le vecteur unitaire résultant devrait être égal à (0, 0, -1) . Si quelqu'un rencontre ce message et a des difficultés à traduire Les formules de Beta à ce système particulier, les équations que j'utilise sont:

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

Notez le changement de signe et le changement de lacet en lacet <->. J'espère que cela sauvera du temps à quelqu'un.

8
pauluss86

Vous devez préciser vos définitions ici - en particulier, quel est le vecteur que vous voulez? Si c'est la direction d'un avion, le roulis ne l'affecte même pas et vous utilisez simplement coordonnées sphériques (probablement avec axes/angles permutés).

Si par contre vous voulez prendre un vecteur donné et le transformer par ces angles, vous recherchez une matrice de rotation. Le article wiki sur les matrices de rotation contient une formule pour une rotation yaw-pitch-roll, basée sur les matrices de rotation xyz. Je ne vais pas essayer de le saisir ici, étant donné les lettres grecques et les matrices impliquées.

1
Cascabel

Si quelqu'un tombe sur la recherche d'une implémentation dans 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