欧拉角速度推导与不建议使用欧拉角的原因

摘要 欧拉角速度指欧拉角对时间的微分与角速度的关系,用于刚体姿态运动学建模,本文从一种复杂但严谨(应该)的角度推导这一关系,并解释为什么不建议使用欧拉角来描述姿态。

欧拉角微分方程
w ⃗ = [ 1 0 − sin ⁡ θ 0 cos ⁡ ϕ sin ⁡ ϕ cos ⁡ θ 0 − sin ⁡ ϕ cos ⁡ ϕ cos ⁡ θ ] [ ϕ ˙ θ ˙ ψ ˙ ] = [ ϕ ˙ − sin ⁡ θ ψ ˙ cos ⁡ ϕ θ ˙ + sin ⁡ ϕ cos ⁡ θ ψ ˙ − sin ⁡ ϕ θ ˙ + cos ⁡ ϕ cos ⁡ θ ψ ˙ ] [ ϕ ˙ θ ˙ ψ ˙ ] = [ 1 sin ⁡ ϕ tan ⁡ θ cos ⁡ ϕ tan ⁡ θ 0 cos ⁡ ϕ − sin ⁡ ϕ 0 sin ⁡ ϕ cos ⁡ θ cos ⁡ ϕ cos ⁡ θ ] w ⃗ \vec w = \begin{bmatrix} 1&0&-\sin\theta\\ 0&\cos\phi&\sin\phi\cos\theta\\ 0&-\sin\phi&\cos\phi\cos\theta \end{bmatrix} \begin{bmatrix} \dot{\phi} \\ \dot{\theta} \\ \dot{\psi} \end{bmatrix} =\begin{bmatrix} \dot{\phi}-\sin\theta\dot{\psi} \\ \cos\phi\dot{\theta}+\sin\phi\cos\theta\dot{\psi} \\ -\sin\phi\dot{\theta}+\cos\phi\cos\theta\dot{\psi} \end{bmatrix} \\ \begin{bmatrix} \dot{\phi} \\ \dot{\theta} \\ \dot{\psi} \end{bmatrix} = \begin{bmatrix} 1&\sin\phi\tan\theta&\cos\phi\tan\theta\\ 0&\cos\phi&-\sin\phi\\ 0&\frac{\sin\phi}{\cos\theta}&\frac{\cos\phi}{\cos\theta} \end{bmatrix}\vec w w = 1000cosϕsinϕsinθsinϕcosθcosϕcosθ ϕ˙θ˙ψ˙ = ϕ˙sinθψ˙cosϕθ˙+sinϕcosθψ˙sinϕθ˙+cosϕcosθψ˙ ϕ˙θ˙ψ˙ = 100sinϕtanθcosϕcosθsinϕcosϕtanθsinϕcosθcosϕ w
其中 ϕ , θ , ψ \phi,\theta,\psi ϕ,θ,ψ 分别为横滚角、俯仰角、偏航角。

欧拉角微分方程推导

  推导欧拉角微分方程有3种方法。第一种方法比较简单,好多教材里也都这么解释,可以参考
欧拉角导数和角速度之间的转换关系推导 -CSDN博客
另外两种方法用的都是根据旋转矩阵微分方程和旋转矩阵与欧拉角的关系来推导,可以参考
Angular Velocity expressed via Euler Angles -Physics Stack Exchange
【刚体运动】欧拉角时间导数与角速度 -知乎
  下面写一下我对第一种方法的理解。把世界系和本体系分别记作 I , B I,B I,B,世界系 I I I绕Z轴旋转 ψ \psi ψ 角后的坐标系记作 Z Z Z Z Z Z系绕Y轴旋转 θ \theta θ 角后的坐标系记作 Y Y Y。从一个坐标系 A A A到另一个坐标系 B B B的旋转矩阵记作 R B A R_{BA} RBA,即 v B = R B A v A , v A = R A B v B v^B=R_{BA}v^A,v^A=R_{AB}v^B vB=RBAvA,vA=RABvB A A A系与 B B B系之间的角速度向量记作 w A B w_{AB} wAB,并且角速度向量在两系下的坐标是一样的(有人不理解为什么一样的话我再补充)。首先可以直观地得到
