1. 程式人生 > >【Unity編程】歐拉角與萬向節死鎖(圖文版)

【Unity編程】歐拉角與萬向節死鎖(圖文版)

num 接頭 標記 轉發 b2c 出現 spl 探索 質量

萬向節死鎖(Gimbal Lock)問題

上文中以前說過,歐拉旋轉的順規和軸向定義,自然造就了“萬向節死鎖”問題。本文主要來探索它自然形成的原因。

陀螺儀

首先。我們來了解Gimbal 到底是個什麽玩意兒。以下來自維基百科中關於Gimbal的一段引述:


平衡環架(英語:Gimbal)為一具有樞紐的裝置,使得一物體能以單一軸旋轉。由彼此垂直的樞紐軸所組成的一組三僅僅平衡環架。則可使架在最內的環架的物體維持旋轉軸不變,而應用在船上的陀螺儀、羅盤、飲料杯架等用途上,而不受船體因波浪上下震動、船身轉向的影響。


技術分享

上圖就是一個Gimbal裝置了,它是一個陀螺儀。中間有一根豎軸,穿過一個金屬圓盤。

金屬圓盤稱為轉子,豎軸稱為旋轉軸。轉子用金屬制成,應該是了添加質量。從而增大慣性。豎軸外側是三層嵌套的圓環,它們互相交叉,帶來了三個方向自由度的旋轉。
看著不停轉來轉去,有點暈,接下來看兩個靜態的。這兩張圖來自百度百科。

技術分享中文凝視: 技術分享

當中Gimbal僅僅代表陀螺儀裝置中的平衡環,顯然維基百科上將它解釋成“平衡環架”更為合理。

Pitch、Yaw、Roll

在解釋陀螺儀的工作原理之前,我先介紹一些轉動的術語。在飛行器的航行中,進行XYZ三個方向旋轉的旋轉有專業的術語,見下圖:

技術分享

沿著機身右方軸(Unity中的+X)進行旋轉,稱為pitch。中文叫俯仰


沿著機頭上方軸(Unity中的+Y)進行旋轉,稱為Yaw,中文叫偏航
沿著機頭前方軸(Unity中的+Z)進行旋轉,稱為Roll

,中文叫桶滾

陀螺儀的工作原理

我們知道陀螺儀使用來測量平衡和轉速的工具,在載體快速轉動的時候,陀螺儀始終要通過自我調節,使得轉子保持原有的平衡。這一點是怎樣做到的?帶著這個問題。我們來看一下這個古老而又神奇的裝置的工作原理。

為了解釋清楚問題,我自己畫了一個簡單的陀螺儀示意圖。

(金屬圓盤我就省略了,醜點兒也就別管了。

。)
技術分享
這裏,我把三個Gimbal環用不同的顏色做了標記,底部三個軸向,RGB分別相應XYZ。
如果如今這個陀螺儀被放在一艘船上,船頭的方向沿著+Z軸。也就是右前方。

  • 如今如果。船體發生了搖晃,是沿著前方進行旋轉的搖晃,也就是桶滾。因為轉子和旋轉軸具有較大的慣性。僅僅要沒有直接施加扭矩。就會保持原有的姿態。因為上圖中綠色的活動的連接頭處是能夠靈活轉動的,此時將發生相對旋轉,從而出現以下的情形:
    技術分享

  • 再次如果。船體發生了pitch搖晃,也就是俯仰。相同,因為存在相應方向的能夠相對旋轉的連接頭(紅色連接頭),轉子和旋轉軸將仍然保持平衡。例如以下圖:
    技術分享

  • 最後如果。船體發生了yaw搖晃,也就是偏航,此時船體在發生水平旋轉。相對旋轉發生在藍色連接頭。

    例如以下圖:
    技術分享

終於,在船體發生Pitch、Yaw、Roll的情況下,陀螺儀都能夠通過自身的調節,而讓轉子和旋轉軸保持平衡。

陀螺儀中的萬向節死鎖

如今看起來,這個陀螺儀一切正常,在船體發生隨意方向搖晃都能夠通過自身調節來應對。

然而,真的是這樣嗎?

假如,船體發生了劇烈的變化,此時船首仰起了90度(這是要翻船的節奏。。。。)。此時的陀螺儀調節狀態例如以下圖:
技術分享

此時,船體再次發生轉動,沿著當前世界坐標的+Z軸(藍色軸,應該正指向船底)進行轉動,那麽來看看發生了什麽情況。

技術分享

如今,轉子不平衡了,陀螺儀的三板斧不起作用了。它失去了自身的調節能力。那麽這是為什麽呢?
之前陀螺儀之所以能通過自身調節。保持平衡,是因為存在能夠相對旋轉的連接頭。在這樣的情況下,已經不存在能夠相對旋轉的連接頭了。
那麽連接頭呢?去了哪裏?顯然,它還是在那裏,僅僅只是是。連接頭能夠旋轉的相對方向不是如今須要的按著+Z軸方向。從上圖中,我們清楚地看到:

  • 紅色連接頭:能夠給予一個相對俯仰的自由度。
  • 綠色連接頭:能夠給予一個相對偏航的自由度。
  • 藍色連接頭:能夠給予一個相對偏航的自由度。

沒錯,三個連接頭,提供的自由度僅僅相應了俯仰和偏航兩個自由度,桶滾自由度丟失了。這就是陀螺儀上的“萬向節死鎖”問題。

用小程序來重現萬向節死鎖問題

首先,預設一下接下來的歐拉角變化順序。見下圖:
技術分享

上圖中,紅色框內的部分的列表,記錄了接下來歐拉角的增長變化過程。即它會從(0,0,0)變化到(90,0,0)。再變化到(90,90,0)。再變化到(90,180,0),再變化到(90,180,90)。再變化到(90,180,180)。下圖是變化的過程演示。

技術分享

如今能夠看到:
- 當先運行X軸旋轉90度,此時在運行Pitch(俯仰)變化。
- 再在Y軸進行變化0-180度,此時在運行相對自身的Roll(桶滾)變化。
- 再在Z軸進行變化0-180度,此時仍在運行相對自身的Roll(桶滾)變化。

這裏所說的俯仰、桶滾、偏航都是相對自己局部坐標系的。這與上述的陀螺儀中出現的問題是一樣的,萬向節死鎖。

也就是雖然歐拉角在XYZ三個軸向進行進動(持續增長或者降低),可是影響終於的結果,僅僅相應了兩個軸向。

死鎖的過程解析

在《Unity中歐拉旋轉》一文中我曾提到,是歐拉角順規和軸向的定義方式,造就了“萬向節死鎖”問題的自然形成。通過上述的樣例,這裏作個詳解。

首先我們知道,因為Unity中歐拉旋轉的順規的定義,環繞Z軸的進動最先運行。所以,Z軸是“嚴格保護”的一個軸。就是說。當先沿著Z軸進行進動時,不管此時的XY是什麽值,終於的結果,環繞Z軸的進動始終造成相對自身運行桶滾變化。
然而X、Y軸就不同了,我們先不考慮Y軸,如果其一直為0。先說X軸。如果Z軸也是保持為0,那麽環繞X軸進動,終於的影響是預期的俯仰變化。

例如以下圖:

技術分享

然而當Z軸為90度時。環繞X軸進動變成了偏航變化,例如以下圖:

技術分享

也就是說,歐拉角的X軸進動造成最後的變化結果,受到到了預先運行的Z軸進動的影響,它仍然會造成某個相對自身的軸向的變化,可是結果不唯一。相同,歐拉角的Y軸進動,則受到了Z軸和X軸的影響,結果更加不唯一。

然而,以上的過程運行,都是嚴格遵守歐拉角的順規和軸向定義的。

某些時刻,這樣的不確定的結果。就可能造成某個軸向自由度的丟失。


就拿下圖來說:
技術分享

歐拉角Z軸的進動。最先運行,造成桶滾。這個沒問題。
歐拉角Y軸的進動,最後運行,造成沿著歐拉旋轉前的Y軸旋轉,這也是依據定義運行。然而如今這樣的沿著Y軸的旋轉。相同也被映射到了物體的桶滾變化。

總結

總結來說。歐拉角的“萬向節死鎖”問題,是因為歐拉旋轉定義本身造成的。這樣的環繞選旋轉前固定軸的先Z、再X、再Y的旋轉操作,與其終於所預期的三個軸向能夠旋轉的結果並不是一定是一對一的映射。某些情況下是多對一的映射,造成一些旋轉自由度的缺失,也就是“死鎖”。

建議

對於寫代碼來說,你直接去改變Transform的歐拉角顯然是不合適的。通過本文也能夠看到,這樣的結果差點兒是不可預測的。

可是某些情況下,卻是能夠預期的,就是你僅僅在一個軸向進動,其他兩個軸向保持為0,此時有效,而且直接改動歐拉角的代碼效率應該是比較高的。

【Unity編程】歐拉角與萬向節死鎖(圖文版)