How to convert Euler angles to directional vector?
Asked Answered
E

5

71

I have pitch, roll, and yaw angles. How would I convert these to a directional vector?

It'd be especially cool if you can show me a quaternion and/or matrix representation of this!

Excepting answered 14/10, 2009 at 19:50 Comment(0)
S
113

Unfortunately there are different conventions on how to define these things (and roll, pitch, yaw are not quite the same as Euler angles), so you'll have to be careful.

If we define pitch=0 as horizontal (z=0) and yaw as counter-clockwise from the x axis, then the direction vector will be

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

Note that I haven't used roll; this is direction unit vector, it doesn't specify attitude. It's easy enough to write a rotation matrix that will carry things into the frame of the flying object (if you want to know, say, where the left wing-tip is pointing), but it's really a good idea to specify the conventions first. Can you tell us more about the problem?

EDIT: (I've been meaning to get back to this question for two and a half years.)

For the full rotation matrix, if we use the convention above and we want the vector to yaw first, then pitch, then roll, in order to get the final coordinates in the world coordinate frame we must apply the rotation matrices in the reverse order.

First roll:

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

then pitch:

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

then yaw:

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

Combine them, and the total rotation matrix is:

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

So for a unit vector that starts at the x axis, the final coordinates will be:

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

And for the unit vector that starts at the y axis (the left wing-tip), the final coordinates will be:

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)
Shalandashale answered 14/10, 2009 at 20:11 Comment(13)
FWIW, there are six different formula for normalized (from -PI to PI) Euler solutions depending on rotation order (and infinity more variants considering angles wrap around at 2*PI). Depending on your use case, you might have to use one of the alternate formula to get the desired result.Culottes
What would the equations be if we did need roll?Expressway
@Expressway the equations would be exactly the same, since roll causes the vector to rotate around itself, which has no effect on it.Requiescat
@Beta, where can i find the math Derivation of this formula ? wiki is too broad , I need a help in derivation .Autograph
@wangdq: the derivation is not too difficult, but I suggest you start with 2D rotations. Are you comfortable with vectors and matrices?Shalandashale
@Beta, is it possible to convert back to Pitch Yaw Roll? XYZ -> Pitch Yaw Roll?Sambar
@Cookies: Generally yes, with some exceptions. Do you have an initial vector in mind, like the nose, or the left wing-tip?Shalandashale
Thank you very much for your concise answer. I am using your x/y formula for a Lap Swim app (iOS) - you get free upgrade if you want.Momently
You messed up with a sign of sin(pitch). Should be | cos(pitch) 0 sin(pitch) | | 0 1 0 | | -sin(pitch) 0 cos(pitch) | planning.cs.uiuc.edu/node102.html en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensionsGujarati
@nlminhtl: You are mistaken. In your convention, positive pitch moves the nose downward, in mine it moves the nose upward (which is the convention in aviation). Perhaps you didn't notice the first sentence of my answer, or my first set of equations.Shalandashale
@Invariant: That is what I've been using as an example of initial orientation, yes.Shalandashale
does x,y,z stand for omega, phi, kappa, or degrees of rotation around x,y,z axes? Sorry if that's a confusing comparison.Jipijapa
@bozdoz: x,y,z are Cartesian coordinates.Shalandashale
C
30

There are six different ways to convert three Euler Angles into a Matrix depending on the Order that they are applied:

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, some CPU's can compute Sin & Cos simultaneously (for example fsincos on x86). If you do this, you can make it a bit faster with three calls rather than 6 to compute the initial sin & cos values.

Update: There are actually 12 ways depending if you want right-handed or left-handed results -- you can change the "handedness" by negating the angles.

Culottes answered 15/10, 2009 at 1:45 Comment(0)
M
10

Beta saved my day. However I'm using a slightly different reference coordinate system and my definition of pitch is up\down (nodding your head in agreement) where a positive pitch results in a negative y-component. My reference vector is OpenGl style (down the -z axis) so with yaw=0, pitch=0 the resulting unit vector should equal (0, 0, -1). If anyone comes across this post and has difficulties translating Beta's formulas to this particular system, the equations I use are:

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

Note the sign change and the yaw <-> pitch swap. Hope this will save someone some time.

Mcguire answered 4/9, 2012 at 17:8 Comment(0)
L
2

You need to be clear about your definitions here - in particular, what is the vector you want? If it's the direction an aircraft is pointing, the roll doesn't even affect it, and you're just using spherical coordinates (probably with axes/angles permuted).

If on the other hand you want to take a given vector and transform it by these angles, you're looking for a rotation matrix. The wiki article on rotation matrices contains a formula for a yaw-pitch-roll rotation, based on the xyz rotation matrices. I'm not going to attempt to enter it here, given the greek letters and matrices involved.

Lazybones answered 14/10, 2009 at 20:7 Comment(0)
F
1

If someone stumbles upon looking for implementation in 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)
Fredenburg answered 20/6, 2017 at 12:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.