三维旋转矩阵构成的特殊正交群 $SO(3)$
$$ S O ( 3 ) = \left\{ R \in \mathbb R ^ { n \times n } \mid R R ^ T = 1 , \operatorname { det } ( R ) = 1 \right\} $$
变换矩阵构成的特殊欧式群 $SE(3)$
$$ S E ( 3) = \left\{ T = \left[ \begin{array} { c c } R & t \\ 0 ^ { T } & 1 \end{array} \right] \in \mathbb R ^ { 4 \times 4 } \mid R \in S O ( s ) , t \in \mathbb R ^ { 3 } \right\} $$
群是一种集合加上一种运算的代数结构, 若把集合记为 $A$, 运算记为 $\cdot$ , 则这个群记为 $G = (A, \cdot)$ , 并且要求满足以下性质
粗略地说,李群是连续的群,也即其元素可由几个实参数描述。
李代数由一个集合 $\mathbb V$, 一个数域 $\mathbb F$, 和一个二元运算符 $[,]$ 组成, 若其满足以下几条性质, 则称 $(\mathbb V, \mathbb F, [,])$ 为一个李代数
$SO(3)$ 在 $\mathbb R ^3$ 上的向量, 记作 $\phi = [\phi_1, \phi_2, \phi_3]^T$.
$$ \Phi = \phi^\wedge = \left[\begin{array}{c} 0&-\phi_3&\phi_2 \\ \phi_3&0&-\phi_1 \\ -\phi_2&\phi_1&0\end{array} \right] $$
在此定义下, 两个向量 $\phi_1, \phi_2$ 的李括号运算定义为: $[\phi_1, \phi_2] = (\Phi_1\Phi_2-\Phi_2\Phi_1)^\vee$
李代数 $\mathfrak{so}(3) = \left\{ \phi \in \mathbb R^3, \Phi=\phi^\wedge \in \mathbb R ^{3 \times 3} \right\}$, 是一个三维向量的集合, 每个三维向量对应一个反对称阵, 表示旋转矩阵的导数
旋转矩阵与李代数 $\mathfrak{so}(3)$ 的关系
$$ R= \exp(\phi ^{\wedge}) $$
$\mathfrak{se}(3)$ 位于 $\mathbb R^ 6$ 空间中, $\rho$ 表示平移, $\phi$ 表示旋转
$$ \mathfrak{se}(3) = \left\{ \xi = \left[ \begin{array}{c}\rho\\\phi \end{array}\right]\in \mathbb R^6, \rho \in \mathbb R ^3, \phi \in \mathfrak{so}(3), \xi ^{\wedge} = \left[ \begin{array}{c} \phi^\wedge & \rho \\ 0^T & 0\end{array}\right] \in \mathbb R^{4 \times 4}\right\} $$
使用李代数的理由
旋转矩阵有约束条件, 必须是一个正交矩阵, 不好进行优化.使用旋转向量的话, 则无约束条件
对于矩阵 $\mathbf {A, B}$, 其计算矩阵的指数乘积时, 其 BCH 公式如下:
$$ \ln ( \exp ( \mathbf { A } ) \exp ( \mathbf { B } ) ) = \mathbf { A } + \mathbf { B } + \frac { 1 } { 12 } [ \mathbf { A } , \mathbf { B } ] + \frac { 1 } { 12 } [ \mathbf { A } , [ \mathbf { A } , \mathbf { B } ] ] - \frac { 1 } { 12 } [ \mathbf { B } , [ \mathbf { A } , \mathbf { B } ] ] + \ldots $$
考虑当相机运动时, 机器人运动的更新量 $\phi_2$ 很小, 则其 $SO(3)$ 上的李代数 $\ln \left( \exp \left( \phi _ { 1 } ^ { \wedge } \right) \exp \left( \phi _ { 2 } ^ { \wedge } \right) \right) ^ { \vee }$, 其小量二次以上的项都可以忽略, 此时, BCH 的线性近似为:
$$ \ln \left( \exp \left( \phi _ { 1 } ^ { \wedge } \right) \exp \left( \phi _ { 2 } ^ { \wedge } \right) \right) ^ { \vee } \approx \left\{ \begin{array} { l } \mathbf { J } _ { l } \left( \phi _ { 2 } \right) ^ { - 1 } \phi _ { 1 } + \phi 2 , \text { 当 } \phi _ { 1 } \text { 为小量 } \\ \mathbf { J } _ { r } \left( \phi _ { 1 } \right) ^ { - 1 } \phi _ { 2 } + \phi _ { 1 } , \text { 当 } \phi _ { 2 } \text { 为小量 } \end{array} \right. $$
其中
$$ \mathbf { J } _ { l } = \mathbf { J } = \frac { \sin \theta } { \theta } \mathbf { I } + \left( 1 - \frac { \sin \theta } { \theta } \right) \mathbf { a } \mathbf { a } ^ { T } + \frac { 1 - \cos \theta } { \theta } \mathbf { a } ^ { \wedge }\mathbf { J } _ { l } = \mathbf { J } = \frac { \sin \theta } { \theta } \mathbf { I } + \left( 1 - \frac { \sin \theta } { \theta } \right) \mathbf { a } \mathbf { a } ^ { T } + \frac { 1 - \cos \theta } { \theta } \mathbf { a } ^ { \wedge } $$
$$ \mathbf { J } _ { l } ^ { - 1 } = \frac { \theta } { 2 } \cot \frac { \theta } { 2 } \mathbf { I } + \left( 1 - \frac { \theta } { 2 } \cot \frac { \theta } { 2 } \right) \mathbf { a } \mathbf { a } ^ { T } - \frac { \theta } { 2 } \mathbf { a } ^ { \wedge } $$
$$ \mathbf { J } _ { r } ( \phi ) = \mathbf { J } _ { l } ( - \phi ) $$
反之,如果我们在李代数上进行加法,让 $\phi$ 加上 $\Delta \phi$ ,那么可以近似为李群上带左/右雅可比矩阵的乘法:
$$ \exp \left( ( \phi + \Delta \phi ) ^ { \wedge } \right) = \exp \left( \left( \mathbf { J } _ { l } \Delta \phi \right) ^ { \wedge } \right) \exp \left( \phi ^ { \wedge } \right) = \exp \left( \phi ^ { \wedge } \right) \exp \left( \left( \mathbf { J } _ { r } \Delta \phi \right) ^ { \wedge } \right) $$
同样的, 对于 $SE(3)$, 也有类似的BCH近似公式
$$ \begin{array} { l } \exp \left( \Delta \xi ^ { \wedge } \right) \exp \left( \xi ^ { \wedge } \right) \approx \exp \left( \left( \mathcal { J } _ { l } ^ { - 1 } \Delta \xi + \xi \right) ^ { \wedge } \right) \\ \exp \left( \xi ^ { \wedge } \right) \exp \left( \Delta \xi ^ { \wedge } \right) \approx \exp \left( \left( \mathcal { J } _ { r } ^ { - 1 } \Delta \xi + \xi \right) ^ { \wedge } \right) \end{array} $$
根据定义求导
假设空间点 $p$ 进行了一次矩阵表示为 $R$ 的旋转,得到了 $Rp$ 。要计算旋转后的点的坐标相对于旋转的导数. 设 $R$ 所对应的李代数为 $\phi$, 就可以写成:
$$ \frac { \partial \left( \exp \left( \phi ^ { \wedge } \right) \mathbf { p } \right) } { \partial \phi } $$
那么根据导数的定义
$$ \frac { \partial \left( \exp \left( \phi ^ { \wedge } \right) \mathbf { p } \right) } { \partial \phi } = \lim _ { \delta \phi \rightarrow 0 } \frac { \exp \left( ( \phi + \delta \phi ) ^ { \wedge } \right) \mathbf { p } - \exp \left( \phi ^ { \wedge } \right) \mathbf { p } } { \delta \phi } = - ( \mathbf { R } \mathbf { p } ) ^ { \wedge } \mathbf { J } _ { l } $$
这种方式求得的导数任然含有形式复杂的 $\mathbf { J } _ { l }$, 因此可以使用以下的方式可以求得更简单的形式
左乘模型的求导
另一种方法则是对旋转矩阵 $R$ 进行一次扰动 $\Delta R$ ,然后在对这个扰动进行求导, 设左扰动的李代数为 $\phi$, 直接对 $\phi$ 进行求导:
$$ \frac { \partial ( \mathbf { R } \mathbf { p } ) } { \partial \varphi } = \lim _ { \varphi \rightarrow 0 } \frac { \exp \left( \varphi ^ { \wedge } \right) \exp \left( \phi ^ { \wedge } \right) \mathbf { p } - \exp \left( \phi ^ { \wedge } \right) \mathbf { p } } { \varphi } = - ( \mathbf { R } \mathbf { p } ) ^ { \wedge } $$
$SE(3)$ 上的扰动模型
假设某空间点 $p$ 经过了一次变换 $T$ ,对应的李代数为 $\xi$ ,得到了 $Tp$ 。给 $T$ 左乘一个微小扰动 $\Delta T$ ,扰动项的李代数为 $\delta \xi = [ \delta \rho , \delta \phi ] ^ { T }$ 。则有:
$$ \frac { \partial ( \mathbf { T } \mathbf { p } ) } { \partial \delta \xi } = \lim _ { \delta \xi \rightarrow 0 } \frac { \exp \left( \delta \xi ^ { \wedge } \right) \exp \left( \xi ^ { \wedge } \right) \mathbf { p } - \exp \left( \xi ^ { \wedge } \right) \mathbf { p } } { \delta \xi } = \left[ \begin{array} { c c } \mathbf { I } _ { 3 \times 3 } & - ( \mathbf { R } \mathbf { p } + \mathbf { t } ) _ { 3 \times 3 } ^ { \wedge } \\ \mathbf { 0 } _ { 1 \times 3 } ^ { T } & \mathbf { 0 } _ { 1 \times 3 } ^ { T } \end{array} \right] = ( \mathbf { T } \mathbf { p } ) ^ { \odot } $$
git clone <https://github.com/strasdat/Sophus.git>
cd Sophus
git checkout a621ff
// 编译
mkdir build
cd build
cmake ..
make
在Cmakelist.txt中添加
find_package(Sophus REQUIRED)
include_directories( ${Sophus_INCLUDE_DIRS})
add_executable(useSophus useSophus.cpp)
target_link_libraries(useSophus ${Sophus_LIBRARIES})
//
// Created by fjczx on 2021/8/29.
//
#include <iostream>
#include "Eigen/Core"
#include "Eigen/Geometry"
#include "sophus/so3.h"
#include "sophus/se3.h"
using namespace std;
int main(){
// 以旋转向量方式初始化旋转矩阵R
Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d(0, 0, 1)).toRotationMatrix();
// 用旋转矩阵构建SO3
Sophus::SO3 SO3_R(R);
// 用向量直接构建SO3
Sophus::SO3 SO3_v(0, 0, M_PI/2);
// 从四元数构建SO3
Eigen::Quaterniond q(R);
Sophus::SO3 SO3_q(q);
// 它们的输出都是一致的
// 注意: 当输出 SO(3) 的时候, 将会以 so3 的形式输出
cout << "SO(3) from matrix: \n" << SO3_R << endl;
cout << "SO(3) from vector: \n" << SO3_v << endl;
cout << "SO(3) from quaternion: \n" << SO3_q << endl;
// 使用对数映射来获取它的李代数
Eigen::Vector3d so3 = SO3_R.log();
cout << "so3: \n" << so3.transpose() << endl;
// 旋转向量所对应的反对称阵
cout << "so3^{\\wedge}: \n " << Sophus::SO3::hat(so3) << endl;
// 反对称矩阵所对应的特征向量
cout << "so3^{\\wedge}^{\\vee}: \n" << Sophus::SO3::vee(Sophus::SO3::hat(so3)).transpose() << endl;
// 增量扰动模型
Eigen::Vector3d update_so3(1e-4, 0, 0);
Sophus::SO3 SO3_update = Sophus::SO3::exp(update_so3)*SO3_R;
cout << "SO3_update: \n" << SO3_update << endl;
/*
* 如下是对SE3的操作
*/
Eigen::Vector3d t(1, 0, 0);
// 从旋转矩阵和平移来构建SE(3)
Sophus::SE3 SE3_Rt(R, t);
// 使用四元数和平移来构建SE(3)
Sophus::SE3 SE3_qt(q, t);
cout << "SE(3) from R,t: \n" << SE3_Rt << endl;
cout << "SE(3) from q,t: \n" << SE3_qt << endl;
// 由于李代数 se(3) 是一个六维向量, 所以先定义一个六维向量类型
typedef Eigen::Matrix<double, 6, 1> Vector6d;
Vector6d se3 = SE3_Rt.log();
// 输出李代数 se(3), 输出的时候平移部分在前面, 旋转部分在后面
cout << "se3: \n" << se3.transpose() << endl;
// 将李代数 se(3) 转化为响应的反对称矩阵
cout << "se3^{\\wedge}: \n" << Sophus::SE3::hat(se3) << endl;
cout << "se3^{\\wedge}^{\\vee}: \n" << Sophus::SE3::vee(Sophus::SE3::hat(se3)).transpose() << endl;
// 定义更新量
Vector6d update_se3;
update_se3.setZero();
update_se3(0, 0) = 1e-4;
Sophus::SE3 SE3_update = Sophus::SE3::exp(update_se3)*SE3_Rt;
cout << "SE3 updated: \n" << SE3_update << endl;
return 0;
}