学习笔记搜索

01.1|先把一个向量说清楚:坐标、姿态与传感器杆臂

这一课解决最基础也最容易被软件掩盖的问题:同一条速度为什么会有三个不同的数字?输入是带坐标标签的向量、姿态和传感器安装位置;输出是正确的导航速度、姿态传播式和传感器点速度模型。后续动力学、EKF、位置控制和推进器分配,都以这里的约定为共同语言。不要先记旋转矩阵;先想清楚物理向量没有改变,改变的是用哪组三根基向量描述它。

开始前只需掌握这些

先读 00.1 向量与矩阵乘法;本课出现姿态求导时,再回看 00.2 导数。第一遍只要求会解释 vn=Rbnvbv^n=R_b^nv^b、会算一例杆臂速度。欧拉角和四元数部分可在这两个问题完成后分第二遍阅读。

符号含义与维度单位/坐标约定
n,b,cn,b,c三个右手坐标系nn:北东下;bb:前右下;cc:相机右下前
RbnR_b^n3×33\times3姿态矩阵,把bb分量变为nn分量无量纲;列向量是bb基轴在nn的表示
pn,vnp^n,v^n参考点位置、对地速度;各3×13\times1m、m/s\mathrm{m/s};nn
ωb=[pr,qr,rr]T\omega^b=[p_r,q_r,r_r]^T机体对nn角速度;3×13\times1rad/s\mathrm{rad/s};bb,角速率下标避免混同位置pp
ϕ,θ,ψ;q=[q0,qvT]T\phi,\theta,\psi;q=[q_0,q_v^T]^T横滚俯仰偏航;标量在前Hamilton单位四元数rad;qq描述b→nb\to n
ℓb\ell^b参考点到传感器的固定杆臂;3×13\times1m;bb

从基向量投影到可检查的旋转矩阵

假设研究区域足够小,可把导航系看成局部惯性系;姿态描述刚性机体,安装外参在本课保持常数。令机体三根单位轴在导航系中的坐标为矩阵的三列。将一个向量沿机体三轴展开,再对导航三轴取投影,就得到第一行等式。基轴正交使内积保持不变,所以逆矩阵是转置;右手性再要求行列式为正一,而不仅是正交。

an=[ebxn ebyn ebzn]ab=Rbnab,(Rbn)TRbn=I3,det⁡Rbn=1,Rnb=(Rbn)T.\begin{aligned}a^n&=[e_{b_x}^n\ e_{b_y}^n\ e_{b_z}^n]a^b=R_b^n a^b,\\(R_b^n)^TR_b^n&=I_3,\qquad\det R_b^n=1,\qquad R_n^b=(R_b^n)^T.\end{aligned}

(1.1)

把式(1.1)(1.1)拆成一次真正的换基

这里的 aa 可以是速度、力或位移,但一次计算中必须始终是同一种物理量;上标只是分量所用坐标系,绝不是幂。ebxne_{b_x}^n 是机体前轴在导航系中的三个方向余弦。第一步把物理向量写成“前轴乘前向分量,加右轴乘侧向分量,加下轴乘垂直分量”;第二步把三项并成矩阵乘法。第三步计算任意两列的内积:相同列得一,不同列得零,便得到正交性。若矩阵只是交换两个轴而没有同步反号,行列式可能是负一,那是镜像,不是刚体姿态。

例如 ab=(1,2,3)Ta^b=(1,2,3)^T 且机头向东,三项分别贡献导航系的 (0,1,0)T(0,1,0)^T、(−2,0,0)T(-2,0,0)^T 和 (0,0,3)T(0,0,3)^T,相加得 an=(−2,1,3)Ta^n=(-2,1,3)^T。长度平方仍为 1414,提供了比单看符号更强的检查。代码实现中先决定矩阵列的意义,再决定存储采用行主序还是列主序;数组布局不会改变数学定义。

