• ORBITER-FORUM will be temporarily closed at 2026-07-23 18:00 UTC while we complete some OF maintenance tasks. The amount of downtime is expected to take up to one hour, but probably less.

Calculating Yaw and Roll in a arbitrary frame

I'm just frustrated at this point.

I would expect this to be a reasonably simple, or at the very least, a "pre-solved" problem. But no. I don't even give a :censored: about right vs. left handed coordinates, if I have one I know how to get the other.

On the bright-side I have read some interesting articles on inverse kinematics while looking for an answer.

Inverse kinematics and this problem are actually mathematically the same problem. :lol: Inverse kinematics just add some more preparation to formalize the problem into a nice matrix. But solving the matrix for the angles is just the same approach.
 
Matrix A = reference axes.
Matrix B = direction of the vessel's X Y and Z axes
Matrix C = Rotation Matrix.

Get acos (dotp (Ax, Bx))

if angle = 0 skip to next axis

otherwise C = Identity matrix rotated by angle around the cross product of Ax and Bx.

Repeat for Y axis.

Does anyone have a quicker, or computationally simpler way?
Here's how it's done in SSU:
A = target attitude (rotation matrix in global frame)
B = current attitude (rotation matrix in global frame)
C = [math] B^TA [/math]
PYR angles = ConvertRotationMatrixToPYR(C)
The PYR angles here represent the rotation angles from the current attitude to the target attitude. The exact method for converting the rotation matrix C to PYR angles depends on the angle convention you're using (see https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix).
 
Last edited:
What is the value of the exponent in C?
 
Last edited:
Ok, I've always seen transpose represented with the t in front of the matrix label or actually spelled out ie "A^transpose".

---------- Post added at 16:04 ---------- Previous post was at 13:44 ----------


So once I have the matrix of transpose B * A how do I get P, Y, and R from it?

---------- Post added 07-18-14 at 03:34 ---------- Previous post was 07-17-14 at 16:48 ----------

through iutside reasearch and some experimentation I have found that the following sequence will give me the correct PYR angles for the ecliptic plane. In otherwords input matrix = GetRotationMatrix ().

P = atan2 (vz.y, vz.z);
Y = -asin (vz.x);
R = atan2 (vy.x, vx.x);

But not when I use the process described by SiameseCat.

Now I suck at this so I figure my process is broken somewhere, and could use a seconds set of eyes on it.


Code:
	MATRIX3 m1 = GetReferenceFrame ();

	MATRIX3 m2 = identity ();
	vessel->GetRotationMatrix (m2);
	
	MATRIX3 mRot = mul (transpose (m2), m1);

	VECTOR3 vx, vy, vz;
	vx = GetColumnVector (mRot, 0);
	vy = GetColumnVector (mRot, 1);
	vz = GetColumnVector (mRot, 2);

GetColumnVector returns the specified column from the specified matrix as a vector3.

This is my reference frame code, I've confirmed its validity independently using setrotationmatrix() so I don't think the problem lies here but I'm posting it for completeness.

Code:
		North = vesselstate.rvel;									// North / Forward = velocity vector
		Vertical = crossp (vesselstate.rvel, vesselstate.rpos);		// Vertical axis = Orbit's 'normal' vector
		Horizon = RotateVector (North, Vertical, PI/2);				// Rotate "North" 90 degrees to find Horizon / East vector  
		
		// Normalise vectors
		normalise (North);
		normalise (Vertical);
		normalise (Horizon);

		// Compose matrix
		ref = ComposeMatrixByColumn ( Horizon, Vertical, North);

Note: ComposeMatrixByColumn returns a Matrix3 made up of the three vectors. Each vector forming a column of the matrix.

Rotatevector rotates the first vector passed to it around the second by the specified number of radians

---------- Post added at 03:43 ---------- Previous post was at 03:34 ----------

I'f i could get some help here it would be appreciated, this particular issue is a signifigant bottleneck and I'm working with a (self-imposed) deadline
 
Last edited:
Here is my code I use to get a vessels PYR angles in the orbital coordinate system, which is the reference frame you are also using?! Nott 100% sure. I define the axis of the coordinate system, build a matrix and then combined with the rotation matrix of the vessel the complete rotation matrix, from which I derive the PYR angles. I hope it helps!

