How to convert euler angles to rotation matrix and back to euler angles consistently?
62 views (last 30 days)
Show older comments
I want to compare the rotations from two different sources. However, I can do it only in R3, using Euler angles. However, it seems even for an elementary conversion, we don't get matching euler vectors. I know that there can be non-unique representations for the same rotation matrix, but is there a way, where I can enforce some particular angle range output so that the vectors match? Maybe a constraint like rotation in Z has to be positive.
For eg.
%% Euler Angle -> Rotation Matrix -> Euler Angle
Rzc = -0.0030; Ryc = -2.4788; Rxc = 0.0180;
eul_seq_c_in = [Rzc, Ryc, Rxc]
rotm_c = eul2rotm(eul_seq_c_in);
eul_seq_c_out = rotm2eul(rotm_c)
%% Many to One Mapping for Euler Angle
eul2rotm(eul_seq_c_in)
eul2rotm(eul_seq_c_out)
For my application, all I get is a sequence of euler angles as an input. Then, I get a rotation transform independently, whose Euler sequence is calculated. And then I verify, if they represent the same rotation transform.
0 Comments
Accepted Answer
Ganesh
on 7 Aug 2024
I have written the code for converting Euler Angles to Rotation matrix and back below:
Rzc = -0.0030; Ryc = -2.4788; Rxc = 0.0180;
eul_seq_c_in = [Rzc, Ryc, Rxc];
rotm_c = eulerToRotationMatrix(eul_seq_c_in);
eul_seq_c_out = rotationMatrixToEuler(rotm_c)
function R = eulerToRotationMatrix(seq_in)
alpha = seq_in(1);
beta = seq_in(2);
gamma = seq_in(3);
Rz = [cos(alpha) -sin(alpha) 0;
sin(alpha) cos(alpha) 0;
0 0 1];
Ry = [cos(beta) 0 sin(beta);
0 1 0;
-sin(beta) 0 cos(beta)];
Rx = [1 0 0;
0 cos(gamma) -sin(gamma);
0 sin(gamma) cos(gamma)];
R = Rz * Ry * Rx;
end
function seq = rotationMatrixToEuler(R)
beta = -asin(R(3,1));
if abs(cos(beta)) > 1e-6
alpha = atan2(R(3,2), R(3,3));
gamma = atan2(R(2,1), R(1,1));
else
alpha = atan2(-R(2,3), R(2,2));
gamma = 0;
end
seq = [alpha, beta, gamma];
end
To elaborate, you can see that the operation to convert "Rotation Matrix" to "Euler Angles" completely depends on the original "Rotation Matrix", and hence you would need to brute force this check. Moreover, in the original conversion of Euler Angles to Rotation Matrix, you can see that the "cos" or "sin" of the values are being stored, hence your period or phase information is being lost.
If you are very strict that you want a one to one mapping, you might have to trace back to writing code for the exact mathematical constraints to convert "Euler Angles" to the desired "Rotation Matrix".
Theese functions try to achieve the required result in the simplest way possible and hence goes about it this way.
The workaround for your solution might be to conver all your original "Euler Angles" to "Rotation Matrix" and convert it back and then store the same. The Euler Angles after conversion show the "one to one mapping" you require.
Hope this answer helps!
2 Comments
Ganesh
on 7 Aug 2024
Yup, thats what you are doing currently, but what I intend to imply more is that once converted, you can be assured of the one to one mapping henceforth.
Rzc = -0.0030; Ryc = -2.4788; Rxc = 0.0180;
eul_seq_c_in = [Rzc, Ryc, Rxc];
rotm_c = eul2rotm(eul_seq_c_in);
eul_seq_c_out = rotm2eul(rotm_c);
rotm_c_1 = eul2rotm(eul_seq_c_out);
eul_seq_c_out_1 = rotm2eul(rotm_c);
disp(isequal(eul_seq_c_out,eul_seq_c_out_1))
My suggestion was to store the Euler Angles at the source this way, if you aren't already and there is provision to
More Answers (1)
Paul
on 7 Aug 2024
Edited: Paul
on 8 Aug 2024
"While I am aware of the intermediate steps, I kind of expected the inbuilt matlab functions to be consistent during the to-and-fro conversion."
I don't see how that's possible. There are an infinite number of Euler angle triplets (for a given sequence) that will yield the same rotation matrix with eul2rotm. How would rotm2eul know which one of those triplets is the "right" one. Even setting aside multiple-of-two-pi cases, there's still ambiguity unless another constraint is applied, typically that the absolute value of the middle rotation is less than or equal to pi/2, which is the affect we're seeing in the question (Ryc > pi/2). It appears that rotm2eul applies this convention (for its first output, and see below), though that's not stated in the documentation. Tthere's also ambiguity, in principal, for angles that could be either +pi or -pi.
It's probably best to construct the rotation matrix from the input sequence of Euler angles and compare to the independent rotation matrix.
BUT, I just discovered that rotm2eul provides a second output that matches what you want for this particular example
Rzc = -0.0030; Ryc = -2.4788; Rxc = 0.0180;
eul_seq_c_in = [Rzc, Ryc, Rxc]
rotm_c = eul2rotm(eul_seq_c_in);
[eul_seq_c_out,eulalt] = rotm2eul(rotm_c)
Unfortunately, the documentation of rotm2eul is silent on what exactly is the difference between its first and second outputs (or why that second output is even offered), so I can't say for sure that one of the outputs will always match your Euler angles in eul_seq_c_in, though I suspect that's the case, as long as none of abs(angle_seq_c_in) is greater than pi.
Apparently this second output was introduced in 2020a, but it's not showing in the documentation for 2021b.
2 Comments
Paul
on 8 Aug 2024
I'm pretty sure that the first output of rotm2eul uses the convention that the middle angle is constrained to have absolute value less than or equal to pi/2. And the first and third angles in the first output of rotm2eul will never have absolute value greater than pi. So those would be the constraints to enforce on the angles in eul_seq_c_in if you want to continue down the path of comparing the input Euler angles to that output of rotm2eul.
The second output of rotm2eul is documented, as shown at the link in the original answer and in this comment.
See Also
Categories
Find more on Assembly in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!