=1 ,我们就可以用两个参数表示出旋转轴,总共只需要三个参数,跟欧拉角一样多。旋转向量我们可以用θ=θe 表示,其中 e 是单位向量。顺便提一句,这里的旋转轴我们称为欧拉轴(Euler axis),这里的旋转向量我们称为欧拉向量(Euler vector)。从矩阵角度考虑这个东西的存在也是可以的,矩阵中有个相似矩阵和特征向量的概念,大家可以理解这个旋转轴就是欧拉角旋转矩阵的特征向量,这个旋转轴的旋转角度就是该特征向量的特征值。
那么四元数是什么呢?
四元数是复数,更具体地说四元数是存在三个虚部的复数。q=w+ix+jy+kz,其中i,j,k是虚数单位,满足 i2=j2=k^2 = -1,且 i⋅j=k,j⋅i=k 。
q1+q2=(w1+w2)+i(x1+x2)+j(y1+y2)+k(z1+z2)=[(w1+22),(v1+v2)]q1⋅q2=(w1w2−x1x2−y1y2−z1z2)+i(w1x2+x1w2+y1z2−z1y2)+j(w1y2−x1z2+y1w2+z1x2)+k(w1z2+x1y2−yzx2+z1w2)
将四元数用于计算轴角表示运算时,我们通常写成向量形式(vector representation) ,q=[w,v]=⎣⎢⎡w,⎝⎛xyz⎠⎞⎦⎥⎤,为了表达清晰和计算方便,我们将w,x,y,z的取值定位w2+x2+y2+z2=1 ,并称之为单位四元数,在方向计算时单位四元数中w,x,y,z分饰的角色我们后面会解释。此时,复数乘法可表示为向量形式
q1⋅q2=[w1,v1]⋅[w2,v2]=[w1w2−v1v2,v1×v2+w1⋅v2+w2⋅v1]
或者我们也可以写成矩阵的形式
q1q2=⎣⎢⎢⎢⎡w1x1y1z1−x1w1z1−y1−y1−z1w1x1−z1y1−x1w1⎦⎥⎥⎥⎤⎣⎢⎢⎢⎡w2x2y2z2⎦⎥⎥⎥⎤
观察此式,我们发现两个四元数相乘,需要存储8个单位的数据,也就是说,每个参与运算的四元数只要存储4个单位数据即可。此外还需要几个特殊的性质:
- 四元数模∣∣q∣∣=w2+x2+y2+z2
- 四元数共轭q∗=(w+ix+jy+kz)∗=w−ix−jy−kz
- 共轭的向量形式q∗=([wv])∗=[w−v]
- 四元数的倒数:q⋅q−1=q−1⋅q=1
- 共轭与倒数的关系:q−1=w2+x2+y2+z2q∗,对于单位四元数q∗=q−1
- 四元数运算同时满足结合律和分配律,不符合交换律
了解了上面的计算法则,我们就可以利用四元数来计算方向变换过程了。还记得我们之前说过计算时四元数我们用向量形式表示,且保证它是单位四元数吗?其实四元数的向量形式我们还可以进一步改写为极形式(polar representation),q=∥q∥[cosθ,n⋅sinθ]
其中 ‖q‖ 代表了四元数的模,单位四元数模为1,而 θ 是四元数表示的旋转过程的半角大小,也就是说(2θ) 就是旋转角大小, n 则是表示旋转轴方向的单位向量。用这种表示方法,四元数即可表示任意轴角表达的方向变换。
先将原向量坐标表示为四元数p=[0,v] ,将旋转角度及旋转轴表示为单位四元数 q ,旋转后的向量坐标可通过r=q⋅p⋅q∗ 或r=q⋅p⋅q−1 计算得出
为什么引入四元数
其实四元数就是为了更好地表示旋转轴和旋转角度而已,旋转轴是个三维向量,加上旋转角度就变成四维了。而选择四元数来表示是因为它的一些特性。
先说结论,四元数的引用是为了减少计算量和计算时存储占用的空间。
但是,如果你足够细心,一定可以发现两个四元数相乘的过程其实是一个4×4矩阵与一个4×1矩阵相乘的过程,而四元数计算一次变换需要两次这个过程,其中包括24次加法运算和32次乘法运算,反观欧拉角的矩阵变换只要进行一次3×3矩阵和3×1矩阵的乘法运算,其中包括6次加法运算和9次乘法运算,运算量明显是四元数更大一些。如果你再细心一些可以发现,四元数运算时虽然有个4×4矩阵参与运算,但是矩阵中的每一项都是已经存储过的单位数据,而参与欧拉角运算的3×3矩阵则要通过另外已存储的单位数据进行的16次乘法运算,4次加法运算以及4次符号改变运算来求出,不过即使加上这些运算过程,矩阵运算也只要25次乘法运算,10次加法运算以及4次符号改变运算,运算量上来说,欧拉角的矩阵运算依然比四元数运算要有优势。但事实上,我们一般遇到的运动学问题很少会有只做一次方向转换的情况出现,对于复杂的系统和机器人来说,我们往往会面对数量庞大的转变方向过程。这种情况下四元数的优势就体现出来了,我们考虑多次变换的四元数运算(利用上面极坐标形式):
R=R1R2...Rn−1Rn=(qn(qn−1...(q2(q1pq1∗)q2∗)...qn−1∗)qn∗)
利用结合律:
R=R1R2...Rn−1Rn=(qnqn−1...q2q1)p(q1∗q2∗...qn−1∗qn∗)
考虑四元数的共轭(qaqb)∗=qb∗qa∗
R=R1R2...Rn−1Rn=(qnqn−1...q2q1)p(qnqn−1...q2q1)∗
可以发现,原向量 ppp 左右两侧括号里的运算结果是一对共轭四元数,也就是说可以利用3次易号运算代替n次四元数相乘运算,大大减少了计算量。
最后稍微提一嘴,很多接触这个问题的人都是游戏开发者,可能会有疑问,为什么在Unity的Inspector中没有这个问题,这个大家可以去试试,Unity的Inspector中Y轴不是物体自身坐标轴旋转,所以万向锁就被解了,具体Unity内部的旋转是怎么回事可以看下一篇博客,这里挖个坑
参考文章:
欧拉角 - 维基百科
如何通俗地解释欧拉角?之后为何要引入四元数?
0%