Code:
gravref = vessel->GetGravityRef();
vessel->GetRelativePos(gravref, R_0);	//Position vector
vessel->GetRelativeVel(gravref, V_0);	//Velocity vector
vessel->GetRotationMatrix(Rot);			//Vessel rotation matrix
axis3 = unit(V_0);						//Z-Axis: Velocoty unit vector
axis1 = unit(crossp(R_0, axis3));		//X-Axis: Vector in the direction of the specific relative angular momentum
axis2 = crossp(axis3, axis1);			//Y-Axis: 90° up from velocity vector
R_loc = _M(axis1.x, axis2.x, axis3.x,  axis1.y, axis2.y, axis3.y,  axis1.z, axis2.z, axis3.z);	//Rotation matrix for the new orbital coordinate system
//R_loc = _M(axis1.x, axis1.y, axis1.z, axis2.x, axis2.y, axis2.z, axis3.x, axis3.y, axis3.z);	//Transposed rotation matrix
	
Rot_ges = mul(transpose_matrix(R_loc), Rot);	//Combined rotation matrix
p = atan2(Rot_ges.m23, Rot_ges.m33);			//Pitch
y = asin(Rot_ges.m13);							//Yaw
r = atan2(Rot_ges.m12, Rot_ges.m11);			//Roll
 
Ok, I've always seen transpose represented with the t in front of the matrix label or actually spelled out ie "A^transpose".

---------- Post added at 16:04 ---------- Previous post was at 13:44 ----------


So once I have the matrix of transpose B * A how do I get P, Y, and R from it?

---------- Post added 07-18-14 at 03:34 ---------- Previous post was 07-17-14 at 16:48 ----------

through iutside reasearch and some experimentation I have found that the following sequence will give me the correct PYR angles for the ecliptic plane. In otherwords input matrix = GetRotationMatrix ().

P = atan2 (vz.y, vz.z);
Y = -asin (vz.x);
R = atan2 (vy.x, vx.x);

But not when I use the process described by SiameseCat.

Now I suck at this so I figure my process is broken somewhere, and could use a seconds set of eyes on it.


Code:
    MATRIX3 m1 = GetReferenceFrame ();

    MATRIX3 m2 = identity ();
    vessel->GetRotationMatrix (m2);
    
    MATRIX3 mRot = mul (transpose (m2), m1);

    VECTOR3 vx, vy, vz;
    vx = GetColumnVector (mRot, 0);
    vy = GetColumnVector (mRot, 1);
    vz = GetColumnVector (mRot, 2);
GetColumnVector returns the specified column from the specified matrix as a vector3.

This is my reference frame code, I've confirmed its validity independently using setrotationmatrix() so I don't think the problem lies here but I'm posting it for completeness.

Code:
        North = vesselstate.rvel;                                    // North / Forward = velocity vector
        Vertical = crossp (vesselstate.rvel, vesselstate.rpos);        // Vertical axis = Orbit's 'normal' vector
        Horizon = RotateVector (North, Vertical, PI/2);                // Rotate "North" 90 degrees to find Horizon / East vector  
        
        // Normalise vectors
        normalise (North);
        normalise (Vertical);
        normalise (Horizon);

        // Compose matrix
        ref = ComposeMatrixByColumn ( Horizon, Vertical, North);
Note: ComposeMatrixByColumn returns a Matrix3 made up of the three vectors. Each vector forming a column of the matrix.

Rotatevector rotates the first vector passed to it around the second by the specified number of radians

---------- Post added at 03:43 ---------- Previous post was at 03:34 ----------

I'f i could get some help here it would be appreciated, this particular issue is a signifigant bottleneck and I'm working with a (self-imposed) deadline

There's one minor error in the PYR code: it should be
Y = asin (vz.x); (no minus sign)

What are you trying to measure? Your code looks fine, but I suspect the reference frame might not be what you want. At the moment, your reference frame is the Orbitersim prograde attitude, and you're measuring the angles between that and the current vessel attitude.
 
What are you trying to measure? Your code looks fine, but I suspect the reference frame might not be what you want. At the moment, your reference frame is the Orbitersim prograde attitude, and you're measuring the angles between that and the current vessel attitude.