采用ZYX姿态参数化:先以偏航确定水平朝向,再俯仰,再横滚。下面矩阵乘法从右向左作用于向量;不能把乘法顺序与口头描述的姿态构造混为一谈。记号cc和ss分别表示对应角的余弦和正弦。将三个基本矩阵相乘,就逐项得到最后的完整矩阵;例如第一列仅受俯仰和偏航影响,因为绕自身前轴的横滚不改变前轴方向。

Rx(ϕ)=[1000cϕ−sϕ0sϕcϕ],Ry(θ)=[cθ0sθ010−sθ0cθ],Rz(ψ)=[cψ−sψ0sψcψ0001],Rbn=RzRyRx=[cψcθcψsθsϕ−sψcϕcψsθcϕ+sψsϕsψcθsψsθsϕ+cψcϕsψsθcϕ−cψsϕ−sθcθsϕcθcϕ].\begin{aligned}R_x(\phi)&=\begin{bmatrix}1&0&0\\0&c_\phi&-s_\phi\\0&s_\phi&c_\phi\end{bmatrix},\quad R_y(\theta)=\begin{bmatrix}c_\theta&0&s_\theta\\0&1&0\\-s_\theta&0&c_\theta\end{bmatrix},\\R_z(\psi)&=\begin{bmatrix}c_\psi&-s_\psi&0\\s_\psi&c_\psi&0\\0&0&1\end{bmatrix},\\R_b^n&=R_zR_yR_x=\begin{bmatrix}c_\psi c_\theta&c_\psi s_\theta s_\phi-s_\psi c_\phi&c_\psi s_\theta c_\phi+s_\psi s_\phi\\s_\psi c_\theta&s_\psi s_\theta s_\phi+c_\psi c_\phi&s_\psi s_\theta c_\phi-c_\psi s_\phi\\-s_\theta&c_\theta s_\phi&c_\theta c_\phi\end{bmatrix}.\end{aligned}

(1.2)

为什么式(1.2)(1.2)中某些负号不能“凭感觉调整”

绕向下轴正转时,前轴朝右转,因此偏航矩阵第一列的东向分量是 +sinψ+sin\psi。绕向右轴正转时,前轴向上抬,因而俯仰矩阵第一列的下向分量是 −sin⁡θ-\sin\theta。这两个右手规则已经固定了大部分容易写错的符号。矩阵第三列表示机体下轴,不是重力本身;只有水平时它才与导航下轴重合。

完整乘法可以手算一个元素:乘积第一行第二列先取 RyRxR_yR_x 的第二列 (sin⁡θsin⁡ϕ,cos⁡ϕ,cos⁡θsin⁡ϕ)T(\sin\theta\sin\phi,\cos\phi,\cos\theta\sin\phi)^T,再与 RzR_z 第一行 (cos⁡ψ,−sin⁡ψ,0)(\cos\psi,-\sin\psi,0) 点乘,得到 cos⁡ψsin⁡θsin⁡ϕ−sin⁡ψcos⁡ϕ\cos\psi\sin\theta\sin\phi-\sin\psi\cos\phi。每个元素都按同样规则产生,不存在独立调正负号的自由。实现时统一以弧度传入三角函数;把数值 9090 直接传给 std::sin 并不是九十度。

手算:水平、向东即偏航90度时,机体前速0.2 m/s\mathrm{m/s}变为导航东速0.2 m/s\mathrm{m/s};导航北向目标则在机体系表现为左向。相机光轴若恰好对齐机体前轴,则相机右、下、前三轴分别对应机体右、下、前。此时下面的安装矩阵可以直接由三根轴填写;真实安装有偏角时应再乘标定旋转,不能沿用一个任意交换轴。

Rbn(0,0,π/2)=[0−10100001],Rcb=[001100010],Rcn=RbnRcb.R_b^n(0,0,\pi/2)=\begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\end{bmatrix},\qquad R_c^b=\begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix},\qquad R_c^n=R_b^nR_c^b.

(1.3)

式(1.3)(1.3)的安装外参与姿态为什么必须分开