w Z I Z = w Z I I = [ 0 0 ψ ˙ ] T w Y Z Y = w Y Z Z = [ 0 θ ˙ 0 ] T w B Y B = w B Y Y = [ ϕ ˙ 0 0 ] T w_{ZI}^Z=w_{ZI}^I=[0 \quad 0 \quad \dot\psi]^\text T \\ w_{YZ}^Y=w_{YZ}^Z=[0 \quad \dot\theta \quad 0]^\text T \\ w_{BY}^B=w_{BY}^Y=[\dot\phi \quad 0 \quad 0]^\text T \\ wZIZ=wZII=[00ψ˙]TwYZY=wYZZ=[0θ˙0]TwBYB=wBYY=[ϕ˙00]T
三次旋转的旋转矩阵分别为
R Z I = R z ( − ψ ) ,   R Y Z = R y ( − θ ) ,   R B Y = R x ( − ϕ ) R_{ZI}=R_z(-\psi),\ R_{YZ}=R_y(-\theta),\ R_{BY}=R_x(-\phi) RZI=Rz(ψ), RYZ=Ry(θ), RBY=Rx(ϕ)
于是
w Z I B = R B Y R Y Z w Z I Z w Y Z B = R B Y w Y Z Y w B I B = w B Y B + w Y Z B + w Z I B = [ ϕ ˙ 0 0 ] + R x ( − ϕ ) [ 0 θ ˙ 0 ] + R x ( − ϕ ) R y ( − θ ) [ 0 0 ψ ˙ ] = [ 1 0 0 0 cos ⁡ ϕ sin ⁡ ϕ 0 − sin ⁡ ϕ cos ⁡ ϕ ] ( [ ϕ ˙ 0 0 ] + [ cos ⁡ θ 0 − sin ⁡ θ 0 1 0 sin ⁡ θ 0 cos ⁡ θ ] [ 0 θ ˙ ψ ˙ ] ) = [ 1 0 0 0 cos ⁡ ϕ sin ⁡ ϕ 0 − sin ⁡ ϕ cos ⁡ ϕ ] [ ϕ ˙ − sin ⁡ θ ψ ˙ θ ˙ cos ⁡ θ ψ ˙ ] = [ ϕ ˙ − sin ⁡ θ ψ ˙ cos ⁡ ϕ θ ˙ + sin ⁡ ϕ cos ⁡ θ ψ ˙ − sin ⁡ ϕ θ ˙ + cos ⁡ ϕ cos ⁡ θ ψ ˙ ] = R x ( − ϕ ) ( [ ϕ ˙ 0 0 ] + R y ( − θ ) ( [ 0 θ ˙ 0 ] + R z ( − ψ ) [ 0 0 ψ ˙ ] ) ) \begin{aligned} w_{ZI}^B =& R_{BY}R_{YZ}w_{ZI}^Z \\ w_{YZ}^B =& R_{BY}w_{YZ}^Y \\ w_{BI}^B =& w_{BY}^B+w_{YZ}^B+w_{ZI}^B \\ =& \begin{bmatrix} \dot{\phi} \\ 0 \\ 0 \end{bmatrix} +R_x(-\phi) \begin{bmatrix} 0 \\ \dot{\theta} \\ 0 \end{bmatrix} +R_x(-\phi)R_y(-\theta) \begin{bmatrix} 0 \\ 0 \\ \dot{\psi} \end{bmatrix} \\ =& \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\phi & \sin\phi \\ 0 & -\sin\phi & \cos\phi \end{bmatrix}\left( \begin{bmatrix} \dot{\phi} \\ 0 \\ 0 \end{bmatrix}+\begin{bmatrix} \cos\theta & 0 & -\sin\theta \\ 0 & 1 & 0 \\ \sin\theta & 0 & \cos\theta \end{bmatrix}\begin{bmatrix} 0 \\ \dot{\theta} \\ \dot{\psi} \end{bmatrix}\right) \\ =& \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\phi & \sin\phi \\ 0 & -\sin\phi & \cos\phi \end{bmatrix}\begin{bmatrix} \dot{\phi}-\sin\theta\dot{\psi} \\ \dot{\theta} \\ \cos\theta\dot{\psi} \end{bmatrix} \\ =& \begin{bmatrix} \dot{\phi}-\sin\theta\dot{\psi} \\ \cos\phi\dot{\theta}+\sin\phi\cos\theta\dot{\psi} \\ -\sin\phi\dot{\theta}+\cos\phi\cos\theta\dot{\psi} \end{bmatrix} \\ =& R_x(-\phi)\left( \begin{bmatrix} \dot{\phi} \\ 0 \\ 0 \end{bmatrix}+R_y(-\theta)\left( \begin{bmatrix} 0 \\ \dot{\theta} \\ 0 \end{bmatrix}+R_z(-\psi)\begin{bmatrix} 0 \\ 0 \\ \dot{\psi} \end{bmatrix}\right)\right) \\ \end{aligned} wZIB=wYZB=wBIB======RBYRYZwZIZRBYwYZYwBYB+wYZB+wZIB ϕ˙00 +Rx(ϕ) 0θ˙0 +Rx(ϕ)Ry(θ) 00ψ˙ 1000cosϕsinϕ0sinϕcosϕ ϕ˙00 + cosθ0sinθ010sinθ0cosθ 0θ˙ψ˙ 1000cosϕsinϕ0sinϕcosϕ ϕ˙sinθψ˙θ˙cosθψ˙ ϕ˙sinθψ˙cosϕθ˙+sinϕcosθψ˙sinϕθ˙+cosϕcosθψ˙ Rx(ϕ) ϕ˙00 +Ry(θ) 0θ˙0 +Rz(ψ) 00ψ˙

  下面写一下我想的另一种方法。由旋转矩阵微分方程可以得到角速度关于旋转矩阵的表达式
(旋转矩阵微分方程的推导见 角速度变化时四元数和旋转矩阵微分方程的证明
R ˙ T = − w ⃗ × R T w ⃗ × = − R ˙ T R \dot{R}^\text T=-\vec w\times R^\text T \\ \vec w^\times=-\dot{R}^\text TR R˙T=w ×RTw ×=R˙TR
或者
R T R = I R ˙ T R + R T R ˙ = 0 w ⃗ × = R T R ˙ R^\text TR=I \\ \dot{R}^\text TR+R^\text T\dot{R}=0 \\ \vec w^\times=R^\text T\dot{R} RTR=IR˙TR+RTR˙=0w ×=RTR˙
因为 R R R 可以看作是多元复合函数 R ( ϕ ( t ) , θ ( t ) , ψ ( t ) ) R(\phi(t),\theta(t),\psi(t)) R(ϕ(t),θ(t),ψ(t)),所以
d R d t = ∂ R ∂ ϕ ϕ ˙ + ∂ R ∂ θ θ ˙ + ∂ R ∂ ψ ψ ˙ \frac{\text dR}{\text dt} =\frac{\partial R}{\partial\phi}\dot{\phi} +\frac{\partial R}{\partial\theta}\dot{\theta} +\frac{\partial R}{\partial\psi}\dot{\psi} dtdR=ϕRϕ˙+θRθ˙+ψRψ˙
于是
w ⃗ × = R T R ˙ = R T ∂ R ∂ ϕ ϕ ˙ + R T ∂ R ∂ θ θ ˙ + R T ∂ R ∂ ψ ψ ˙ \vec w^\times=R^\text T\dot{R} =R^\text T\frac{\partial R}{\partial\phi}\dot{\phi} +R^\text T\frac{\partial R}{\partial\theta}\dot{\theta} +R^\text T\frac{\partial R}{\partial\psi}\dot{\psi} w ×=RTR˙=RTϕRϕ˙+RTθRθ˙+RTψRψ˙
其中 R T ∂ R ∂ ϕ , R T ∂ R ∂ θ , R T ∂ R ∂ ψ R^\text T\frac{\partial R}{\partial\phi},R^\text T\frac{\partial R}{\partial\theta},R^\text T\frac{\partial R}{\partial\psi} RTϕR,RTθR,RTψR 是3个反对称矩阵,简单想想可以理解,因为 w × w^\times w× 是反对称矩阵,而 ϕ ˙ , θ ˙ , ψ ˙ \dot{\phi},\dot{\theta},\dot{\psi} ϕ˙,θ˙,ψ˙ 都是标量并且可以是任意值,那么当 θ ˙ = 0 , ψ ˙ = 0 \dot{\theta}=0,\dot{\psi}=0 θ˙=0,ψ˙=0 时, R T ∂ R ∂ ϕ R^\text T\frac{\partial R}{\partial\phi} RTϕR 一定是反对称矩阵,同理,3个矩阵都是反对称矩阵,并且分别对应角速度和欧拉角时间导数之间转换矩阵 T T T 的3列元素
w ⃗ = T [ ϕ ˙ θ ˙ ψ ˙ ] w ⃗ × = [ R T ∂ R ∂ ϕ R T ∂ R ∂ θ R T ∂ R ∂ ψ ] [ ϕ ˙ θ ˙ ψ ˙ ] T = [ ( R T ∂ R ∂ ϕ ) × ( R T ∂ R ∂ θ ) × ( R T ∂ R ∂ ψ ) × ] = [ [ 0 0 0 0 0 − 1 0 1 0 ] × [ 0 sin ⁡ ( ϕ ) cos ⁡ ( ϕ ) − sin ⁡ ( ϕ ) 0 0 − cos ⁡ ( ϕ ) 0 0 ] × [ 0 − cos ⁡ ( ϕ ) cos ⁡ ( θ ) sin ⁡ ( ϕ ) cos ⁡ ( θ ) cos ⁡ ( ϕ ) cos ⁡ ( θ ) 0 sin ⁡ ( θ ) − sin ⁡ ( ϕ ) cos ⁡ ( θ ) − sin ⁡ ( θ ) 0 ] × ] = [ 1 0 − sin ⁡ θ 0 cos ⁡ ϕ − sin ⁡ ϕ cos ⁡ θ 0 sin ⁡ ϕ cos ⁡ ϕ cos ⁡ θ ] \begin{aligned} \vec w =& T\begin{bmatrix} \dot{\phi} \\ \dot{\theta} \\ \dot{\psi} \end{bmatrix} \\ \vec w^\times =& \begin{bmatrix} R^\text T\frac{\partial R}{\partial\phi} & R^\text T\frac{\partial R}{\partial\theta} & R^\text T\frac{\partial R}{\partial\psi} \end{bmatrix}\begin{bmatrix} \dot{\phi} \\ \dot{\theta} \\ \dot{\psi} \end{bmatrix} \\ T =& \begin{bmatrix} \left(R^\text T\frac{\partial R}{\partial\phi}\right)_\times & \left(R^\text T\frac{\partial R}{\partial\theta}\right)_\times & \left(R^\text T\frac{\partial R}{\partial\psi}\right)_\times \end{bmatrix} \\ =&\begin{bmatrix} \begin{bmatrix}0 & 0 & 0\\0 & 0 & -1\\0 & 1 & 0\end{bmatrix}_\times & \begin{bmatrix}0 & \sin{\left(\phi \right)} & \cos{\left(\phi \right)}\\- \sin{\left(\phi \right)} & 0 & 0\\- \cos{\left(\phi \right)} & 0 & 0\end{bmatrix}_\times & \begin{bmatrix}0 & - \cos{\left(\phi \right)} \cos{\left(\theta \right)} & \sin{\left(\phi \right)} \cos{\left(\theta \right)}\\\cos{\left(\phi \right)} \cos{\left(\theta \right)} & 0 & \sin{\left(\theta \right)}\\- \sin{\left(\phi \right)} \cos{\left(\theta \right)} & - \sin{\left(\theta \right)} & 0\end{bmatrix}_\times \end{bmatrix} \\ =& \begin{bmatrix} 1 & 0 & -\sin\theta \\ 0 & \cos\phi & -\sin\phi\cos\theta \\ 0 & \sin\phi & \cos\phi\cos\theta \end{bmatrix} \end{aligned} w =w ×=T===T ϕ˙θ˙ψ˙ [RTϕRRTθRRTψR] ϕ˙θ˙ψ˙ [(RTϕR)×(RTθR)×(RTψR)×] 000001010 × 0sin(ϕ)cos(ϕ)sin(ϕ)00cos(ϕ)00 × 0cos(ϕ)cos(θ)sin(ϕ)cos(θ)cos(ϕ)cos(θ)0sin(θ)sin(ϕ)cos(θ)sin(θ)0 × 1000cosϕsinϕsinθsinϕcosθcosϕcosθ

推导代码

下面的代码使用 sympy 推导转换矩阵 T T T

import sympy as sp
phi, theta, psi = sp.symbols('\\phi, \\theta, \\psi')
Rx = sp.Matrix([
    [1,           0,              0],
    [0, sp.cos(phi),   -sp.sin(phi)],
    [0, sp.sin(phi),    sp.cos(phi)],
])
Ry = sp.Matrix([
    [sp.cos(theta) , 0, sp.sin(theta)],
    [0             , 1,             0],
    [-sp.sin(theta), 0, sp.cos(theta)],
])
Rz = sp.Matrix([
    [sp.cos(psi), -sp.sin(psi), 0],
    [sp.sin(psi),  sp.cos(psi), 0],
    [0          ,            0, 1],
])
R = (Rz @ Ry @ Rx)
Rdotx = sp.diff(R, phi)
Rdoty = sp.diff(R, theta)
Rdotz = sp.diff(R, psi)
Ransx = sp.simplify(R.T @ Rdotx)
Ransy = sp.simplify(R.T @ Rdoty)
Ransz = sp.simplify(R.T @ Rdotz)
TR = sp.Matrix([
    [-Ransx[5], -Ransy[5], -Ransz[5]],
    [+Ransx[2], +Ransy[2], +Ransz[2]],
    [-Ransx[1], -Ransy[1], -Ransz[1]],
])
# sp.print_latex(TR)
sp.print_latex(sp.simplify(TR.inv()))

另外使用这一代码时,只需要改代码第18行处3次旋转的顺序就可以方便地计算出气动角微分方程(见 攻角、侧滑角、倾侧角与欧拉角的关系
w ⃗ = [ cos ⁡ β cos ⁡ α 0 − sin ⁡ α − sin ⁡ β 1 0 sin ⁡ α cos ⁡ β 0 cos ⁡ α ] [ σ ˙ α ˙ β ˙ ] [ σ ˙ α ˙ β ˙ ] = [ cos ⁡ α cos ⁡ β 0 sin ⁡ α cos ⁡ β cos ⁡ α tan ⁡ β 1 sin ⁡ α tan ⁡ β − sin ⁡ α 0 cos ⁡ α ] w ⃗ \begin{aligned} \vec w =& \begin{bmatrix} \cos\beta \cos\alpha & 0 & - \sin\alpha \\ -\sin\beta & 1 & 0 \\ \sin\alpha \cos\beta & 0 & \cos\alpha \end{bmatrix} \begin{bmatrix} \dot{\sigma} \\ \dot{\alpha} \\ \dot{\beta} \end{bmatrix} \\ \begin{bmatrix} \dot{\sigma} \\ \dot{\alpha} \\ \dot{\beta} \end{bmatrix} =& \begin{bmatrix} \frac{\cos\alpha}{\cos\beta}&0&\frac{\sin\alpha}{\cos\beta}\\ \cos\alpha\tan\beta&1&\sin\alpha\tan\beta\\ -\sin\alpha&0&\cos\alpha \end{bmatrix}\vec w \end{aligned} w = σ˙α˙β˙ = cosβcosαsinβsinαcosβ010sinα0cosα σ˙α˙β˙ cosβcosαcosαtanβsinα010cosβsinαsinαtanβcosα w

仿真

仿真一下来验证sympy推导出的结果正确,将欧拉角微分方程的仿真结果与四元数微分方程的仿真结果比较。
使用欧拉角微分方程建模的被控对象代码如下

# rigidbodyeuler.py
# 四阶龙格库塔法根据欧拉角微分方程建立刚体的运动学和动力学模型
import numpy as np
# from quaternions import *

# 刚体
# J: 刚体的转动惯量矩阵
# initEuler: 刚体的初始欧拉角
# initOmega: 刚体的初始角速度向量
class RigidBody:
    def __init__(self, J, initEuler, initOmega):
        self._J = J
        e1 = initEuler
        w1 = initOmega
        self._t = 0
        self._Jinv = np.linalg.inv(self._J)
        self._states = np.concatenate((e1, w1), dtype=float)
        self.ctrlLaw = lambda x: 0  # 控制律

    def Simulate_OneStep(self):
        h = 0.01
        K1 = self._ODE4Function(self._t, self._states)
        K2 = self._ODE4Function(self._t+h/2, self._states + h/2*K1)
        K3 = self._ODE4Function(self._t+h/2, self._states + h/2*K2)
        K4 = self._ODE4Function(self._t+h, self._states + h*K3)
        dx = h/6*(K1 + 2*K2 + 2*K3 + K4)
        self._states += dx

    def Get_State(self):
        return self._states
    def Get_EulerVec(self):
        # q1 = Euler_To_Quaternion(self._states[0:3])
        # return Quaternion_to_Euler(q1)
        return self._states[0:3]

    def _ODE4Function(self, t, x):
        E, W = x[0:3], x[3:6]
        matTR = np.matrix([
            [1, 0, -np.sin(E[1])],
            [0,  np.cos(E[0]), np.sin(E[0])*np.cos(E[1])],
            [0, -np.sin(E[0]), np.cos(E[0])*np.cos(E[1])],
        ])
        # matTR = np.matrix([
        #     [1, np.sin(E[0])*np.tan(E[1]), np.cos(E[0])*np.tan(E[1])],
        #     [0, np.cos(E[0]), - np.sin(E[0])],
        #     [0, np.sin(E[0]) / np.cos(E[1]), np.cos(E[0]) / np.cos(E[1])],
        # ])
        dE = np.linalg.inv(matTR) @ W
        # dE = matTR @ W
        torque = self.ctrlLaw(x)
        dW = self._Jinv @ (torque - np.cross(W, self._J @ W))[0]
        return np.concatenate((np.array(dE)[0], np.array(dW)[0]))

四元数微分方程代码见 刚体四元数姿态控制
主程序如下

# main.py
import numpy as np
import matplotlib.pyplot as plt
# from rigidbodyquaternion import RigidBody
from rigidbodyeuler import RigidBody
J = np.matrix([
            [1, 0, 0],
            [0, 10, 0],
            [0, 0, 3],
])
usv1 = RigidBody(J, np.array([1, -0.2, 0.3]), np.array([-0.1, 0.2, -0.3]))
t = 0
plottime, plotdata = [], []
while t < 10:
    for n in range(10):
        usv1.Simulate_OneStep()
    t += 0.1
    e1 = usv1.Get_EulerVec()
    plotdata.append(e1.tolist())
    plottime.append(t)
plt.plot(plottime, np.array(plotdata))
plt.legend(['roll', 'pitch', 'yaw'])
plt.show()

四元数和欧拉角微分方程的仿真结果相同,如图所示。
在这里插入图片描述

欧拉角的缺点

  可以说欧拉角除了看上去更直观以外几乎没有任何优点了。本文从欧拉角微分方程的角度谈谈欧拉角的其中一个缺点:在限定的范围以外不连续。首先应该知道的是,四元数、欧拉角、旋转矩阵这三种描述姿态的方法之间可以互相换算,也几乎可以一一对应,之所以说“几乎”就是因为,如果旋转角度过大,这种对应关系就出了一些问题。
  先看看当绕俯仰轴(Y轴)旋转一圈时,3种姿态表示方法的表现。
四元数:
四元数
欧拉角:
欧拉角
旋转矩阵:
旋转矩阵
由此可见,在大角度机动时欧拉角存在严重的不连续问题,应尽量避免使用。
画这3幅图使用四元数微分方程的代码,把控制律设成0,初始欧拉角为全0,初始角速度为 [ 0 , 1 , 0 ] [0,1,0] [0,1,0]。如果使用欧拉角微分方程,则需要把俯仰角约束在 ± 9 0 ∘ \pm 90^\circ ±90 以内。也可以直接简单地使用欧拉角转一圈,同时转四元数和旋转矩阵出图,但此时我就发现了欧拉角转四元数的问题。

下面的代码是最常见的欧拉角转四元数的代码

def Euler_To_Quaternion(euler):
    from numpy import sin, cos
    cr = cos(euler[0] * 0.5)
    sr = sin(euler[0] * 0.5)
    cp = cos(euler[1] * 0.5)
    sp = sin(euler[1] * 0.5)
    cy = cos(euler[2] * 0.5)
    sy = sin(euler[2] * 0.5)
    q0 = cy * cp * cr + sy * sp * sr
    q1 = cy * cp * sr - sy * sp * cr
    q2 = sy * cp * sr + cy * sp * cr
    q3 = sy * cp * cr - cy * sp * sr
    return np.array([q0, q1, q2, q3])

这一代码出自下面这个公式
Q = [ cos ⁡ ( ψ / 2 ) 0 0 sin ⁡ ( ψ / 2 ) ] [ cos ⁡ ( θ / 2 ) 0 sin ⁡ ( θ / 2 ) 0 ] [ cos ⁡ ( ϕ / 2 ) sin ⁡ ( ϕ / 2 ) 0 0 ] = [ cos ⁡ ( ϕ / 2 ) cos ⁡ ( θ / 2 ) cos ⁡ ( ψ / 2 ) + sin ⁡ ( ϕ / 2 ) sin ⁡ ( θ / 2 ) sin ⁡ ( ψ / 2 ) sin ⁡ ( ϕ / 2 ) cos ⁡ ( θ / 2 ) cos ⁡ ( ψ / 2 ) − cos ⁡ ( ϕ / 2 ) sin ⁡ ( θ / 2 ) sin ⁡ ( ψ / 2 ) cos ⁡ ( ϕ / 2 ) sin ⁡ ( θ / 2 ) cos ⁡ ( ψ / 2 ) + sin ⁡ ( ϕ / 2 ) cos ⁡ ( θ / 2 ) sin ⁡ ( ψ / 2 ) cos ⁡ ( ϕ / 2 ) cos ⁡ ( θ / 2 ) sin ⁡ ( ψ / 2 ) − sin ⁡ ( ϕ / 2 ) sin ⁡ ( θ / 2 ) cos ⁡ ( ψ / 2 ) ] (1) \begin{aligned} Q & =\left[\begin{array}{c} \cos (\psi / 2) \\ 0 \\ 0 \\ \sin (\psi / 2) \end{array}\right]\left[\begin{array}{c} \cos (\theta / 2) \\ 0 \\ \sin (\theta / 2) \\ 0 \end{array}\right]\left[\begin{array}{c} \cos (\phi / 2) \\ \sin (\phi / 2) \\ 0 \\ 0 \end{array}\right] \\ & =\left[\begin{array}{l} \cos (\phi / 2) \cos (\theta / 2) \cos (\psi / 2)+\sin (\phi / 2) \sin (\theta / 2) \sin (\psi / 2) \\ \sin (\phi / 2) \cos (\theta / 2) \cos (\psi / 2)-\cos (\phi / 2) \sin (\theta / 2) \sin (\psi / 2) \\ \cos (\phi / 2) \sin (\theta / 2) \cos (\psi / 2)+\sin (\phi / 2) \cos (\theta / 2) \sin (\psi / 2) \\ \cos (\phi / 2) \cos (\theta / 2) \sin (\psi / 2) - \sin (\phi / 2) \sin (\theta / 2) \cos (\psi / 2) \end{array}\right] \end{aligned} \tag{1} Q= cos(ψ/2)00sin(ψ/2) cos(θ/2)0sin(θ/2)0 cos(ϕ/2)sin(ϕ/2)00 = cos(ϕ/2)cos(θ/2)cos(ψ/2)+sin(ϕ/2)sin(θ/2)sin(ψ/2)sin(ϕ/2)cos(θ/2)cos(ψ/2)cos(ϕ/2)sin(θ/2)sin(ψ/2)cos(ϕ/2)sin(θ/2)cos(ψ/2)+sin(ϕ/2)cos(θ/2)sin(ψ/2)cos(ϕ/2)cos(θ/2)sin(ψ/2)sin(ϕ/2)sin(θ/2)cos(ψ/2) (1)
同样地绕y轴转一圈看看欧拉角转四元数式(1)的表现。首先可以求出四元数随时间变化的解析解。设角速度为 w ⃗ = [ 0 , 1 , 0 ] T \vec w=[0,1,0]^\text T w =[0,1,0]T,四元数初值为 Q 0 = [ 1 , 0 , 0 , 0 ] T Q_0=[1,0,0,0]^\text T Q0=[1,0,0,0]T,代入四元数微分方程
[ q ˙ 0 q ˙ 1 q ˙ 2 q ˙ 3 ] = 1 2 [ 0 − w x − w y − w z w x 0 w z − w y w y − w z 0 w x w z w y − w x 0 ] [ q 0 q 1 q 2 q 3 ] = 1 2 [ 0 0 − 1 0 0 0 0 − 1 1 0 0 0 0 1 0 0 ] [ q 0 q 1 q 2 q 3 ] q ˙ 1 = − 0.5 q 3 = 0 q ˙ 3 = 0.5 q 1 = 0 q ˙ 2 = 0.5 q 0 q ¨ 0 = − 0.5 q ˙ 2 = − 0.25 q 0 q 0 ( t ) = C 1 cos ⁡ t 2 + C 2 sin ⁡ t 2 = cos ⁡ t 2 q 2 ( t ) = sin ⁡ t 2 \begin{aligned} \begin{bmatrix} \dot q_0 \\ \dot q_1 \\ \dot q_2 \\ \dot q_3 \end{bmatrix} =& \frac{1}{2}\begin{bmatrix} 0 & -w_x & -w_y & -w_z \\ w_x & 0 & w_z & -w_y \\ w_y & -w_z & 0 & w_x \\ w_z & w_y & -w_x & 0 \end{bmatrix} \begin{bmatrix} q_0 \\ q_1 \\ q_2 \\ q_3 \end{bmatrix} \\ =& \frac 12\begin{bmatrix} 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & -1 \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \end{bmatrix} \begin{bmatrix} q_0 \\ q_1 \\ q_2 \\ q_3 \end{bmatrix} \\ \dot q_1 =& -0.5q_3=0 \\ \dot q_3 =& 0.5q_1=0 \\ \dot q_2 =& 0.5q_0 \\ \ddot q_0 =& -0.5\dot q_2=-0.25q_0 \\ q_0(t) =& C_1\cos\frac t2+C_2\sin\frac t2=\cos\frac t2 \\ q_2(t) =& \sin\frac t2 \end{aligned} q˙0q˙1q˙2q˙3 ==q˙1=q˙3=q˙2=q¨0=q0(t)=q2(t)=21 0wxwywzwx0wzwywywz0wxwzwywx0 q0q1q2q3 21 0010000110000100 q0q1q2q3 0.5q3=00.5q1=00.5q00.5q˙2=0.25q0C1cos2t+C2sin2t=cos2tsin2t
这个解也很直观地表现出四元数的变化过程,但是这个结果跟式(1)的不同之处在于少了横滚角 ϕ \phi ϕ 和偏航角 ψ \psi ψ,因此在大角度机动时根据式(1)计算的四元数也不连续了,这不是四元数的问题,而是式(1)的问题。
根据式(1)计算出的错误的四元数变化曲线如下图所示。
在这里插入图片描述
直接使用四元数定义计算出正确的四元数变化曲线如下图所示。
在这里插入图片描述
出图代码如下,其中 quaternions.py 的代码见 自用的四元数、欧拉角、旋转矩阵转换代码

import numpy as np
import matplotlib.pyplot as plt
from quaternions import *
plottime, plotq0, plotq2 = [], [], []
for n1 in range(100):
    t = n1 * 0.1  # 角度从0到10弧度(4.7124弧度是-y轴)
    vecx = np.array([np.cos(t), 0, -np.sin(t)])  # 组成旋转矩阵的x轴坐标
    vecy = np.array([0, 1, 0])  # 组成旋转矩阵的y轴坐标
    vecz = np.array([np.sin(t), 0, np.cos(t)])  # 组成旋转矩阵的z轴坐标
    R = np.vstack([vecx, vecy, vecz]).T  # 旋转矩阵
    E = Rotation_to_Euler(R)  # 由旋转矩阵计算欧拉角
    # Q = Euler_To_Quaternion(E)  # 由欧拉角计算四元数(有问题的转换公式)
    Q = [np.cos(t/2), 0, np.sin(t/2), 0]  # 直接使用四元数定义(正确的结果)
    plottime.append(t)
    plotq0.append(Q[0])
    plotq2.append(Q[2])
plt.plot(plottime, plotq0)
plt.plot(plottime, plotq2)
plt.legend(['q0', 'q2'])
plt.show()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值