我可能有点晚了,zabop的回答已经指向了正确的方向。我只想澄清两件事。
当我们使用变换时,存在几个不确定性,这可能会使事情更加混乱。可能会让这里的代码有点混乱的两件事是:
active vs. passive rotation
(主动旋转与被动旋转)
intrinsic vs. extrinsic rotation
(本质旋转与外在旋转)
我从您上面的示例开始:
import numpy as np
r_0 = np.array([[-0.02659679, -0.00281247, 0.99964229],
[ 0.76308514, -0.64603356, 0.01848528],
[ 0.64575048, 0.76330382, 0.01932857]])
r_1 = np.array([[ 0.05114056, -0.03815443, 0.99796237],
[-0.30594799, 0.95062582, 0.05202294],
[-0.95067369, -0.30798506, 0.03694226]])
我会计算一个旋转矩阵,将
r_0
旋转到
r_1
,具体步骤如下(与你的代码不同!):
r0_to_r1 = r_1.dot(r_0.T)
r0_to_r1
结果:
array([[ 0.99635252, 0.08212126, 0.0231898 ],
[ 0.05746796, -0.84663889, 0.52905579],
[ 0.06308011, -0.52579339, -0.84827012]])
我使用外部约定来拼接旋转矩阵,即先应用
r_0.T
再应用
r_1
。(如果
r_0
和
r_1
是实数,我们会写
r_1 - r_0
来得到一个将
r_0
转换为
r_1
的数字。)
您可以验证
r0_to_r1
从
r_0
旋转到
r_1
:
from numpy.testing import assert_array_almost_equal
assert_array_almost_equal(r_1, r0_to_r1.dot(r_0))
无论如何,固有的约定也可以起到作用:
r0_to_r1_intrinsic = r_0.T.dot(r_1)
assert_array_almost_equal(r_1, r_0.dot(r0_to_r1_intrinsic))
自从 zabop 推出 pytransform3d 之后,我也想澄清一点,即 scipy 使用的是
主动旋转矩阵,而
pytransform3d.rotations.euler_xyz_from_matrix
生成的旋转矩阵是一个
被动旋转矩阵!以前的版本没有这么清楚地记录下来。您可以通过矩阵转置将活动旋转矩阵转换为被动旋转矩阵,反之亦然。Pytransform3d 和 scipy 的
Rotation.to_euler("xyz", ...)
函数都使用
本质连结约定。
from scipy.spatial.transform import Rotation as R
r = R.from_matrix(r0_to_r1)
euler_xyz_intrinsic_active_degrees = r.as_euler('xyz', degrees=True)
euler_xyz_intrinsic_active_degrees
结果:array([-148.20762964, -3.6166255 , 3.30106818])
使用pytransform3d可以得到相同的结果(注意我们通过.T
获得被动旋转矩阵):
import pytransform3d.rotations as pr
euler_xyz_intrinsic_active_radians = pr.euler_xyz_from_matrix(r0_to_r1.T)
np.rad2deg(euler_xyz_intrinsic_active_radians)
结果:数组([-148.20762951,-3.61662542,3.30106799])
您还可以使用pytransform3d从欧拉角获得旋转矩阵(请注意,我们通过.T
获得主动旋转矩阵):
r0_to_r1_from_euler = pr.matrix_from_euler_xyz(euler_xyz_intrinsic_active_radians).T
r0_to_r1_from_euler
结果:
array([[ 0.99635251, 0.08212125, 0.0231898 ],
[ 0.05746796, -0.84663889, 0.52905579],
[ 0.06308011, -0.52579339, -0.84827013]])
r_0
和r_1
是否分别等同于rot_mat_0
和rot_mat_1
? - zabopnp.degrees(r.as_euler('xyz', degrees=True)
看起来不太对。如果你能让as_euler()
返回角度值,那么你就不需要再将结果转换为角度了! - jasonharper