旋轉矩陣---數學理論


       旋轉矩陣是姿態的一種數學表達方式,或者籠統說變換矩陣是一種抽象的數學變量。其抽象在於當你看到數據,根本無法斷定其正確性;往往只有轉換為較為直觀的歐拉角,然后大概目測估算(總不能拿着量角器去測量精度吧)。

我們知道,姿態的數學形式有旋轉矩陣(滿足RTR=E)、歐拉角旋轉向量(角軸)、四元數(norm(x y z w) = 1)等。今天這里要討論的是旋轉矩陣相關理論基礎。

       旋轉矩陣常用於以下三種場景:

  • 描述一個frame(坐標系)相對於另一個frame間的位姿;(如:描述相鄰兩幀間的相機運動)
  • 描述一個point從一個frame變換到另一個frame;(其實點沒動,只是在兩個frame觀測時,坐標不一樣而已;如:;路標點點P在不同相機坐標系下坐標值不同,但在世界坐標系下是固定的)
  • 描述一個point在同一個frame中的運動;(這里的點是運動了的,在VSLAM中應用較少)

        繞三個軸的旋轉矩陣請按以下形式進行記憶,可能有些地方是下面的轉置形式。

 (本博客和大多數論文資料一樣,都是左乘原則)

一、固定旋轉(Fix Angles)

       所謂固定旋轉,就是按照物體外部固定軸旋轉。這種旋轉在工程中很常見,用的相對多一些(相對於下面的歐拉旋轉),例如:旋轉次序為X-Y-Z,那么旋轉矩陣的形式為:RZRYRX。如下圖,其實沒什么好說。

      已知旋轉矩陣,怎么求解歐拉角呢?下圖便是一種比較好的求解辦法。我們知道,順時針旋轉180°和逆時針旋轉180°是等效的(讓機械臂旋轉190°其實是走遠路,因為旋轉170°似乎更快),所以求解出來的歐拉角其取值范圍最好是:[0°,180°] or [0°,-180°] 或者[-90°,90°],這里采用的后者。

       下圖中的atan2是matlab中的api,我們在這里簡單驗證下其與tan的區別:可以看到,當一個點在第三象限,如(-1, -1),在歐拉角中,其角度為:-135°,但是atan(-1/-1)算出來是45°,顯然是錯的。

 1 >> atan(1) * 180 / pi
 2 
 3 ans =
 4 
 5     45
 6 
 7 >> atan2(1, 1) * 180 / pi
 8 
 9 ans =
10 
11     45
12 
13 >> atan2(-1, -1) * 180 / pi
14 
15 ans =
16 
17   -135
18 
19 >> 

       順在在這里用Eigen驗證下:(相關頭文件去這個鏈接中查找: https://www.cnblogs.com/winslam/p/12765822.html )不去下載,下面C++代碼你都跑不了

 1 #include"geometry.h"
 2 #include<iostream>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     Eigen::Matrix3d R1;
 8     R1 << 0.866, 0.433, 0.25, 0., 0.5, -0.866, -0.5, 0.75, 0.433;
 9 
10     Pose pose1(R1);
11     cout << "旋轉矩陣 = " << endl; cout << pose1.rotation() << endl;
12     cout << "歐拉角 = " << endl;   cout << pose1.euler_angle().transpose()*(180 / M_PI) << endl;
13     cout << "四元數 = " << endl;   cout << pose1.quaternion().coeffs().transpose() << endl;
14     cout << "角軸 = " << endl;
15     cout << pose1.angle_axis().angle()* (180 / M_PI) << " " << pose1.angle_axis().axis().transpose() << endl;
16     cout << "-----------------------------" << endl;
17     return 1;
18 }
View Code

       打印結果:

1 旋轉矩陣 =  0.866  0.433   0.25
2             0    0.5 -0.866
3             -0.5   0.75  0.433 
4 歐拉角 =   63.4349  14.4779 -26.5651                                                                                   
5 四元數 =   0.482959  0.224145 -0.129407  0.836511  
6 角軸 =     66.4519 0.881411 0.409071 -0.23617 

       可以看到Eigen的歐拉角結果和上述PPT中Matlab計算的結果不一樣,但是他們旋轉矩陣具體是一樣的,這個是正常的,下面還會碰到。其實就是利用歐式旋轉矩陣求解

歐拉角的解並不唯一,這個問題在手眼標定中驗證過。 

 

