网站首页 > 博客文章 正文
技术背景
在前面几篇跟SETTLE约束算法相关的文章(1, 2, 3)中,都涉及到了大量的向量旋转的问题--通过一个旋转矩阵,给定三个空间上的欧拉角α,β,γα,β,γ,将指定的向量绕对应轴进行旋转操作。而本文主要就阐述这些旋转操作中,有可能面临到的一个重要问题--万向节死锁问题(Gimbal Lock)。
一般大家觉得用图像化的方式来展示问题会显得更加的直观,但是这里我们准备直接用公式来陈述一下这个问题,也许会更直接。首先我们知道几个熟悉的旋转矩阵:
RY(α)=???cosα0?sinα010sinα0cosα???RX(β)=???1000cosβsinβ0?sinβcosβ???RZ(γ)=???cosγsinγ0?sinγcosγ0001???RY(α)=(cosα0sinα010?sinα0cosα)RX(β)=(1000cosβ?sinβ0sinβcosβ)RZ(γ)=(cosγ?sinγ0sinγcosγ0001)
这些旋转矩阵分别表示绕Y,X,ZY,X,Z轴旋转指定的角度的操作。如果我们将这些旋转操作按照顺序作用在一个向量上,由于矩阵运算的结合律,我们可以得到这样一个等效的操作矩阵:
R(α,β,γ)=RY(α)RX(β)RZ(γ)=???cosα cosγ+sinα sinβ sinγcosβ sinγ?sinα cosγ+cosα sinβ sinγ?cosα sinγ+sinα sinβ cosγcosβ cosγsinα sinγ+cosα sinβ cosγ+sinα cosβ?sinβcosα cosβ???R(α,β,γ)=RY(α)RX(β)RZ(γ)=(cosα cosγ+sinα sinβ sinγ?cosα sinγ+sinα sinβ cosγ+sinα cosβcosβ sinγcosβ cosγ?sinβ?sinα cosγ+cosα sinβ sinγsinα sinγ+cosα sinβ cosγcosα cosβ)
为了简化写法,我们可以定义:
c1=cosα=cos(Y),s1=sinα=sin(Y)c2=cosβ=cos(X),s2=sinβ=sin(X)c3=cosγ=cos(Z),s3=sinγ=sin(Z)c1=cosα=cos(Y),s1=sinα=sin(Y)c2=cosβ=cos(X),s2=sinβ=sin(X)c3=cosγ=cos(Z),s3=sinγ=sin(Z)
那么就有:
R(α,β,γ)=???c1c3+s1s2s3c2s3?s1c3+c1s2s3?c1s3+s1s2c3c2c3s1s3+c1s2c3+s1c2?s2c1c2???R(α,β,γ)=(c1c3+s1s2s3?c1s3+s1s2c3+s1c2c2s3c2c3?s2?s1c3+c1s2s3s1s3+c1s2c3c1c2)
其实按照不同的顺序进行旋转的话,得到的结果会有6种可能性:RXRYRZ,RXRZRY,RYRXRZ,RYRZRX,RZRXRY,RZRYRXRXRYRZ,RXRZRY,RYRXRZ,RYRZRX,RZRXRY,RZRYRX,但是这里一般人为的规定使用RYRXRZRYRXRZ顺规,也就是先绕ZZ轴旋转,再绕XX轴旋转,最后再绕YY轴旋转的顺序。
如果这里假定β=π2β=π2,也就是绕XX轴旋转的角度是90度,那么得到的新的旋转矩阵为:
R(α,π2,γ)=RY(α)RX(π2)RZ(γ)=???c1c3+s1s30?s1c3+c1s3?c1s3+s1c30s1s3+c1c30?10???R(α,π2,γ)=RY(α)RX(π2)RZ(γ)=(c1c3+s1s3?c1s3+s1c3000?1?s1c3+c1s3s1s3+c1c30)
再回顾下三角函数公式:
sin(a±b)=sin(a)cos(b)±sin(b)cos(a)cos(a±b)=cos(a)cos(b)?sin(a)sin(b)sin(a±b)=sin(a)cos(b)±sin(b)cos(a)cos(a±b)=cos(a)cos(b)?sin(a)sin(b)
代入可得:
R(α,π2,γ)=???cos(α?γ)0?sin(α?γ)sin(α?γ)0cos(α?γ)0?10???R(α,π2,γ)=(cos(α?γ)sin(α?γ)000?1?sin(α?γ)cos(α?γ)0)
类似地:
R(α,?π2,γ)=???cos(α+γ)0?sin(α+γ)?sin(α+γ)0?cos(α+γ)010???R(α,?π2,γ)=(cos(α+γ)?sin(α+γ)0001?sin(α+γ)?cos(α+γ)0)
到这里,端倪初现,按照上面的这个公式,改变αα和改变γγ的值,得到的效果是一样的。换句话说,如果在一个欧拉角的旋转矩阵中,在XX轴的方向将其旋转了90度之后,接下来不论是绕YY轴旋转,还是绕ZZ轴旋转,得到的效果是一样的。那么,本来应该是三个方向的自由度,现在变成了两个,这就是问题所在。
SETTLE约束算法的局限性
这里我们先回顾一下SETTLE算法中的一个环节,这个环节中涉及到了旋转矩阵的使用。首先是给定一个三角形Δa0b0c0Δa0b0c0:
然后将其按照这样的一个顺序进行旋转操作:
旋转之后可以得到新的三角形Δa3b3c3Δa3b3c3。按照SETTLE: An Analytical Version of the SHAKE and RATTLE Algorithm for Rigid Water Models这篇文章的推导,我们可以得到所需的三个旋转的欧拉角的计算公式为(这里有一个需要注意的问题,SETTLE文章里面的α,β,γα,β,γ三个参数跟我们前面提到的旋转欧拉角的意义不同,在这篇文章中分别用ψ,?,θψ,?,θ来表示绕Y,X,ZY,X,Z轴的旋转):
?ψθ=arcsin(Z′a3ra)=arcsin(Z′b3?Z′c32rccos?)=arcsin(γα2+β2??????√)?arctan(βα)?=arcsin(Za3′ra)ψ=arcsin(Zb3′?Zc3′2rccos?)θ=arcsin(γα2+β2)?arctan(βα)
其中αα、ββ和γγ的取值如下:
αβγ=?rccosψ(X′b0?X′c0)+(?rbcos??rcsinψsin?)(Y′b0?Y′a0)+(?rbcos?+rcsinψsin?)(Y′c0?Y′a0)=?rccosψ(Y′c0?Y′b0)+(?rbcos??rcsinψsin?)(X′b0?X′a0)+(?rbcos?+rcsinψsin?)(X′c0?X′a0)=Y′b1(X′b0?X′a0)?X′b1(Y′b0?Y′a0)+Y′c1(X′c0?X′a0)?X′c1(Y′c0?Y′a0)α=?rccosψ(Xb0′?Xc0′)+(?rbcos??rcsinψsin?)(Yb0′?Ya0′)+(?rbcos?+rcsinψsin?)(Yc0′?Ya0′)β=?rccosψ(Yc0′?Yb0′)+(?rbcos??rcsinψsin?)(Xb0′?Xa0′)+(?rbcos?+rcsinψsin?)(Xc0′?Xa0′)γ=Yb1′(Xb0′?Xa0′)?Xb1′(Yb0′?Ya0′)+Yc1′(Xc0′?Xa0′)?Xc1′(Yc0′?Ya0′)
那么在这个计算公式中,如果我们取XX轴的旋转角度为90度,也就是:
?=±π2?=±π2
此时,由于cos?=0cos?=0,在计算ψψ的时候,就会直接出现报错,SETTLE算法无法继续执行。那么在其他类似的欧拉角求解的场景下,一样有可能出现类似的问题,导致无法正常计算欧拉角。并且,如果给定欧拉角,那么从原始的向量到终点的向量是一一对应的,但是如果给定两个向量,其对应的旋转矩阵不是唯一的。或者说,两个向量之间变换的轨迹不是唯一的。
Gimbal平衡环架中的死锁
在参考链接2中,作者自己画了一个平衡环架用于表示欧拉角死锁的问题。非常的直观,本章节中的图片都来自于参考链接2。首先我们给定一个这样的Gimbal:
其中每一个颜色的环都可以绕对应轴进行旋转,比如绕绿轴的旋转:
绕红轴的旋转:
绕蓝轴的旋转:
有了这三个轴的话,不论怎么旋转,都可以保持中间那根棍子的位置和朝向不变,达到一个稳定的效果。这个三轴稳定器已经被大量应用在航空航海领域,而后面要讲的四元数的概念,其实也是Hamilton在一次坐船的过程中提出来的一个概念。但是有这样一个特殊的场景,有可能会破坏这个稳定结构。假设我们先把红色这个圈,旋转90度到跟蓝色圈共面的位置:
那么接下来我们就会发现,原本在三个轴向的旋转下都可以保持稳定的棍子,居然摇晃起来了:
这就是有名的万向节死锁,死锁出现的时候,原本三个方向旋转的自由度,变成了两个,就失去了一个自由度。接下来我们可以看一看,有没有什么方案可以解决万向节死锁的问题。
四元数(Quaternion)的定义
应该说,四元数的出现,并不是为了解决欧拉角死锁的问题。但是在后来长期的应用中,人们发现了四元数在几何旋转表示中的独特优势。在蛋白质折叠软件AlphaFold2和MEGAProtein中都使用到了四元数,用于表征分子结构的三维旋转。关于四元数的介绍材料,可以参考一下参考链接3、4,分别是英文版和中文翻译版。
要理解四元数,至少需要了解复数,可以把四元数当做是复数的一个推广形式。一个复数是由实部和虚部组成,很多时候我们也会将其写成指数形式或者是向量形式:
z=x+i y=1x2+y2??????√ei arctan(yx)=[xy]z=x+i y=1x2+y2ei arctan(yx)=[xy]
其中x,yx,y是实数,xx称为复数zz的实部,yy称为复数zz的虚部,i2=?1i2=?1是虚数单位。正因为复数可以被看做是一个矢量,所以我们才会想到复数跟向量旋转之间的联系,比如我们有一个单位长度的复数z′=cosθ+i sinθz′=cosθ+i sinθ,那么就有以下的复数乘法关系:
z′z=(cosθ+i sinθ)(x+i y)=xcosθ+iycosθ+ixsinθ?ysinθ=[xcosθ?ysinθycosθ+xsinθ]=[cosθsinθ?sinθcosθ][xy]z′z=(cosθ+i sinθ)(x+i y)=xcosθ+iycosθ+ixsinθ?ysinθ=[xcosθ?ysinθycosθ+xsinθ]=[cosθ?sinθsinθcosθ][xy]
如此一来,我们就得到了一个二维向量的旋转矩阵:
R2(θ)=[cosθsinθ?sinθcosθ]R2(θ)=[cosθ?sinθsinθcosθ]
有了复数的概念基础,我们可以将其扩展成一个四元数:
z=x+iyi+jyj+kyk=??????xyiyjyk??????z=x+iyi+jyj+kyk=[xyiyjyk]
比较特殊的,相比于复数的定义有一些补充定义:
i2=j2=k2=ijk=?1ij=k,jk=i,ki=jji=?k,kj=?i,ik=?ji2=j2=k2=ijk=?1ij=k,jk=i,ki=jji=?k,kj=?i,ik=?j
这些关系,其实很容易让我们联想到向量的叉乘。类似于单位长度复数的定义,这里我们可以定义一个单位长度的四元数:
q=(cosα+j sinα)(cosβ+i sinβ)(cosγ+k sinγ)=(cosα cosβ cosγ+sinα sinβ sinγ)+i(cosα sinβ cosγ+sinα cosβ sinγ)+j(sinα cosβ cosγ?cosα sinβ sinγ)+k(cosα cosβ sinγ?sinα sinβ cosγ)=(c1c2c3+s1s2s3)+i(c1s2c3+s1c2s3)+j(s1c2c3?c1s2s3)+k(c1c2s3?s1s2c3)=s+ix+jy+kzq=(cosα+j sinα)(cosβ+i sinβ)(cosγ+k sinγ)=(cosα cosβ cosγ+sinα sinβ sinγ)+i(cosα sinβ cosγ+sinα cosβ sinγ)+j(sinα cosβ cosγ?cosα sinβ sinγ)+k(cosα cosβ sinγ?sinα sinβ cosγ)=(c1c2c3+s1s2s3)+i(c1s2c3+s1c2s3)+j(s1c2c3?c1s2s3)+k(c1c2s3?s1s2c3)=s+ix+jy+kz
这里我们假定:
s=c1c2c3+s1s2s3x=c1s2c3+s1c2s3y=s1c2c3?c1s2s3z=c1c2s3?s1s2c3s=c1c2c3+s1s2s3x=c1s2c3+s1c2s3y=s1c2c3?c1s2s3z=c1c2s3?s1s2c3
因为我们要使得qq是一个单位四元数,因此有:
s2+x2+y2+z2=1s2+x2+y2+z2=1
四元数与旋转矩阵
四元数与复数的旋转矩阵略有不同,给定一个单位四元数qq和一个三维空间向量(纯四元数,即s=0s=0):v=0+i vi+j vj+k vkv=0+i vi+j vj+k vk,那么向量vv关于qq的旋转被定义为:qvq?qvq?。这里q?=s?ix?jy?kzq?=s?ix?jy?kz,是qq的共轭四元数。对于一个单位四元数而言,q?=q?1q?=q?1。那么我们可以计算一下对应的旋转矩阵RqRq:
Rqv=qvq?=(s+ix+jy+kz)[vix+vjy+vkz+i(vis?vjz+vky)+j(viz+vjs?vkx)+k(?viy+vjx+vks)]=???s2+x2?y2?z22sz+2xy2xz?2sy2xy?2szs2?x2+y2?z22sx+2yz2xz+2sy2yz?2sxs2?x2?y2+z2??????vivjvk???Rqv=qvq?=(s+ix+jy+kz)[vix+vjy+vkz+i(vis?vjz+vky)+j(viz+vjs?vkx)+k(?viy+vjx+vks)]=[s2+x2?y2?z22xy?2sz2xz+2sy2sz+2xys2?x2+y2?z22yz?2sx2xz?2sy2sx+2yzs2?x2?y2+z2][vivjvk]
即,四元数所代表的旋转矩阵为:
R(α,β,γ)=???s2+x2?y2?z22sz+2xy2xz?2sy2xy?2szs2?x2+y2?z22sx+2yz2xz+2sy2yz?2sxs2?x2?y2+z2???=???cos2α cos2γ+sin2α sin2β sin2γcos2β sin2γcos2α sin2β sin2γ?sin2α cos2γsin2α sin2β cos2γ?cos2α sin2γcos2β cos2γsin2α sin2γ+cos2α sin2β cos2γsin2α cos2β?sin2βcos2α cos2β???R(α,β,γ)=[s2+x2?y2?z22xy?2sz2xz+2sy2sz+2xys2?x2+y2?z22yz?2sx2xz?2sy2sx+2yzs2?x2?y2+z2]=[cos2α cos2γ+sin2α sin2β sin2γsin2α sin2β cos2γ?cos2α sin2γsin2α cos2βcos2β sin2γcos2β cos2γ?sin2βcos2α sin2β sin2γ?sin2α cos2γsin2α sin2γ+cos2α sin2β cos2γcos2α cos2β]
可以发现这里得到的旋转矩阵跟前面的RYRXRZRYRXRZ顺规结果是一致的。但有一点不同的是,在这个结果中我们还发现了一个比较重要的变换:所有的角度在旋转矩阵中都翻了1倍。这里给了我们一个重要启示:在使用四元数对向量进行旋转时,需要先把角度除以2。
四元数Python代码实现
在Python的符号计算库Sympy中,已经支持了四元数的相关运算:
from sympy import *from sympy.algebras.quaternion import Quaternion s, x, y, z = symbols('s x y z', real=True, positive=True)a, b, g = symbols('a b g')vi, vj, vk = symbols('v_i v_j v_k')tvi, tvj, tvk = symbols('t_i, t_j, t_k') # 定义三个轴的旋转四元数qa = Quaternion(cos(a), 0, sin(a), 0)qb = Quaternion(cos(b), sin(b), 0, 0)qg = Quaternion(cos(g), 0, 0, sin(g)) # 按顺序合并旋转四元数为一个单位四元数q = qa.mul(qb.mul(qg)) print ('The unit quaternion q is: {}'.format(pretty(q)))# The quaternion q is: (sin(a)*sin(b)*sin(g) + cos(a)*cos(b)*cos(g)) + (sin(a)*sin(g)*cos(b) + sin(b)*cos(a)*cos(g))*i +# (sin(a)*cos(b)*cos(g) - sin(b)*sin(g)*cos(a))*j + (-sin(a)*sin(b)*cos(g) + sin(g)*cos(a)*cos(b))*k # 定义一个普通四元数q = Quaternion(s, x, y, z)print ('The normal quaternion q is: {}'.format(pretty(q)))# The normal quaternion q is: s + x*i + y*j + z*k # 四元数求共轭cq = conjugate(q)print ('The conjugate quaternion cq is: {}'.format(pretty(cq))) # 定义一个纯四元数v = Quaternion(0, vi, vj, vk)print ('The pure quaternion v is: {}'.format(pretty(v)))# The pure quaternion v is: 0 + v_i*i + v_j*j + v_k*k # 计算四元数的旋转qvq*tv = simplify(q.mul(v.mul(cq)))print ('Transformed pure quaternion tv is: {}'.format(pretty(tv)))# Transformed pure quaternion tv is: 0 +# (s*(s*v_i - v_j*z + v_k*y) + x*(v_i*x + v_j*y + v_k*z) + y*(s*v_k - v_i*y + v_j*x) - z*(s*v_j + v_i*z - v_k*x))*i +# (s*(s*v_j + v_i*z - v_k*x) - x*(s*v_k - v_i*y + v_j*x) + y*(v_i*x + v_j*y + v_k*z) + z*(s*v_i - v_j*z + v_k*y))*j +# (s*(s*v_k - v_i*y + v_j*x) + x*(s*v_j + v_i*z - v_k*x) - y*(s*v_i - v_j*z + v_k*y) + z*(v_i*x + v_j*y + v_k*z))*k
那么有了Sympy这样强大的四元数处理的工具,可以节省我们很多手算的时间。
四元数是否解决了Gimbal Lock问题?
在最前面的章节中,我们讲Gimbal Lock欧拉角死锁问题时,提到了一个比较重要的点:在特定条件下(如绕一个指定的轴旋转90度),两个空间向量中间可以对应无穷多个欧拉角的组合。这个现象也体现出了,用欧拉角的方式无法一一对应的表示每两个空间向量之间的旋转关系。因此我们需要找到一个新的表示方法,基于新的表示方法,不仅要使得每一组输入参数对应一个特定的旋转,还需要使得给定任意的两个空间向量,所计算得到的参数要是唯一的,这样才能构成一一对应的映射关系。我们先介绍一下从两个空间向量v1,v2v1,v2中去计算四元数的方法,再结合一些实际案例,看看是否会出现欧拉角旋转矩阵中出现的奇点。
假设两个向量之间的夹角为θθ,则对应的旋转四元数可以表示为:
u=v1×v2cosθ=v1?v2|v1||v2|q=cosθ2+i sinθ2u?i+j sinθ2u?j+k sinθ2u?ku=v1×v2cosθ=v1?v2|v1||v2|q=cosθ2+i sinθ2u?i+j sinθ2u?j+k sinθ2u?k
案例重现
那么如果我们使用前面提到的欧拉角奇点的案例,假定一个空间向量v0=iv0=i,也就是处于三维坐标系的X轴正方向上的一个单位向量,我们给它设计一个路径:先绕Z轴旋转γγ的角度,然后绕X轴旋转90度,最后再绕Y轴旋转αα的角度,那么对应的四元数为:
q=(cosα2?j sinα2)(2–√2+i2–√2)(cosγ2+k sinγ2)=2–√2[cos(α2+γ2)+i cos(α2+γ2)?j sin(α2+γ2)+k sin(α2+γ2)]q=(cosα2?j sinα2)(22+i22)(cosγ2+k sinγ2)=22[cos(α2+γ2)+i cos(α2+γ2)?j sin(α2+γ2)+k sin(α2+γ2)]
因为在四元数中我们并不关心具体每个旋转角度的值,我们只需要四元数的四个元素就可以了,所以这里令x=cos(α2+γ2),y=sin(α2+γ2)x=cos(α2+γ2),y=sin(α2+γ2),则有:
q=2–√2(x+ix?jy+ky)x2+y2=1q=22(x+ix?jy+ky)x2+y2=1
使用Hamilton Product作用在v0v0上可以得到:
v1=qv0q?=i(x2?y2)+2kxyv1=qv0q?=i(x2?y2)+2kxy
为了简化计算量,假定我们得到的结果是v1=kv1=k,在三维坐标系下,这个矢量位于ZZ轴的正方向上,也就是:
v1=qv0q?=i(x2?y2)+2kxy=kv1=qv0q?=i(x2?y2)+2kxy=k
则有对应关系:
?????x2?y2=0x2+y2=1xy=12{x2?y2=0x2+y2=1xy=12
那么得到两组解:
???x=2√2,y=2√2x=?2√2,y=?2√2{x=22,y=22x=?22,y=?22
也就是说,这个旋转过程有两个可能对应的四元数:
???q1=2√2+2√2i?2√2j+2√2kq2=?2√2?2√2i+2√2j?2√2k{q1=22+22i?22j+22kq2=?22?22i+22j?22k
而在这个计算过程中,我们依然发现,如果使用欧拉角来进行旋转的话,只能计算出α+γα+γ的值,但是法对其进行求解,而四元数则不存在这样的奇点。
案例拓展
在上面这个案例中,我们其实是已经给定了一个轨迹所对应的四元数。而如果只是知道起始点ii和终点kk,其实我们也可以用上述计算旋转四元数的方法来进行求解:
u=i×k=?jcosθ=i?k=0u=i×k=?jcosθ=i?k=0
这就可以计算得四元数:
q=cosθ2+i sinθ2u?i+j sinθ2u?j+k sinθ2u?k=2–√2?2–√2jq=cosθ2+i sinθ2u?i+j sinθ2u?j+k sinθ2u?k=22?22j
虽然这个计算过程很容易,但是我们依然可以使用sympy来验算一下:
In [1]: from sympy import * In [2]: from sympy.algebras.quaternion import Quaternion In [3]: import numpy as np In [4]: q=Quaternion(np.sqrt(2)/2,0,-np.sqrt(2)/2,0) In [5]: v=Quaternion(0,1,0,0) In [6]: q.mul(v.mul(conjugate(q)))Out[6]: 0 + 0*i + 0*j + 1.0*k
类似的,我们也可以验证一下上一个模块中提到的指定轨迹和起始点与终点所得到的旋转四元数:
In [7]: q=Quaternion(np.sqrt(2)/2,np.sqrt(2)/2,-np.sqrt(2)/2,np.sqrt(2)/2)/np.sqrt(2) In [8]: q.mul(v.mul(conjugate(q)))Out[8]: 0 + 0*i + 0*j + 1.0*k In [9]: q=-1*Quaternion(np.sqrt(2)/2,np.sqrt(2)/2,-np.sqrt(2)/2,np.sqrt(2)/2)/np.sqrt(2) In [10]: q.mul(v.mul(conjugate(q)))Out[10]: 0 + 0*i + 0*j + 1.0*k
总结概要
本文通过两个案例——旋转矩阵和分子动力学模拟中的SETTLE约束算法,介绍了一下Gimbal Lock问题,简单来说就是,用旋转矩阵去表示三维空间的向量旋转有可能会遇到奇点,使得三维空间原本的三个自由度在某一个点变成两个自由度。而使用我们这里所介绍的四元数Quaternion则不会有这样的问题,同时本文也介绍了一些四元数的基本运算法则和sympy中的代码实现。后续会再单独写三篇博客介绍一下四元数的具体运算细则、四元数在SETTLE算法中的应用以及四元数的物理含义等,敬请期待。
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/quaternion.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/
打赏专用链接:https://www.cnblogs.com/dechinphy/gallery/image/379634.html
腾讯云专栏同步:https://cloud.tencent.com/developer/column/91958
CSDN同步链接:https://blog.csdn.net/baidu_37157624?spm=1008.2028.3001.5343
51CTO同步链接:https://blog.51cto.com/u_15561675
参考链接
- https://matthew-brett.github.io/transforms3d/gimbal_lock.html
- https://blog.csdn.net/AndrewFan/article/details/60981437
- https://www.3dgep.com/understanding-quaternions/
- https://www.qiujiawei.com/understanding-quaternions/
- https://zhuanlan.zhihu.com/p/45404840#:~:text=这个四元数构造的大概思路就是把 四元数的旋转操作写成矩阵形式 (注:给定一个用于旋转的单位四元数 textbf q%3Dw%2Bx textbf i%2By textbf,p'%3D textbf q textbf p textbf q^-1 )。
- https://blog.csdn.net/shenshikexmu/article/details/70991286
猜你喜欢
- 2024-10-14 “互联网+”大赛华软学院参赛项目风采|疲劳驾驶预警系统
- 2024-10-14 双目视觉在机械臂抓取中的应用(3D locate)
- 2024-10-14 翻译文章二:项目说明及四旋翼直升机的动力学原理
- 2024-10-14 基于TOF相机的靶标识别与位姿测量系统设计
- 2024-10-14 ANSYS Fluent中的动态网格模型理论介绍
- 2024-10-14 3D视觉 | 机器人3D手眼标定实验(上)
- 2024-10-14 基于VANET的车辆相对定位技术(gps相对定位常用的组合方法有)
- 2024-10-14 研究员为HoloLens 2 AR引导操作提出鲁棒性更强的姿态追踪
- 2024-10-14 基于全球卫星导航信号的极化阵列平台姿态估计
- 2024-10-14 使用OpenCV和Dlib的头部姿态估计(opencv 姿态估计)
你 发表评论:
欢迎- 07-02在线学习在爱奇艺信息流推荐业务中的探索与实践
- 07-02Diallyl Trisulfide(H2S donor)二烯丙基三硫:合成方法与工艺
- 07-02MitoSOX Red Mitochondrial Superoxide Indicator使用方法
- 07-02深度时空网络、记忆网络与特征表达学习在 CTR 预估中的应用
- 07-02iFluor 488标记鬼笔环肽可通过标记F-actin,研究细胞在迁移等
- 07-02快速了解红色线粒体超氧化物荧光探针的基本特性
- 07-02腔肠素400A(Coelenteramine 400a)综合解析,一文掌握所有要点!
- 07-02Chinese doctor Zhang Junqiao's heroic act exemplifies deep China-Africa friendship: FM spokesperson
- 最近发表
-
- 在线学习在爱奇艺信息流推荐业务中的探索与实践
- Diallyl Trisulfide(H2S donor)二烯丙基三硫:合成方法与工艺
- MitoSOX Red Mitochondrial Superoxide Indicator使用方法
- 深度时空网络、记忆网络与特征表达学习在 CTR 预估中的应用
- iFluor 488标记鬼笔环肽可通过标记F-actin,研究细胞在迁移等
- 快速了解红色线粒体超氧化物荧光探针的基本特性
- 腔肠素400A(Coelenteramine 400a)综合解析,一文掌握所有要点!
- Chinese doctor Zhang Junqiao's heroic act exemplifies deep China-Africa friendship: FM spokesperson
- 用Python写了一个上课点名系统(附源码)(自制考勤系统)
- Kubernetes中的PV、PVC、Configmap介绍
- 标签列表
-
- ifneq (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)