How to convert euler angles to rotation matrix and back to euler angles consistently?

62 views (last 30 days)
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]
eul_seq_c_in = 1x3
-0.0030 -2.4788 0.0180
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
rotm_c = eul2rotm(eul_seq_c_in);
eul_seq_c_out = rotm2eul(rotm_c)
eul_seq_c_out = 1x3
3.1386 -0.6628 -3.1236
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
%% Many to One Mapping for Euler Angle
eul2rotm(eul_seq_c_in)
ans = 3x3
-0.7883 -0.0081 -0.6153 0.0024 0.9999 -0.0162 0.6153 -0.0142 -0.7881
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
eul2rotm(eul_seq_c_out)
ans = 3x3
-0.7883 -0.0081 -0.6153 0.0024 0.9999 -0.0162 0.6153 -0.0142 -0.7881
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
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.

Accepted Answer

Ganesh
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)
eul_seq_c_out = 1x3
-3.1236 -0.6628 3.1386
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
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
Manish Kumar Nayak
Manish Kumar Nayak on 7 Aug 2024
Thanks for the prompt response. As you can see, even in your manual function, there is a difference between the input and the output, which as you correctly pointed, is owed to the phase difference of sin and cos.
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 do plan to write some code for the comparison for taking the phase into account.
Although as for this part below, I didn't quite get it properly
"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."
Isn't this exactly what I am doing right now? As mentioned in the question? Unless I am understanding it wrong.
Ganesh
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))
1
My suggestion was to store the Euler Angles at the source this way, if you aren't already and there is provision to

Sign in to comment.

More Answers (1)

Paul
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]
eul_seq_c_in = 1x3
-0.0030 -2.4788 0.0180
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
rotm_c = eul2rotm(eul_seq_c_in);
[eul_seq_c_out,eulalt] = rotm2eul(rotm_c)
eul_seq_c_out = 1x3
3.1386 -0.6628 -3.1236
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
eulalt = 1x3
-0.0030 -2.4788 0.0180
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
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
Manish Kumar Nayak
Manish Kumar Nayak on 8 Aug 2024
"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."
True. Hence, I asked if there's some way to enforce constraints inherently. Apparently there isn't, but it's fine.
However, the second implementation which you found is amazing. This could be useful. But if it's not there in documentation, maybe they plan to remove it soon.
Paul
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.

Sign in to comment.

Products


Release

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!