That is correct as I am trying to independently reproduce the "orbit" HUD mode.

---------- Post added at 11:57 ---------- Previous post was at 05:44 ----------

Interestingly, I started having issues where multiple axes of rotation would start to "corrupt" other values. IE, pitch would only be correct in cases where roll was near zero. This updated PYR function works with my reference frame but inverts my global orientation.

Code:
		R = -atan2 (mRot.m21, mRot.m11);	
		P = atan2 (mRot.m32, mRot.m33);
		Y = asin (mRot.m31);

For instance zeroing out my global orientation via scenario editor results in a PYR vector of (180, 0, -180).

I suspect that this issue is "right handed" vs "left handed" coordinatesystems but not sure how best to normalize everything to the same handedness.
 
Last edited:
You might want to use
Code:
p = atan2(mRot.m23, mRot.m33);
y = asin(mRot.m13);	
R = atan2(mRot.m12, mRot.m11);
instead (I think this is what you were using in one of the previous posts). This version is what is used by Orbitersim to convert the rotation matrix to Euler angles (the Get/SetGlobalOrientation functions). It defines pitch as rotation around the X axis, yaw as rotation around the Y axis, and roll as rotation around the Z axis, and applies the rotations in PYR order.

It would be helpful if you could post one of the attitudes when you're getting incorrect results (i.e. a screenshot of the orbit HUD and the Euler angles you're calculating).
 
Using

Code:
p = atan2(mRot.m23, mRot.m33);
y = asin(mRot.m13);	
r = atan2(mRot.m12, mRot.m11);

Gives correct values when passed the raw rotation matrix but fails when passed [math]B^TA[/math]

In the following screen shot my pitch SHOULD read 30, Yaw 0 and Roll 45 degrees however you can see in the debug string that this is not what I am getting.

picture.php
 
Last edited:
Or you sure you are using the same coordinate frame as Orbiter there?
 
Reasonably.

I mean the "north" (0 yaw) reference axis is obviously pro-grade and vertical reference is obviously perpendicular to the orbital plane but beyond that...

---------- Post added at 04:02 ---------- Previous post was at 03:53 ----------

If course I'm assuming that the "global" reference frame is an Identity matrix.

This could be an issue if vessel and global coordinates are of a different "handedness"
 
When you're in a prograde attitude, what is the calculated attitude? Also does it handle single-axis rotations (just pitch, yaw or roll) correctly?
 
It reads 0, 0, 0, and no it does not.

Unless the Z-axis is aligned pro-grade rotation about a single axis causes changes in all three values.
 
Last edited:
I figured out what's happening;
Code:
p = atan2(mRot.m23, mRot.m33);
y = asin(mRot.m13);	
r = atan2(mRot.m12, mRot.m11);
gives rotations in RYP order, not PYR. Sorry for messing things up.

You should be using
Code:
P = -atan2(mRot.m23, mRot.m33);
Y = -asin(mRot.m13);
R = -atan2(mRot.m12, mRot.m11);
You might need to change some of the signs because you're using left-handed matrices.
 
All right, I can confirm that the following returns matching values...

Code:
	vessel->GetRotationMatrix (mRot);
		P = atan2(mRot.m23, mRot.m33);
		Y = -asin(mRot.m13);
		R = atan2(mRot.m12, mRot.m11);

picture.php



The raw rotaion matrix parses correctly so any further troubleshooting needs to focus on this part, or the reference frame itself...

Code:
	// Initialize variables
	MATRIX3 m1 = GetReferenceFrame (frame);

	MATRIX3 m2 = identity ();
	vessel->GetRotationMatrix (m2);
	
	MATRIX3 mRot = mul (transpose (m2), m1);
 
The values you're getting from Orbitersim values are RYP angles (i.e. rotation occurs around the roll axis first, then yaw, then pitch). If that's the behaviour you want, then everything is fine. In http://www.orbiter-forum.com/showthread.php?p=475661&postcount=30 you seem to want PYR angles (i.e. pitch, then yaw, then roll). The calculated angles look like sensible RYP angles. For display purposes, PYR angles are probably more intuitive.
 
Well this is for display purposes so yes PYR would be preferable.
 
Back
Top