RcbR_c^b 是安装标定结果,艇体转向时通常不变;RbnR_b^n 是运行中的姿态,随时间变化。组合矩阵的中间坐标必须消去:先把相机分量变成机体分量,再变成导航分量,故顺序是 RbnRcbR_b^nR_c^b,不是反过来。拿相机光轴单位向量 (0,0,1)T(0,0,1)^T 做检查:安装矩阵将它变成机体 (1,0,0)T(1,0,0)^T,九十度偏航又变成导航 (0,1,0)T(0,1,0)^T。如果最终不是东向,错误发生在轴约定或乘法顺序,而不是传感器噪声。对DVL安装也做同一检查,只是设备轴向不必等于这里的相机约定。

先把叉乘矩阵按一行一行乘开

后面的 [ωb]×[\omega^b]_\times 就是 00.1 的叉乘表,没有额外定义。若只绕下轴转,ωb=[0,0,rr]T\omega^b=[0,0,r_r]^T,则

[ωb]×=[0−rr0rr00000],[ωb]×ℓb=[−rrℓyrrℓx0].[\omega^b]_\times=\begin{bmatrix}0&-r_r&0\\r_r&0&0\\0&0&0\end{bmatrix}, \qquad [\omega^b]_\times\ell^b=\begin{bmatrix}-r_r\ell_y\\r_r\ell_x\\0\end{bmatrix}.

ℓx,ℓy\ell_x,\ell_y 是杆臂前、右分量(m),rrr_r 是偏航角速度(rad/s),结果单位为 m/s。令 rr=0.5 rad/sr_r=0.5\ \mathrm{rad/s}、ℓb=[0.2,0,0]T m\ell^b=[0.2,0,0]^T\ \mathrm m,就得到传感器相对参考点向右 0.1 m/s0.1\ \mathrm{m/s} 的速度。把叉乘换成矩阵是为了以后统一做乘法和求导,不是为了让物理更复杂。

欧拉角变化率不是陀螺仪的三个读数

陀螺仪输出的是瞬时机体角速度。欧拉角变化率却分别绕三个不同的中间轴发生。将偏航轴、俯仰轴和横滚轴都投到最终机体系,再相加,得到下式左矩阵。对其求逆便得到右侧的TT矩阵;因此只有姿态接近水平时,三个欧拉角速率才近似等于机体角速度。俯仰达到正负90度时,余弦分母为零,是参数化失效,不是机器人角速度无穷大。

ωb=[10−sθ0cϕsϕcθ0−sϕcϕcθ][ϕ˙θ˙ψ˙],[ϕ˙θ˙ψ˙]=T(ϕ,θ)ωb,T=[1sϕtan⁡θcϕtan⁡θ0cϕ−sϕ0sϕ/cθcϕ/cθ].\begin{aligned}\omega^b&=\begin{bmatrix}1&0&-s_\theta\\0&c_\phi&s_\phi c_\theta\\0&-s_\phi&c_\phi c_\theta\end{bmatrix}\begin{bmatrix}\dot\phi\\\dot\theta\\\dot\psi\end{bmatrix},\\\begin{bmatrix}\dot\phi\\\dot\theta\\\dot\psi\end{bmatrix}&=T(\phi,\theta)\omega^b,\quad T=\begin{bmatrix}1&s_\phi\tan\theta&c_\phi\tan\theta\\0&c_\phi&-s_\phi\\0&s_\phi/c_\theta&c_\phi/c_\theta\end{bmatrix}.\end{aligned}

(1.4)

用两个标量方程亲手解出式(1.4)(1.4)

