简体   繁体   中英

Euler Angles and Rotation Matrix from two 3D points

I am trying to find the Euler angles that allow the transformation from point A to point B in 3D space.

Consider the normalized vectors A = [1, 0, 0] and B = [0.32 0.88 -0.34] .

I understand that by computing the cross product A × B I get the rotation axis. The angle between A and B is given by tan⁻¹(||cross||, A·B) , where A·B is the dot product between A and B .

This gives me the rotation vector rotvec = [0 0.36 0.93 1.24359531111] , which is rotvec = [A × B; angle] rotvec = [A × B; angle] (the cross product is normalized).

Now my question is: How do I move from here to get the Euler angles that correspond to the transformation from A to B ?

In MATLAB the function vrrotvec2mat receives as input a rotation vector and outputs a rotation matrix. Then the function rotm2eul should return the corresponding Euler angles. I get the following result (in radians): [0.2456 0.3490 1.2216] , according to the XYZ convention. Yet, this is not the expected result.

The correct answer is [0 0.3490 1.2216] that corresponds to a rotation of 20° and 70° in Y and Z , respectively.

When I use eul2rot([0 0.3490 1.2216]) (with eul2rot taken from here ) to verify the resulting rotation matrix, this one is different from the one I obtain when using vrrotvec2mat(rotvec) .

I also have a Python spinet that yields the exactly same results as described above.

--- Python (2.7) using transform3d ---

import numpy as np
import transforms3d

cross = np.cross(A, B)
dot = np.dot(A, B.transpose())
angle = math.atan2(np.linalg.norm(cross), dot)
rotation_axes = sklearn.preprocessing.normalize(cross)
rotation_m = transforms3d.axangles.axangle2mat(rotation_axes[0], angle, True)
rotation_angles = transforms3d.euler.mat2euler(rotation_m, 'sxyz')

What I am missing here? What should I be doing instead?

Thank you

A rotation matrix has 3 degrees of freedom but the constraints of your problem only constrain 2 of those degrees.

This can be made more concrete by considering the case where we have a rotation matrix R which rotates from A to B so R*A == B . If we then construct another rotation matrix RB which rotates about vector B then applying this rotation to R*A won't have any effect, ie B == R*A == RB*R*A . It will, however, produce a different rotation matrix RB*R with different Euler angles.

Here's an example in MATLAB:

A = [1; 0; 0];
B = [0.32; 0.88; -0.34];

A = A / norm(A);
B = B / norm(B);

ax = cross(A, B);
ang = atan2(norm(ax), dot(A, B)); % ang = acos(dot(A, B)) works too
R = axang2rotm([ax; ang].');

ang_arbitrary = rand()*2*pi;
RB = axang2rotm([B; ang_arbitrary].');

R*A - B
RB*R*A - B

rotm2eul(R)
rotm2eul(RB*R)

Result

ans =
   1.0e-15 *

   -0.0555
    0.1110
         0

ans =
   1.0e-15 *

    0.2220
    0.7772
   -0.2776

ans =    
    1.2220    0.3483    0.2452

ans =    
    1.2220    0.3483    0.7549

I will give you a solution based on Euler's rotation theorem .

This solution gives you only the one angle, but the other angles can be derived.

import numpy as np


a_vec = np.array([1, 0, 0])/np.linalg.norm(np.array([1, 0, 0]))
b_vec = np.array([0.32, 0.88, -0.34])/np.linalg.norm(np.array([0.32, 0.88, -0.34]))

cross = np.cross(a_vec, b_vec)
ab_angle = np.arccos(np.dot(a_vec,b_vec))


vx = np.array([[0,-cross[2],cross[1]],[cross[2],0,-cross[0]],[-cross[1],cross[0],0]])
R = np.identity(3)*np.cos(ab_angle) + (1-np.cos(ab_angle))*np.outer(cross,cross) + np.sin(ab_angle)*vx


validation=np.matmul(R,a_vec)

This uses the common axis of rotation (eigenvector in this case), as the cross product.

The matrix R is then the rotation matrix .

This is a general way of doing it, and very simple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM