三維空間中剛體運動

 個人博客:http://www.chenjianqu.com/

原文鏈接:http://www.chenjianqu.com/show-82.html

本文是總結<視覺SLAM14講>所做的筆記。在前面的博文ROS-座標轉換(TF)介紹了ROS中的座標變換通信的機制,但是沒有提到座標變換本身,因此這篇博文補充這些基本概念。

    兩個座標系之間的運動由一個旋轉加上一個平移組成,若同一個向量在各個座標系下的長度和夾角都不會發生變化,則這種運動稱爲剛體運動。剛體運動前後的兩個座標系相差一個歐式變換。除了歐式變換之外,還有其它的變換,彙總如下:

    歐式變換:保持向量的長度和夾角,包括旋轉和平移。

    相似變換:比歐式變換多了一個縮放因子s,可以在旋轉之後進行縮放。

    仿射變換:仿射變換要求A是是一個可逆矩陣,而不一定是正交矩陣。經過放射變換後,立方體可能會變成斜的,但是各個面仍然是平行四邊形。

    射影變換:射影變換是最一般的變換,左上角爲可逆矩陣A,右上角爲平移t,左下角爲縮放a。

各個變換對比:

40.jpg

    一般說的座標變換就是歐式變換。

 

旋轉矩陣和變換矩陣

旋轉矩陣

    對於座標變換,向量本身沒有發生變換,只是座標系變了,根據座標的定義有:

1.jpg

    對上式左右兩邊同時左乘[e1,e2,e3]T,得:

2.jpg

    得到旋轉矩陣R, 該矩陣各分量是兩個座標系基的內積,由於基向量的長度爲 1,所以實際上是各基向量的夾角之餘弦,所以也叫方向餘弦矩陣(Direction Cosine matrix)。旋轉矩陣是行列式爲1的正交矩陣,反之行列式爲1的正交矩陣也是旋轉矩陣。旋轉矩陣集合:

3.jpg

    SO(n)稱爲特殊正交羣(special Orthogonal Group)。旋轉矩陣的逆描述了一個相反的旋轉,且R-1=RT

 

平移向量

    歐式變換由旋轉變換和平移變換組成,旋轉變換由旋轉矩陣R描述,平移變換由平移向量t描述,即座標變換A’=RA+t

 

變換矩陣

    使用旋轉矩陣和平移向量描述座標系變換,多次變換後公式過於複雜,因此引入齊次座標變換矩陣。齊次座標:在三維向量末尾添加1,變成四維向量。變換矩陣T;將旋轉和平移寫在一個矩陣裏。座標變換可表示如下:

4.jpg

    變換矩陣集合:

5.jpg

    SE(3)的意思是特殊歐式羣(Special Euclidean Group)。變換矩陣的逆也表示一個反向的變換:

6.jpg

 

旋轉向量和歐拉角

旋轉向量

    用旋轉矩陣描述旋轉存在以下缺點:

    1.SO(3)的旋轉矩陣有9個量,但是一次旋轉只有三個自由度,因此這種方式存在冗餘。變換矩陣同理。

    2.旋轉矩陣自身帶有約束:必須是正交矩陣,而且行列式爲1。當想要估計或優化一個旋轉矩陣/變換矩陣時,這些約束會使得求解變得更加困難。

    因此需要一種更加緊湊方式的描述旋轉和平移。任意旋轉都可以用一個旋轉軸和一個旋轉角來刻畫,使用一個向量,其方向和旋轉軸一致,長度等於旋轉角,這種向量稱爲旋轉向量(或軸角Axis-Angle)。這種表示法僅需要一個三維向量即可描述旋轉。使用旋轉向量加平移向量,只有六維,即可描述一次變換。

 

旋轉向量和旋轉矩陣之間的轉換

    假設有一個旋轉軸爲n,角度爲θ的旋轉,則其對應的旋轉向量爲θ*n。從旋轉向量到旋轉矩陣的轉換使用羅德里格斯公式

7.jpg

    符號^表示向量到反對稱的轉換符,如下:

10.jpg

    反之從旋轉矩陣轉換到旋轉向量,對於轉角θ,有:

11.jpg

    其中tr(R)表示矩陣R的跡。對於轉軸n,由於旋轉軸上的向量在旋轉後不發生改變,即Rn=n,因此轉軸n是旋轉矩陣R特徵值1對應的特徵向量。求解此方程,再歸一化,就得到了旋轉軸。

 

歐拉角

    旋轉矩陣和旋轉向量雖然能描述旋轉,但是非常不直觀。歐拉角提供了非常直觀的方式描述旋轉,將一個旋轉分解爲3次繞不同軸的旋轉。比如先繞X軸,再繞Y軸,最後繞Z軸就得到XYZ軸的旋轉。同理得ZYX,ZXY等方式的旋轉。這裏使用ZYX分解,假設一個剛體的前方(朝向我們的方向)爲X軸,右側爲Y軸,上方爲Z軸。

1.繞物體的Z軸旋轉,得到偏航角yaw

2.繞旋轉之後的Y軸旋轉,得到俯仰角pitch

3.繞旋轉之後的X軸旋轉,得到滾轉角roll

9.jpg

    歐拉角和旋轉向量的一個重大缺點是萬向鎖問題(Gimbal Lock):在俯仰角爲+-90度時,第一次旋轉和第三次旋轉將使用同一個軸,這使得系統丟失了一個自由度,這被稱爲奇異性問題。三個實數表示旋轉一定會碰到奇異性問題,因爲三維旋轉是一個三維流形,想要無奇異的表達它,三個量是不夠的。因此歐拉角往往只用於人際交互。

 

四元數

概念

    旋轉矩陣具有冗餘性,而歐拉角和旋轉向量雖然緊湊,但是具有奇異性。四元數(Quaternion)是一種擴展的複數,用它來表示旋轉既緊湊,又沒有奇異性。 一個四元數q有一個實部和三個虛部,如q = q0 + q1*i + q2*j + q3*k ,其中i,j,k爲四元數的三個虛部。三個虛部滿足如下關係式:

12.jpg

    也可以用一個標量和一個向量表示四元數:q=[s,v],s=q0,v=[q1,q2,q3],s稱爲實部,v稱爲虛部。若虛部爲0,則該四元數稱爲實四元數,反之稱之爲虛四元數

 

四元數的運算

1.加減法

13.jpg

2.乘法

14.jpg

15.jpg

3.模長

16.jpg

兩個四元數乘積的模即爲模的乘積

17.jpg

4.共軛

18.jpg

四元數共軛與其本身相乘,得到一個實四元數,其實部爲模長的平方:

19.jpg

5.逆

一個四元數的逆爲:

20.jpg

且:

21.jpg

22.jpg

6.數乘

23.jpg

 

用四元數表示旋轉

    可以用一個單位四元數q表示旋轉。假設空間點p爲[x,y,z],旋轉後的點爲p’。用一個虛四元數描述p點p=[0,x,y,z],則p’=q*p*q-1,結果p’的虛部就是旋轉後的座標。

 

將四元數乘法寫成矩陣形式

    q=[s,v],定義如下符號:

27.jpg

    則可以將四元數的乘法寫成矩陣形式:

28.jpg

29.jpg

    則用四元數矩陣乘法表示旋轉:

30.jpg

31.jpg

 

四元數和旋轉矩陣的轉換

    四元數轉換爲旋轉矩陣:

32.jpg

    設四元數q=q0+q1*i+q2*j+q3*k,對應的旋轉矩陣R爲:

33.jpg

旋轉矩陣到四元數的轉換:已知旋轉矩陣爲R={m_ij},i,j屬於[1,2,3],其對應的四元數爲:

34.jpg

 

四元數和旋轉向量的轉換

35.jpg

 

    

 

 

Eigen實現

    Eigen是一個開源的C++線性代數庫。座標變換的Eigen數據類型:

41.jpg

 

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(eigengeometrytest)
include_directories("/usr/include/eigen3")
add_executable(eigengeometrytest main.cpp)
install(TARGETS eigengeometrytest RUNTIME DESTINATION bin)

main.cpp

#include <iostream>
#include<ctime>
#include<Eigen/Core>
#include<Eigen/Geometry>
#include<Eigen/Dense>
using namespace std;
using namespace Eigen;
int main(int argc, char **argv) {
    std::cout << "Hello, world!" << std::endl;
      
    //旋轉矩陣使用Matrix3d
    Eigen::Matrix3d rotation_m=Eigen::Matrix3d::Identity();
    //旋轉向量 轉角,轉軸
    Eigen::AngleAxisd rotation_v(M_PI/4,Eigen::Vector3d(0,0,1));
    
    cout.precision(3);
    //將旋轉向量轉換爲旋轉矩陣
    cout<<"rotation_v.matrix:\n"<<rotation_v.matrix()<<endl<<endl;
    rotation_m=rotation_v.toRotationMatrix();
    cout<<"rotation_m:\n"<<rotation_m<<endl<<endl;
    
    //使用旋轉向量進行旋轉變換
    Eigen::Vector3d v(1,0,0);
    Eigen::Vector3d v_r=rotation_v*v;
    cout<<v<<endl<<"after v rotated:"<<v_r<<endl<<endl;
    
    //使用旋轉矩陣進行旋轉變換
    v_r=rotation_m*v;
    cout<<v<<endl<<"after m rotated:"<<v_r<<endl<<endl;
    
    //將旋轉矩陣轉換爲歐拉角ZYX
    Eigen::Vector3d euler_a=rotation_m.eulerAngles(2,1,0);
    cout<<"yaw pitch roll="<<euler_a.transpose()<<endl<<endl;
    
    //歐式變換矩陣
    Eigen::Isometry3d T=Eigen::Isometry3d::Identity();//實質是4x4矩陣
    //設置旋轉
    T.rotate(rotation_v);
    //設置平移向量
    T.pretranslate(Eigen::Vector3d(1,3,4));
    cout<<"Transform m:\n"<<T.matrix()<<endl<<endl;
    
    
    //旋轉向量轉換爲四元數
    Eigen::Quaterniond q=Eigen::Quaterniond(rotation_v);
    //輸出爲q1 q2 q3 q0,最後一個是實部
    cout<<"q:\n"<<q.coeffs()<<endl<<endl;
    
    //旋轉矩陣轉換爲旋轉向量
    q=Eigen::Quaterniond(rotation_m);
    cout<<"q\n"<<q.coeffs()<<endl<<endl;
    
    
    //使用四元數旋轉
    v_r=q*v; //乘法是重載的,數學上是qvq^-1
    cout<<"v_q_r:"<<v_r<<endl;
    
    
    return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章