先看机体系第二、第三行:qr=cos⁡ϕθ˙+sin⁡ϕcos⁡θψ˙q_r=\cos\phi\dot\theta+\sin\phi\cos\theta\dot\psi,rr=−sin⁡ϕθ˙+cos⁡ϕcos⁡θψ˙r_r=-\sin\phi\dot\theta+\cos\phi\cos\theta\dot\psi。第一式乘 cos⁡ϕ\cos\phi 减第二式乘 sin⁡ϕ\sin\phi,交叉项抵消,得到 θ˙=cos⁡ϕqr−sin⁡ϕrr\dot\theta=\cos\phi q_r-\sin\phi r_r。第一式乘 sin⁡ϕ\sin\phi 加第二式乘 cos⁡ϕ\cos\phi,得到 cos⁡θψ˙=sin⁡ϕqr+cos⁡ϕrr\cos\theta\dot\psi=\sin\phi q_r+\cos\phi r_r。最后将 ψ˙\dot\psi 代回第一行 pr=ϕ˙−sin⁡θψ˙p_r=\dot\phi-\sin\theta\dot\psi,三行逆矩阵就都出来了。

例如横滚零、俯仰三十度,只测到机体偏航角速率 rr=0.2 rad/sr_r=0.2\ \mathrm{rad/s},实际欧拉角速率是 ϕ˙≈0.11547\dot\phi\approx0.11547、θ˙=0\dot\theta=0、ψ˙≈0.23094 rad/s\dot\psi\approx0.23094\ \mathrm{rad/s}。把陀螺仪第三项直接积分成偏航会系统性算错。TT 是速率参数变换,不是正交旋转矩阵,因此不能用转置代替逆。

为了避免欧拉角奇异,积分内部用单位四元数。令旋转轴为单位向量aa、旋转角为α\alpha,则四元数标量部是半角余弦、向量部是半角正弦乘轴。把纯向量四元数夹在qq与其共轭之间,展开Hamilton乘法便得到旋转矩阵。下式中的叉乘矩阵定义也固定了所有正负号。qq与负qq表示同一姿态,比较两个四元数前应先令其内积非负。

[a]×=[0−a3a2a30−a1−a2a10],q=[cos⁡(α/2)asin⁡(α/2)],R(q)=(q02−qvTqv)I3+2qvqvT+2q0[qv]×,q˙=12q⊗[0,(ωb)T]T=12[0−(ωb)Tωb−[ωb]×]q.\begin{aligned}[a]_\times&=\begin{bmatrix}0&-a_3&a_2\\a_3&0&-a_1\\-a_2&a_1&0\end{bmatrix},\quad q=\begin{bmatrix}\cos(\alpha/2)\\a\sin(\alpha/2)\end{bmatrix},\\R(q)&=(q_0^2-q_v^Tq_v)I_3+2q_vq_v^T+2q_0[q_v]_\times,\\\dot q&=\tfrac12q\otimes[0,(\omega^b)^T]^T=\tfrac12\begin{bmatrix}0&-(\omega^b)^T\\\omega^b&-[\omega^b]_\times\end{bmatrix}q.\end{aligned}

(1.5)

式(1.5)(1.5):四元数乘法到底增加了什么

Hamilton乘法把两个四元数 (s,x)(s,x)、(t,y)(t,y) 定义为 (st−xTy, sy+tx+x×y)(st-x^Ty,\ sy+tx+x\times y),其中 s,ts,t 为标量、x,yx,y 为三维向量。对单位四元数,共轭 (q0,−qv)(q_0,-q_v) 就是逆。将纯向量 (0,ab)(0,a^b) 先左乘 qq 再右乘共轭,并收集 aba^b 的系数:标量平方贡献单位矩阵项,向量外积贡献第二项,叉乘贡献第三项,这正是式中的 R(q)R(q)。因此它不是另加一套物理,而是同一旋转的无奇异参数表示。

微分式中的 1/21/2 来自半角,不是可调增益。四元数四个分量无量纲,其导数单位为每秒;角速度以弧度每秒输入。手算九十度偏航时 q=(2/2,0,0,2/2)Tq=(\sqrt2/2,0,0,\sqrt2/2)^T,矩阵第一行第二列是 −1-1、第二行第一列是 +1+1,与前面的换基矩阵一致。源码中遇到四元数构造函数,要先读清标量在前还是在后、表示机体到地面还是其逆,不能只凭类型名移植公式。

