Comment convertir Euler angles en vecteur directionnel?

j'ai des angles de tangage, de roulis et de lacet. Comment les convertir en vecteur directionnel?

ce serait particulièrement cool si vous pouviez me montrer une représentation du quaternion et/ou de la matrice de ceci!

40
demandé sur Makoto 2009-10-14 23:50:42

5 réponses

malheureusement, il y a différentes conventions sur la façon de définir ces choses (et le roulis, le tangage, le lacet ne sont pas tout à fait les mêmes que les angles D'Euler), donc vous devrez être prudent.

si nous définissons pitch=0 comme étant horizontal (z=0) et yaw comme étant dans le sens contraire des aiguilles d'une montre par rapport à l'axe des x, alors le vecteur de direction sera

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

notez que je n'ai pas utilisé roll; c'est le vecteur Unité de direction, il ne spécifie pas l'assiette. Il est assez facile d'écrire une matrice de rotation qui portera des choses dans le cadre de l'objet volant (si vous voulez savoir, dire, où l'aile gauche-pointe pointe), mais c'est vraiment une bonne idée de préciser les conventions de premier. 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 fasse un mouvement de lacet en premier, puis un mouvement de tangage, puis un mouvement de roulis, afin d'obtenir la finale coordonnées dans le cadre de coordonnées du monde 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) |

hauteur:

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

un mouvement de 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 par l'axe 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 à l'axe des y (l'aile gauche-pointe), la finale coordonnées:

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)
64
répondu Beta 2016-05-13 21:57:15

il y a six façons différentes de convertir trois Angles D'Euler en matrice selon 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 CPU peuvent calculer sin & Cos simultanément (par exemple fsincos sur x86). Si vous faites cela, vous pouvez le faire un peu plus vite avec trois appels plutôt que 6 pour calculer les valeurs initiales sin & cos.

mise à jour: il y a en fait 12 façons selon que vous voulez droitier ou gaucher résultats -- vous pouvez changer le "impartialité" en niant les angles.

18
répondu Adisak 2012-09-05 15:44:26

Bêta 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 pitch est up\down (hochement de la tête en accord) où a positif pitch donne un négative y-composant. Mon vecteur de référence est le style OpenGl (sur l'axe-z) donc avec yaw=0, pitch=0 le vecteur unitaire résultant devrait être égal (0, 0, -1). Si quelqu'un vient à travers ce post et a des difficultés à traduire les formules de Beta à ce système particulier, le les équations que j'utilise sont:

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

Remarque: le signe du changement et le mouvement de lacet <-> pas de swap. Espérons que cela permettra de sauver quelqu'un certain temps.

7
répondu pauluss86 2012-09-04 17:08:07

Vous devez être clair sur vos définitions ici - en particulier, quel est le vecteur que vous voulez? Si c'est la direction qu'un avion pointe, le roulis ne l'affecte même pas, et vous utilisez juste coordonnées sphériques

si d'un autre côté vous voulez prendre un vecteur donné et le transformer par ces angles, vous êtes à la recherche d'une matrice de rotation. article wiki

1
répondu Cascabel 2009-10-14 20:07:52

si quelqu'un trébuche sur la recherche d'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
répondu nvd 2017-06-20 12:51:01