二、歐拉旋轉(Euler Angle)

        固定旋轉與歐拉旋轉的關系,例如:固定旋轉次序為:XYZ,寫成旋轉矩陣則為:Rz*Ry*Rx;其等效的歐拉旋轉次序為:ZYX,寫成旋轉矩陣則為:Rz*Ry*Rx,最后的映射矩陣是一樣的,但是過程不一樣,殊途同歸。)例如下面例子:

 

      ZYZ的歐拉旋轉次序,這個我是實際“體驗過”,那是在自研機械臂上示教器是數據。

      歐拉旋轉的方式如下圖:

 

         形如固定旋轉,我這里也給出:已經ZYZ類型歐拉旋轉,求解歐拉角的一種方法:

 

      針對上面等式,這里用Eigen驗證下:

       對於等式左邊:

 1 #include"geometry.h"
 2 #include<iostream>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     // 低級錯誤:是60.0,不是60
 8     Eigen::Matrix3d R1;
 9     R1 = Eigen::AngleAxisd(60.0 / 180 * M_PI, Eigen::Vector3d::UnitX()) *
10          Eigen::AngleAxisd(30.0 / 180 * M_PI, Eigen::Vector3d::UnitY()) *
11           Eigen::AngleAxisd(              0.0, Eigen::Vector3d::UnitZ());
12 
13     Pose pose3(R1);
14     cout << "旋轉矩陣 = " << endl; cout << pose3.rotation() << endl;
15     cout << "歐拉角 = " << endl;   cout << pose3.euler_angle().transpose()*(180 / M_PI) << endl;
16     cout << "四元數 = " << endl;   cout << pose3.quaternion().coeffs().transpose() << endl;
17     cout << "角軸 = " << endl;
18     cout << pose3.angle_axis().angle()* (180 / M_PI) << " " << pose3.angle_axis().axis().transpose() << endl;
19     cout << "-----------------------------" << endl;
22     return 1;
23 }

 

         針對等式右邊,同理有:

#include"geometry.h"
#include<iostream>
using namespace std;

int main()
{
    Eigen::Vector3d RPY;
    RPY << -56.3 / 180 * M_PI, 64.3 / 180 * M_PI, 73.9 / 180 * M_PI;

    cout << RPY(2, 0) << endl;


    Eigen::Matrix3d R2;
    // note: ZYZ
    R2 = Eigen::AngleAxisd(RPY(0, 0), Eigen::Vector3d::UnitZ()) *
         Eigen::AngleAxisd(RPY(1, 0), Eigen::Vector3d::UnitY()) *
         Eigen::AngleAxisd(RPY(2, 0), Eigen::Vector3d::UnitZ());
    Pose pose4(R2);
    cout << "旋轉矩陣 = " << endl; cout << pose4.rotation() << endl;
    cout << "歐拉角 = " << endl;   cout << pose4.euler_angle().transpose()*(180 / M_PI) << endl;
    cout << "四元數 = " << endl;   cout << pose4.quaternion().coeffs().transpose() << endl;
    cout << "角軸 = " << endl;
    cout << pose4.angle_axis().angle()* (180 / M_PI) << " " << pose4.angle_axis().axis().transpose() << endl;
    cout << "-----------------------------" << endl;

    return 1;
}

 

      對比兩種旋轉方式,可以看到Eigen計算的結果完全一致;但是比較有意思的是,對於下面,我用的歐拉角明明是( -56.3, 64.3, 73.9 )(ZYZ),結果打印輸出的

歐拉角居然是(59.9, 29.99, 0.031)。這是由於我寫的Pose類底層,我只定義了ZYX的固定旋轉方式。同時,也說明了,同一個旋轉矩陣,可能對應不同的旋轉方式(如:歐拉旋轉、固定旋轉),不同的旋轉歐拉角、甚至不同的旋轉次序

 

 三、旋轉矩陣小結

       歐拉旋轉和固定旋轉的次序有效的排列組合為:12 = 3 * 2 * 2

       姿態的數學形式有旋轉矩陣(約束:RTR=E)、歐拉角(萬向鎖問題)、旋轉向量(角軸)、四元數(約束norm(x y z w) = 1),所以VSLAM在對位姿進行優化的時候,

為了避免“帶約束的優化”問題,一般都會采用旋轉向量的形式作為姿態。

 

 

 

 

 

參考:

(台大機器人學之運動學——林沛群)

https://www.bilibili.com/video/BV1v4411H7ez?p=3

 

https://baike.baidu.com/item/%E6%97%8B%E8%BD%AC%E7%9F%A9%E9%98%B5/3265181?fr=aladdin#5

 

《jlblanco2010geometry3D_techrep.pdf》

 

https://blog.csdn.net/uranus1992/article/details/85788205

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM