对四元数旋转方法的一个更直观说明

听说现在搞空间控制都得学四元数,于是找了几篇文章看了看,但是一直二蒙二蒙的,前几天看到了《Understanding Quaternions 理解四元数》http://www.qiujiawei.com/understanding-quaternions/  这篇文章,茅塞顿开,自己拿纸笔画了画,终于搞明白了。搞明白了以后,我觉得其实还可以写得再直观一点,再简洁一点,所以我决定写一篇博客试着挑战一下,一来巩固自己的理解,二来试一试用新学的LaTex写公式。

四元数的发明者的历史什么的就不多说了,相信大家都看了很多了,我们还是聚焦于四元数本身吧。不过呢,说到四元数,还不得不先从复数说起。我们都知道复数,或者说虚数单位“i”这个东西的来历,是因为实在在已知的数轴上找不到一个数来对应\sqrt{-1}这个东西了,这个问题困扰了思想质朴的古代数学学们几千年,特别是在解方程的时候,二次方程判别式\Delta小于0时就无解,这还罢了,到了三次方程,好不容易鼓捣出了通用求根公式,却发现经常会遇到开负数平方的情况,如果还像二次方程那样认为它无解吧,又偏偏很多情况下实际上是有实解的,现在我们知道,很多情况下求根公式中间过程中会产生一对共轭复根,最后它们的虚部会抵消掉,但是那时的数学家虽然已经知道偷偷摸摸的加入这么一个中间变量,但还是不能接受这也是一种数的概念,只能自欺欺人的说这只不过是个无意义的临时变量,没有实际意义,所以叫“虚数”。最后终于有那么位比较离经叛道的某人不管三七二十一地说“我觉得不要偷偷摸摸拐弯抹角的用他又不承认他,应该给他个名分”。这个做法真是石破天惊,一下子打开了一扇通往一 个神秘新世界的大门。

现在i终于有了个名分了,可是,实数可以用数轴上的一个点来表示,那虚数怎么办呢?数轴上,或者严格说实轴上可是没有他的位子的。也不知道是哪位先贤,某天在纸上画了一条线,这个是大家都知道的实轴,当他想画一个复数时,他的眼光停留在了数轴上下方广阔的空白空间上,突然想到了既然可以用平面直角座标系来表示一个二元函数x,y的关系,为什么不用来表示复数中的实部和虚部这一对二元关系呢?于是用平面直角座标系来表示复数的方法诞生了,复数从此与平面空间联系了起来,人们逐渐发现用复数来表示二维平面的关系有非常大的便利,因此复数的使用越来越广,复变成为一种重要的数学分支。

这里我们不讲太多复变函数方面的东西,只关注一下复数与二维平面的关系。一个实数,比如1吧,乘以i ,就变成了一个纯虚数 i ,从复平面图上来看,就是从实轴上跳到了虚轴上,再乘以一个 ii×i=-1,又跳到了负实轴上,接着乘下去,就会一直绕着原点逆时针转圈圈,所以可以看出每乘一次 i,就是逆时钟转 \pi/2。那么如果乘 -i 呢,就是顺时针转(注意这个结论)。那么是不是任意一个复数乘 i都是转\pi/2呢?结论大家其实都知道,只是我这里还是要用一个比较特别的思路说一下。

假设一个复数z=a+bi,我们可以把它拆开来,看作是两个相互垂直的矢量a\cdot\vec{r}和矢量b\cdot\vec{i}的和,这里\vec{r}是实轴方向的单位矢量,\vec{i}是虚轴方向的单位矢量,a ,b是实系数,代表矢量的长度。一个复数就可以看作是这么两个矢量的矢量和。那么将这个z去乘i , 也可以看作是将两个分量 a\cdot\vec{r}b\cdot\vec{i}分别去乘 i再加起来。此时  a\cdot\vec{r}变成了 a\cdot\vec{i}},旋转了\pi/2b\cdot\vec{i}变成了 b\cdot-\vec{r},也旋转了\pi/2,它们之间的相对位置和大小都没有变,只是整体旋转了\pi/2,因此他们的合矢量当然也就旋转了\pi/2,其它都没有变。所以我们可以得到结论,任意复数 z=\vec{z},它乘以 i都是逆时针旋转\pi/2

为什么要这样解释这个\pi/2的转动呢?因为这样比较好理解如何旋转任意角度。我们可以把一个矢量的旋转过程分成两个过程,比如要把矢量 z=\vec{z}旋转 \theta角度,我们可以先把 \vec{z}旋转\pi/2,并且把它的长度缩短为 \sin\theta,这个过程相当于  z \cdot i \sin\theta,然后,再将原来的矢量缩短为\cos\theta倍大小,并加上这个旋转并缩小过后的矢量,也就是 z\cdot \cos\theta + z\cdot i \sin\theta, 最终的结果就是将z旋转了\theta角度。而

 z\cdot \cos\theta + z\cdot i \sin\theta = z \cdot(\cos\theta + i \sin\theta),所以旋转 \theta角度就相当于乘以一个复数\cos\theta + i \sin\theta 。  

                                                             

                                              

        好了,说了这么多,总算把复数的有关知识复习完了,之所以先说这些,是因为四元数的思想,其实和这个是相同的。接下来我们正式开始四元数的介绍。

自从发现了复数可以表示二维平面后,很多人就在想三维空间能不能也用一种复数来表示,能不能也有像二维复数这样方便的表示旋转、拉申等操作的方法。一个很自然的想法是把复数空间简单的扩展成三维的,比如在实轴、虚轴  i之外,再扩展一个与这两个轴正交的轴 j轴,顺便说一下,这个j轴的正方向如果朝背离我们的方向而去,就是一个左手系,如果朝着我们的方向就是一个右手系。两种定义都有人用,我们从小学习的数学书上一般都是左手系,而上面引的那篇文章用的是右手系。我个人习惯还是倾向左手系。

                                                      

 

好了,我们现在得到了一个三维空间,有三个轴,分别是实轴、i轴 和 j轴。等会我们就会发现这种定义并不好。 在二维复数里实数乘以 i ,可以认为从实轴向虚轴转动了\pi/2,再乘一次,就又转\pi/2,转到了负方向上去。那么现在多了一个轴,从实轴转也就多了一个转动方向,可以转到i轴 ,也可以转到 j轴,(其实现在是多了无数个转动方向,可以转到 i,j平面上的任意一个方向上,这里我们只考虑两个相互正交的方向,即i轴方向 和 j轴方向),那么乘 i 就是向i轴转动\pi/2,乘 j就是向j轴转\pi/2,乘一次转\pi/2,乘两次就转到原来的对面去了。根据这个可以写出下面两个式子:

i\cdot i =-1          ,           j\cdot j =-1

现在有了两个方向的转动,可是三维空间,有三个方向的转动,还有一 个方向是从j轴到 i轴的转动,就用 k来表示这个转动吧。通过这个定义又可以写出两 个式子:

j\cdot k=i , \qquad i\cdot k=-j

根据以上这些式子,我们可以进一步推导出以下的式子:

\\i\cdot j\cdot k=i\cdot(j\cdot k)=i\cdot i=-1 \\ j\cdot k\cdot k=i\cdot k=-j\qquad \Rightarrow k\cdot k=-1

于是我们得到了四元数的基本运算规则:

i\cdot i=j\cdot j=k\cdot k=i\cdot j\cdot k=-1

在这个基本规则上还可以推导出以下的规则

\\i\cdot j=k , \qquad j\cdot i=-k\\ j\cdot k=i , \qquad k\cdot j=-i\\ k\cdot i=j , \qquad i\cdot k=-j

我们发现这个运算和顺序是有关系的,是不满足交换率的,如果顺序交换了,就要变符号。

好了,这就是直接从二维复数推广到三维空间的情况了。在这种座标定义下,绕着 j轴旋转是乘 i,绕 i轴旋转是乘 j,而绕实轴旋转是乘 k,一个在这个座标系下的矢量的座标是a + b i + c j, k是看不到的。这种情况看着是不是很别扭?实际上在做运算的时候其含义也很不好解释。总之这种直接从二维复数推广的方式很不直观方便,在看完本文后大家可以自己试试,看是不是比下面的定义要麻烦多了。既然三维空间里有三个方向的旋转,需要定义三个虚数i,j,k,那何不就把三个轴定义为 i轴,j轴和 k轴,把绕 i轴旋转定义为乘 i,绕 j轴旋转定义为乘 j,绕 k轴旋转定义为乘 k呢?这样就得到了以下的座标系定义,以及他们的转换关系,这里转动的正方向是从转动轴正方向往负方向看的逆时针方向:

\\k\cdot i =j ,\qquad j\cdot i=-k\\ i\cdot j=k , \qquad k\cdot j=-i\\ j\cdot k=i ,\qquad i\cdot k=-j

根据这几个旋转关系,通过推导,我们同样能得到 i\cdot i=j\cdot j=k\cdot k=i\cdot j\cdot k=-1这个基本关系以及其它的推论。在这种座标系定义下,一个矢量的座标表示就变成了q=a\ i+b\ j+c\ k,如果以矢量形式来写就是  \vec{q}=a \vec{i}+b\vec{j}+c\vec{k}\vec{i},\vec{j},\vec{k}来代表三个方向的单位矢量。

现在开始研究一下在这个座标系下,两个四元数的乘法代表什么意义。我们先从简单的情况一点一点的开始。先只考虑没有实部的四元数,称为纯四元数的乘法。我们假设一个在 j-k 平面上的纯四元数 q_1= a\ j+b\ k,以及一个长度为1,方向为 i轴方向的纯四元数 q_2=i,显然,q_1q_2是垂直的。现在计算q_1×q_2的结果:为了区分四元数乘法和普通乘法,以后用\otimes来代表四元数乘法。

q_1\otimes q_2 =(a j+ b k)\times i = -a\ k +b\ j

a j分量绕 i轴逆时针旋转了\pi/2变成了-a\ k, b k分量绕 i轴逆时针旋转了\pi/2变成了bj,结果是q_1整体绕着 q_2向逆时针方向转了\pi/2了。如果换一个角度看,其实也可以看作是q_2 绕着 q_1顺时针方向转了\pi/2

如果再交换一下q_1q_2的顺序,结果就变成了:

q_2\otimes q_1 =i\times (a j+ b k) = a\ k -b\ j

变到和刚才相反的方向上去了。同样,这可以有两种解释,一种可解释为q_2 绕着 q_1逆时针方向转了\pi/2,也可以解释为 q_1绕着 q_2顺时针方向转了\pi/2

通过这个简单的例子我们可以知道,这两个比较特殊的互相垂直纯四元数相乘,可以看作是前面那个数绕着后面那个数逆时针旋转了\pi/2,也可以认为是后面那个数绕前面那个数顺时针旋转了\pi/2。那么是不是任何相互垂直的纯四元数相乘都是这样的?结论是肯定的。我们可以写出任意两个垂直的纯四元数 q_1=a i +b j +c kq_2=Ai+Bj+Ck, 并且假设q_1\perp q_2 ,则

q_1 \otimes q_2 &=(a i +b j +c k)(A i +B j +C k)\\ &=-(aA+bB+cC)+[(bC-cB)i+(cA-aC)j+(aB-bA)k ]\\ &=-\vec{q_1}\cdot\vec{q_2}+\vec{q_1}\times\vec{q_2}

我们看到实际上两个纯四元数的乘法结果,它可能会出现一个实数部分,而这个实数部分的值,就是两个纯四元数矢量的点积乘-1,而它的虚部则是它们的叉积。因为我们已经假设了q_1\perp q_2,所以\vec{q_1}\cdot\vec{q_2}=0 ,所以结果仍然是一个纯四元数,此时的虚部的值是\vec{q_1}\times\vec{q_2},正好就是 q_1绕着 q_2向逆时针方向转了\pi/2,或者说q_2 绕着 q_1顺时针方向转了\pi/2。如果 \left | q_1 \right |\left | q_2 \right |都为1,则结果的长度也是1。如果 \left | q_1 \right |\left | q_2 \right |的长度不为1,则结果的长度就是\left | q_1 \right |\times\left | q_2\right |

现在我们知道了两个互相垂直的纯四元数,它们的积仍然是一个纯四元数,并且是第一个数绕第二个数逆时针旋转了\pi/2。那么如果我们想让它旋转另外一个角度 \theta呢?其实也可以按前面所说的二维复数的旋转方法来实现。我们假设要把一个四元数q_1= a\ \vec{q}绕 \vec{n}旋转 \theta角度,这里 \vec{q}是表示 q_1的方向的单位向量 ,\vec{n}则是一个与  \vec{q}垂直的单位向量。同样,把这个旋转过程分为两步:第一步先把 q_1旋转π/2,并且把它的长度缩短为 sin\theta,这个过程相当于  q_1\otimes \vec{n} \sin\theta,然后,再将原来的矢量q_1缩短为\cos\theta倍大小,并加上这个旋转并缩小过后的矢量,也就是 q_1\cdot \cos\theta + q_1\otimes \vec{n}\sin\theta, 最终的结果就是将q_1旋转了\theta角度。而

 q_1\cdot \cos\theta + q1\otimes \vec{n}\sin\theta=q_1\otimes(\cos\theta+\vec{n}\sin\theta)=q_1\otimes q_2

所以旋转 \theta角度就相当于乘以一个四元数 q_2=\cos\theta+\vec{n}\sin\theta ,这个形式和二维复数的形式“\cos\theta + i \sin\theta ”是一样的。现在我们终于理解为什么说四元数的乘法是一个转动了。如果把两个数乘法的顺序反过来,结果是什么样子的呢?

q_2\otimes q_1\\&=(\cos\theta+\vec{n}\sin\theta)\otimes q_1\\&=\vec{q_1}\cos\theta+\vec{n}\times \vec{q_1}\sin\theta\\ &=\vec{q_1}\cos\theta-\vec{q_1}\times\vec{n}\sin\theta\\ &=\vec{q_1}\cos (-\theta)+\vec{q_1}\times \vec{n}\sin (-\theta)\\ &=q_1\otimes[\cos(-\theta)+\vec{n}\sin (-\theta)]

可见如果交换了顺序,就相当于把q_1向相反的方向转了 \theta角度。

另外如果我们先乘一个q_2=\cos\theta+\vec{n}\sin\theta,正转\theta角度,再乘一个q_2^*=\cos(-\theta)+\vec{n}\sin(-\theta)=\cos\theta-\vec{n}\sin\theta,反转\theta角度,显然就又转回来了,等于没有转动,于是可知

q_1\otimes q_2\otimes q_2^*= q_1\\ \Rightarrow q_2\otimes q_2^*=1

此时称 q_2和 q_2^*为共轭,和二维复数的定义很类似。根据以上推导可知,一个纯四元数q_1和一个转动四元数q_2,当它们的虚部垂直时,可得到以下的结果:

q_1\otimes q_2 = q_2^*\otimes q_1

 

另外再说一下,当q_1、 q_2 是纯四元数时,我们可以说q_1\otimes q_2 是q_1绕着 q_2逆时针转\pi/2,也可以说是q_2绕着 q_1顺时针转\pi/2,但当q_2带有实部,不再是一个纯四元数时,就不好再说q_2怎么绕着 q_1转了。

接下来要进入四元数最麻烦的地方了。向量与旋转轴垂直的情况已经知道了,那如果不垂直呢?我们还是先从简单的例子开始。我们设一个纯四元数 q_1需要绕着 单位向量 \vec{n}旋转\pi/2,但 q_1并不与 \vec{n}完全垂直。我们可以把q_1 分解成两个向量的和,一个向量是 q_1 在与 \vec{n}垂直的平面上的投影 a\cdot \vec{p},另一个分量 b\cdot\vec{n}与 \vec{n}平行,即令 q_1=a\cdot\vec{p}+b\cdot\vec{n},那么根据前面的两个纯四元数乘积的结果的结论,会产生一个实部和一个虚部,实部的值是负的两个数的点积,虚部是两个数的叉积,则

q_1\otimes q_2\\ =(a \cdot \vec{p}+b\cdot \vec{n})\otimes \vec{n}\\ =a( \vec{p}\otimes \vec{n})+b(\vec{n}\otimes \vec{n})\\ =a (-\vec{p}\cdot \vec{n}+\vec{p}\times\vec{n})+ b( -\vec{n}\cdot\vec{n}+\vec{n}\times\vec{n})\\ =a\cdot (\vec{p}\times\vec{n} )- b

这里利用到了\vec{p}\perp \vec{n}所以\vec{p}\cdot\vec{n}=0 ,\qquad \vec{n}\times\vec{n}=0 , \qquad \vec{n}\cdot\vec{n}=1这几个关系。

上面的结果可见,垂直于旋转轴的分量老老实实的转过了\pi/2,而平行于旋转轴的分量则从这个空间跑了,跑到了一个神秘空间,也就是实轴上去了。如果我们把这个结果继续再乘一个q_2呢,结果是

q_1\otimes q_2\otimes q_2 \\ =[a\cdot (\vec{p}\times\vec{n} )- b]\otimes \vec{n}\\ =-a\cdot\vec{p}-b\cdot\vec{n}\\ =-q_1

又把b\cdot\vec{n}给转出来了,只不过转到对面去了,而且是整个 q_1转到了相对原点对称的地方去了。

如果不是想转\pi/2,而是想转\theta角度,还是让q_2=\cos\theta+\vec{n}\sin\theta,现在

q_1\otimes q_2 \\ =(a \cdot \vec{p}+b\cdot \vec{n})\otimes q_2\\ =a( \vec{p}\otimes q_2)+b(\vec{n}\otimes q_2) \\ =a( \vec{p}\otimes q_2)+b(\vec{n}\otimes (\cos\theta +\vec{n}\sin\theta )) \\ =a (\vec{p}\otimes q_2)+ b( \vec{n}\cos\theta-\sin\theta)

这个结果可以看作是将垂直旋转轴方向的分量转了\theta角度,然后还加上了一个平行于旋转轴的分量,最后还有一部分跑到了实轴上,真是够复杂的。看到这个结果脑袋有点大,这可不是我们期望的结果,我们期望的结果是垂直旋转轴​​​​​​​方向的分量转\theta角度,而平行旋转轴方向的分量不变,也就是希望得到a (\vec{p}\otimes q_2)+ b\vec{n},现在这个结果可真够乱的。

不管怎样,我们硬着头皮仔细看看这个结果。前一个部分a \vec{p}\otimes q_2是垂直于\vec{n}}​​​​​​​的纯四元数,主要看后面这个部分的结果,b(\vec{n}\cos\theta-\sin\theta)=b(\vec{n}\otimes q_2),注意到有\vec{n}\otimes\vec{n}=-1这个关系,这个式子可以变为:

b(\vec{n}\cos\theta-\sin\theta)\\ =b(\vec{n}\cos\theta+\vec{n}\otimes\vec{n}\sin\theta)\\ =b\vec{n}\otimes(\cos\theta+\vec{n}\sin\theta) =(\cos\theta+\vec{n}\sin\theta)\otimes b\vec{n}\\ =b\cdot \vec{n}\otimes q_2 = b \cdot q_2\otimes\vec{n}

我们发现\vec{n}\otimes q_2 = q_2\otimes \vec{n},是可交换顺序的,而且只要去乘一个q_2^*=\cos\theta-\vec{n}\sin\theta,就能把 b\vec{n}变回来,并且左乘、右乘都可以。可是如果是右乘q_2^*的话,实际上因为q_2\otimes q_2^*=1,q_1\otimes q_2\otimes q_2^*= q_1,就是又转回去了,这很无聊。所以我们试试左乘吧。

q_2^*\otimes (q_1\otimes q_2)\\ =q_2^*\otimes(a\cdot \vec{p}\otimes q_2 + b\cdot \vec{n}\otimes q_2)\\ =a\cdot q_2^*\otimes \vec{p}\otimes q_2 + b\cdot q_2^*\otimes\vec{n}\otimes q_2\\

首先看后面一项,因为\vec{n}\otimes q_2 = q_2\otimes \vec{n},所以这一项可变为

b\cdot q_2^*\otimes\vec{n}\otimes q_2\\=b\cdot q_2^*\otimes q_2 \otimes \vec{n}\\ =b\cdot\vec{n}

很好,把 b\vec{n}变回来了。然后看第一项。根据前面的推导结果,当一个纯四元数q_1和一个转动四元数q_2,当它们的虚部垂直时,q_1\otimes q_2 = q_2^*\otimes q_1,因此这里:

a\cdot q_2^*\otimes \vec{p}\otimes q_2 \\ =a\cdot \vec{p} \otimes (q_2^*)^* \otimes q_2\\ =a\cdot\vec{p}\otimes q_2\otimes q_2

这相当于把 \vec{p}绕着q_2转了两次,也就是转了两个\theta角度。最后我们把整个结果写下来:

q_2^* \otimes q_1\otimes q_2\\ =q_2^*\otimes(a \vec{p}+b\vec{n})\otimes q_2\\ =q_2^*\otimes a\vec{p}\otimes q_2+ q_2^*\otimes b\vec{n}\otimes q_2\\ =a\vec{p}\otimes q_2\otimes q_2+b\vec{n}\\ =a\vec{p}\otimes q_2^2+b\vec{n}

这个结果就是q_1 整体的绕 q_2转了2\theta角度。看到这大家是不是眼睛一亮。虽然转过的角度变成了2\theta,不是我们希望的\theta,但是聪明的你一定马上就想到了办法,把q_2变成转 \theta/2不就行了?于是,想要让纯四元数 q_1 围绕一个轴\vec{n}转动\theta角的四元数乘法就变成了:

q_2^*\otimes q_1\otimes q_2 \\q_2=\cos \tfrac{\theta}{2} + \vec{n} \sin\tfrac{\theta}{2} \\ q_2^*=\cos \tfrac{\theta}{2} - \vec{n} \sin\tfrac{\theta}{2}

现在我们终于明白了四元数旋转为什么要用两次乘法了。这篇文章也不打算说更多的东西,其实大部分人也就只利用它来做旋转,了解这些就够了。至于插值等功能,了解了这些基本原理方法后,也很容易推导出来,相关文章很多,就不继续写了。其实继续推导下去还可以得到很多有趣的东西,比如四元数函数、四元数插值等等,甚至还有四元数微分等等,有兴趣的同学可以继续深挖下去,祝大家转得快乐。

最后说一下,本来是想配一些图的,听说现在画图都用MatPlotLib,于是学了一下,可是折腾了两天也没搞明白,画不出理想的图来,暂时就算了吧。以后等我搞懂了MatPlotLib再来把图补上吧。

20201206 今天终于下决心把图给补上了,最后用的是mathematica的绘图功能。开始本来是想把符号标注什么的都用软件生成,后来发现太麻烦了,所以只画了矢量图,符号是用windows画图手标上去的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值