欧拉角与旋转矩阵之间的相互转化(推导和Python代码)
表示三维空间中的旋转可以有多种表示的方法(旋转矩阵,欧拉角,四元素,轴角,李群李代数)。欧拉角表示法,分别是指定了三个角度yaw,roll,pitch,分别是绕z轴,x轴,y轴的转动的角度。
1. 欧拉角 -> 旋转矩阵
欧拉角来合成旋转矩阵的过程需要指定顺规,我们常用的顺规是 Z Y X ZYX ZYX,即分别将旋转矩阵 R z R_z Rz, R y R_y Ry和 R x R_x Rx相乘。
参考机器人学的知识,根据下图所示,

绕
z
,
y
,
x
z,y,x
z,y,x轴旋转角度分别为
α
,
β
,
γ
\alpha,\beta,\gamma
α,β,γ,我们可以获得绕
z
,
y
,
x
z,y,x
z,y,x轴的旋转矩阵分别为:
R
z
(
α
)
=
[
1
0
0
0
cos
α
−
sin
α
0
sin
α
cos
α
]
R
y
(
β
)
=
[
cos
β
0
sin
β
0
1
0
−
sin
β
0
cos
β
]
R
x
(
γ
)
=
[
cos
γ
−
sin
γ
0
sin
γ
cos
γ
0
0
0
1
]
R_z(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha \\ 0 & \sin\alpha & \cos\alpha \end{bmatrix} \\ R_y(\beta) = \begin{bmatrix} \cos\beta & 0 & \sin\beta \\ 0 & 1 & 0 \\ -\sin\beta & 0 & \cos\beta \end{bmatrix} \\ R_x(\gamma) = \begin{bmatrix} \cos\gamma & -\sin\gamma & 0 \\ \sin\gamma & \cos\gamma & 0 \\ 0 & 0 & 1 \end{bmatrix}
Rz(α)=
1000cosαsinα0−sinαcosα
Ry(β)=
cosβ0−sinβ010sinβ0cosβ
Rx(γ)=
cosγsinγ0−sinγcosγ0001
然后按照
Z
Y
X
ZYX
ZYX顺规合成旋转矩阵
R
a
b
(
α
,
β
,
γ
)
=
R
z
(
α
)
R
y
(
β
)
R
x
(
γ
)
=
[
c
α
c
β
−
s
α
c
γ
+
c
α
s
β
s
γ
s
α
s
γ
+
c
α
s
β
c
γ
s
α
c
β
c
α
c
γ
+
s
α
s
β
s
γ
−
c
α
s
γ
+
s
α
s
β
c
γ
−
s
β
c
β
s
γ
c
β
c
γ
]
=
[
r
11
r
12
r
13
r
21
r
22
r
23
r
31
r
32
r
33
]
\begin{align*} R_{ab}(\alpha, \beta, \gamma) & = R_z(\alpha)R_y(\beta)R_x(\gamma) \\ & = \begin{bmatrix} c_\alpha c_\beta & -s_\alpha c_\gamma + c_\alpha s_\beta s_\gamma & s_\alpha s_\gamma + c_\alpha s_\beta c_\gamma \\ s_\alpha c_\beta & c_\alpha c_\gamma + s_\alpha s_\beta s_\gamma & -c_\alpha s_\gamma + s_\alpha s_\beta c_\gamma \\ -s_\beta & c_\beta s_\gamma & c_\beta c_\gamma \end{bmatrix} \\ & = \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{bmatrix} \end{align*}
Rab(α,β,γ)=Rz(α)Ry(β)Rx(γ)=
cαcβsαcβ−sβ−sαcγ+cαsβsγcαcγ+sαsβsγcβsγsαsγ+cαsβcγ−cαsγ+sαsβcγcβcγ
=
r11r21r31r12r22r32r13r23r33
其中,
c
α
=
cos
α
,
s
β
=
sin
β
c_\alpha=\cos\alpha, s_\beta=\sin\beta
cα=cosα,sβ=sinβ,别的符号以此类推。
如果已知欧拉角求旋转矩阵,这个非常好求,我们直接求出 R z ( α ) , R y ( β ) , R x ( γ ) R_z(\alpha),R_y(\beta), R_x(\gamma) Rz(α),Ry(β),Rx(γ)然后矩阵相乘即可。
Python
import math
import numpy as np
def rpy2R(rpy): # [r,p,y] 单位rad
rot_x = np.array([[1, 0, 0],
[0, math.cos(rpy[0]), -math.sin(rpy[0])],
[0, math.sin(rpy[0]), math.cos(rpy[0])]])
rot_y = np.array([[math.cos(rpy[1]), 0, math.sin(rpy[1])],
[0, 1, 0],
[-math.sin(rpy[1]), 0, math.cos(rpy[1])]])
rot_z = np.array([[math.cos(rpy[2]), -math.sin(rpy[2]), 0],
[math.sin(rpy[2]), math.cos(rpy[2]), 0],
[0, 0, 1]])
R = np.dot(rot_z, np.dot(rot_y, rot_x))
return R
alpha = 0.25 * np.pi
beta = 0.4 * np.pi
gamma = 0.3 * np.pi
rpy = [alpha, beta, gamma]
print('rpy:', str(rpy))
print('R:', str(rpy2R(rpy)))
结果如下:
rpy: [0.7853981633974483, 1.2566370614359172, 0.9424777960769379]
R: [[ 0.18163563 -0.1767767 0.96734611]
[ 0.25 0.95968966 0.12843579]
[-0.95105652 0.21850801 0.21850801]]
2. 旋转矩阵 -> 欧拉角
如果已知旋转矩阵求欧拉角,就是求解如下方程的过程
[
c
α
c
β
−
s
α
c
γ
+
c
α
s
β
s
γ
s
α
s
γ
+
c
α
s
β
c
γ
s
α
c
β
c
α
c
γ
+
s
α
s
β
s
γ
−
c
α
s
γ
+
s
α
s
β
c
γ
−
s
β
c
β
s
γ
c
β
c
γ
]
=
[
r
11
r
12
r
13
r
21
r
22
r
23
r
31
r
32
r
33
]
\begin{bmatrix} c_\alpha c_\beta & -s_\alpha c_\gamma + c_\alpha s_\beta s_\gamma & s_\alpha s_\gamma + c_\alpha s_\beta c_\gamma \\ s_\alpha c_\beta & c_\alpha c_\gamma + s_\alpha s_\beta s_\gamma & -c_\alpha s_\gamma + s_\alpha s_\beta c_\gamma \\ -s_\beta & c_\beta s_\gamma & c_\beta c_\gamma \end{bmatrix}= \begin{bmatrix} r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{bmatrix}
cαcβsαcβ−sβ−sαcγ+cαsβsγcαcγ+sαsβsγcβsγsαsγ+cαsβcγ−cαsγ+sαsβcγcβcγ
=
r11r21r31r12r22r32r13r23r33
整理一下可以得到
{ − sin β = r 31 cos 2 β sin 2 γ + cos 2 β cos 2 γ = r 32 2 + r 33 2 \left\{\begin{align*} & -\sin\beta = r_{31} \\ & \cos^2\beta\sin^2\gamma + \cos^2\beta\cos^2\gamma = r_{32}^2 + r_{33}^2 \\ \end{align*}\right. {−sinβ=r31cos2βsin2γ+cos2βcos2γ=r322+r332
所以可以得到
{ α = arctan ( r 21 / c β , r 11 / c β ) β = arctan ( − r 31 , r 32 2 + r 33 2 ) γ = arctan ( r 32 / c β , r 33 / c β ) \left\{\begin{align*} & \alpha = \arctan(r_{21}/c_\beta, r_{11}/c_\beta) \\ & \beta = \arctan(-r_{31}, \sqrt{r_{32}^2 + r_{33}^2}) \\ & \gamma = \arctan(r_{32}/c_\beta, r_{33}/c_\beta) \end{align*}\right. ⎩ ⎨ ⎧α=arctan(r21/cβ,r11/cβ)β=arctan(−r31,r322+r332)γ=arctan(r32/cβ,r33/cβ)
当 β = π 2 \beta=\frac{\pi}{2} β=2π的时候, cos β = 0 \cos\beta=0 cosβ=0,这时为奇异点(singular)不能解出欧拉角,这也是欧拉角表示法的一个弊端。
Python
import math
import numpy as np
# Checks if a matrix is a valid rotation matrix.
def isRotationMatrix(R) :
Rt = np.transpose(R)
shouldBeIdentity = np.dot(Rt, R)
I = np.identity(3, dtype = R.dtype)
n = np.linalg.norm(I - shouldBeIdentity)
return n < 1e-6
# Calculates rotation matrix to euler angles
# The result is the same as MATLAB except the order
# of the euler angles ( x and z are swapped ).
def rotationMatrixToEulerAngles(R) :
assert(isRotationMatrix(R))
sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
singular = sy < 1e-6
if not singular :
x = math.atan2(R[2,1] , R[2,2])
y = math.atan2(-R[2,0], sy)
z = math.atan2(R[1,0], R[0,0])
else :
x = math.atan2(-R[1,2], R[1,1])
y = math.atan2(-R[2,0], sy)
z = 0
return np.array([x, y, z])
R = np.array([[ 0.18163563, -0.1767767, 0.96734611],
[ 0.25, 0.95968966, 0.12843579],
[-0.95105652, 0.21850801, 0.21850801]])
print('R:', str(R))
print('rpy:', str(rotationMatrixToEulerAngles(R)))
结果如下
R: [[ 0.18163563 -0.1767767 0.96734611]
[ 0.25 0.95968966 0.12843579]
[-0.95105652 0.21850801 0.21850801]]
rpy: [0.78539816 1.25663706 0.9424778 ]
可以看到结果和我们之前转换的结果保持一致。