最后一行来自一个短时间间隔内的增量四元数:标量部近似一,向量部近似角速度乘时间的一半。机体角速度对应右乘增量;若改成导航角速度,乘法方向也要改。数值上可以直接用有限角度增量右乘,然后归一化,而不是让欧拉积分逐渐破坏单位长度。

δq=[cos⁡(∥ωb∥Δt/2)ωb∥ωb∥sin⁡(∥ωb∥Δt/2)],qk+1=qk⊗δq∥qk⊗δq∥,R˙bn=Rbn[ωb]×.\begin{aligned}\delta q&=\begin{bmatrix}\cos(\|\omega^b\|\Delta t/2)\\\dfrac{\omega^b}{\|\omega^b\|}\sin(\|\omega^b\|\Delta t/2)\end{bmatrix},\quad q_{k+1}=\frac{q_k\otimes\delta q}{\|q_k\otimes\delta q\|},\\\dot R_b^n&=R_b^n[\omega^b]_\times.\end{aligned}

(1.6)

式(1.6)(1.6)怎样变成一拍一拍的传播

令 Δt\Delta t 是两次IMU有效时间戳之差,单位秒;本式假设这一拍内角速度恒定。先算转角 α=∥ωb∥Δt\alpha=\|\omega^b\|\Delta t,再算其一半的正余弦,最后按Hamilton规则右乘增量。右乘表示增量轴是在当前机体系表达。归一化是消除舍入误差,不会修正陀螺偏置。若角速度变动很快,还需使用更细积分或圆锥运动补偿,而不是仅提高归一化频率。

静止时应直接得到单位增量;以 1 rad/s1\ \mathrm{rad/s} 绕下轴转动 0.1 s0.1\ \mathrm{s} 时,标量部约为 0.998750260.99875026,第三向量分量约为 0.049979170.04997917。传播后用同一姿态旋转机体前轴,结果应为 (0.99500417,0.09983342,0)T(0.99500417,0.09983342,0)^T。这个检查同时验证了半角、乘法方向与单位。

零角速度时,增量四元数直接定义为 δq=[1,0,0,0]T\delta q=[1,0,0,0]^T,不能按上式字面做零除零。为稳定处理很小的角速度,可令 x=∥ωb∥Δt/2x=\|\omega^b\|\Delta t/2,将向量部写成 (Δt/2)sinc⁡(x)ωb(\Delta t/2)\operatorname{sinc}(x)\omega^b,这里 sinc⁡(x)=sin⁡x/x\operatorname{sinc}(x)=\sin x/x,并取 sinc⁡(0)=1\operatorname{sinc}(0)=1;小角度时使用 1−x2/61-x^2/6 即可避免数值损失。

杆臂:从位置求导,不靠背补偿符号

同一刚体上参考点 OO和传感器SS的位置相差旋转后的固定杆臂。对这个位置关系逐项求导:参考点产生平移速度,旋转矩阵导数产生切向速度。再乘转置把导航分量转回机体,就得到传感器模型。观测预测应加杆臂速度;从传感器读数还原参考点速度则应减去它,这两个问题不能混为一个“补偿加号”。

pSn=pOn+Rbnℓb,vSn=vOn+Rbn[ωb]×ℓb,vSb=(Rbn)TvOn+ωb×ℓb,vOn=Rbn(vSb−ωb×ℓb).\begin{aligned}p_S^n&=p_O^n+R_b^n\ell^b,\\v_S^n&=v_O^n+R_b^n[\omega^b]_\times\ell^b,\\v_S^b&=(R_b^n)^Tv_O^n+\omega^b\times\ell^b,\\v_O^n&=R_b^n(v_S^b-\omega^b\times\ell^b).\end{aligned}

(1.7)

式(1.7)(1.7)中参考点必须先讲清

下标 OO 是我们希望估计和控制的参考点,SS 是传感器测量中心;杆臂方向必须是从 OO 指向 SS。若厂家给的是反方向,先取负再代入。推导第一行时两点位置都在同一个导航原点下,才能相减;推导第二行时杆臂在机体系恒定,所以没有额外的 Rℓ˙R\dot\ell。第三行把整个式子左乘 RTR^T,而不是仅旋转平移部分。最后一行是求参考点速度的逆问题。

一个有效的程序测试是先正向合成传感器速度,再用补偿函数还原参考点速度。令 vOn=(0.1,0,0)Tv_O^n=(0.1,0,0)^T、偏航九十度、ωb=(0,0,0.2)T\omega^b=(0,0,0.2)^T,仍用本课杆臂,则传感器机体速度为 (0,−0.172,0)T(0,-0.172,0)^T;补偿后应恢复导航北向 0.1 m/s0.1\ \mathrm{m/s}。若直接把观测旋转到导航系,会得到北向 0.172 m/s0.172\ \mathrm{m/s},误差正是旋转杆臂带来的那一项。

使用项目杆臂示例(−0.360,0,0.125)(-0.360,0,0.125)m,原地以0.2 rad/s\mathrm{rad/s}绕向下轴偏航,叉乘给出(0,−0.072,0) m/s(0,-0.072,0)\,\mathrm{m/s}。传感器显示向左运动完全符合刚体几何,不应把它吸收进DVL偏置。若漏掉这一项,滤波器可能错误地修正参考点速度,进而让位置积分漂移。

离线算法、源码入口与手写练习

参考实现:C++17,先独立手写再展开
// 独立教学实现,C++17;单位m、s、rad,机体FRD,导航NED
#include <array>
#include <cmath>
#include <cassert>
#include <iostream>
using V=std::array<double,3>;
V cross(V a,V b){return {a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]};}
V rz(double psi,V v){double c=std::cos(psi),s=std::sin(psi);return {c*v[0]-s*v[1],s*v[0]+c*v[1],v[2]};}
V referenceVelocity(double psi,V sensor,V omega,V lever){
    V rotational=cross(omega,lever);
    for(int i=0;i<3;++i)sensor[i]-=rotational[i];
    return rz(psi,sensor);
}
using Q=std::array<double,4>; // 标量在前,b到n
Q multiply(Q a,Q b){
    return {a[0]*b[0]-a[1]*b[1]-a[2]*b[2]-a[3]*b[3],
      a[0]*b[1]+a[1]*b[0]+a[2]*b[3]-a[3]*b[2],
      a[0]*b[2]-a[1]*b[3]+a[2]*b[0]+a[3]*b[1],
      a[0]*b[3]+a[1]*b[2]-a[2]*b[1]+a[3]*b[0]};
}
Q propagate(Q q,V w,double dt){
    double norm=std::sqrt(w[0]*w[0]+w[1]*w[1]+w[2]*w[2]);
    double x=norm*dt/2;
    double sinc=std::abs(x)<1e-6?1-x*x/6:std::sin(x)/x;
    double k=dt*sinc/2;
    Q next=multiply(q,{std::cos(x),k*w[0],k*w[1],k*w[2]});
    double n=0;for(double v:next)n+=v*v;
    for(double &v:next)v/=std::sqrt(n);
    return next;
}
int main(){
    const double pi=std::acos(-1.0);
    V v=referenceVelocity(pi/2,{0,-.172,0},{0,0,.2},{-.360,0,.125});
    assert(std::abs(v[0]-.1)<1e-12 && std::abs(v[1])<1e-12);
    Q q=propagate({1,0,0,0},{0,0,1},.1);
    assert(std::abs(q[0]-std::cos(.05))<1e-12);
    assert(std::abs(q[3]-std::sin(.05))<1e-12);
    Q stationary=propagate({1,0,0,0},{0,0,0},.1);
    assert(stationary[0]==1 && stationary[3]==0);
    std::cout<<v[0]<<" "<<v[1]<<" "<<v[2]<<"\n";
}

项目阅读顺序:ArduSub/handle_dvl_data.cpp 的 dvl_data_BI 先核对设备轴向和mm/s\mathrm{mm/s}到m/s\mathrm{m/s};AP_AHRS_NavEKF::writeBodyFrameOdom 进入机体系里程计接口;libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp 的 FuseBodyVel 再查看预测和杆臂如何组合。报告中的创新采用预测减观测,本教材统一观测减预测,两者只是整套更新符号要一致。随后看 AP_InertialNav_NavEKF::update:NED米到NEU厘米需要第三轴反号并乘100。

练习一:手写矩阵乘法验证RTR=I3R^TR=I_3,并用航向90度把北向1 m/s\mathrm{m/s}转回机体。答案要点:得到(0,−1,0) m/s(0,-1,0)\,\mathrm{m/s}。练习二:将杆臂改为(0.3,0.1,0)(0.3,0.1,0)m、偏航角速度改为−0.4 rad/s\mathrm{rad/s},算传感器速度。答案:(0.04,−0.12,0) m/s(0.04,-0.12,0)\,\mathrm{m/s}。练习三:从单位四元数出发,以1 rad/s\mathrm{rad/s}偏航积分0.1 ss,写出增量四元数并转换到矩阵;应得q=(cos⁡0.05,0,0,sin⁡0.05)Tq=(\cos0.05,0,0,\sin0.05)^T,矩阵偏航0.1 rad。三题都先手算再写断言,而不是拿绘图“看起来正确”作为判据。

TB01-S1 · Thor I. Fossen:MSS Rzyx.m

精读路线:逐项对照ZYX矩阵,再以零角和90度偏航检验列向量方向;本课其余推导由基变换和刚体求导展开。

原始C++逐行阅读:ArduSub 4.1.1怎样填旋转矩阵

下面是官方 Matrix3<T>::from_euler 中实际存在的三行,不是教学伪代码。来源:ArduPilot,ArduSub-4.1.1,固定提交 66c674c1927d5d31401e6b4bc48b8eb3ee7e066e;原文件第26—43行。版权 Andrew Tridgell,2012;以下原文片段依 GNU GPL v3-or-later 提供,许可证。

    c.x = -sp;
    c.y = sr * cp;
    c.z = cr * cp;

函数开头将 sp、cp 定义为俯仰的正弦和余弦,将 sr、cr 定义为横滚的正弦和余弦;成员 c 是第三行。因此这三行就是 [−sin⁡θ,sin⁡ϕcos⁡θ,cos⁡ϕcos⁡θ][-\sin\theta,\sin\phi\cos\theta,\cos\phi\cos\theta]。第一行的负号与“机首抬起时,机体前轴在NED下向的分量为负”一致。第二行与第三行分别描述机体右轴和下轴在导航下向的投影。将横滚、俯仰都设零,第三行变成 (0,0,1)(0,0,1);只给三十度俯仰,第三行变成 (−0.5,0,3/2)(-0.5,0,\sqrt3/2)。

读完整函数时,逐项把 a.x、a.y、a.z 对应教材第一行,把 b 对应第二行,把 c 对应第三行。接着看同文件的 to_euler:它用第三行第一列恢复俯仰,用第三行第二、第三列恢复横滚,用第二行第一列与第一行第一列恢复偏航。正反转换使用的是同一约定。项目DVL安装轴交换属于进入这套姿态关系之前的传感器外参,不应通过修改这九个通用元素来修正某一台传感器安装。

零基础停步自检

若姿态不变、杆臂为零,传感器与参考点速度还需要杆臂补偿吗?

展开答案与原因

不需要。ωb×ℓb=0\omega^b\times\ell^b=0;坐标变换仍可能需要,但不能把换坐标误称为杆臂补偿。

本章编程练习

查看全部练习

仅保存在当前浏览器,可在学习记录页导出。