欢迎访问我的博客首页。
二维刚体变换
1. 平面旋转
计算机中通常使用右手三维坐标系,因此,如果给图 1 中的坐标系
x
O
y
xOy
xOy 加上
z
z
z 轴,则
z
z
z 轴垂直纸面指向读者。 鉴于此,我们把图 1(左) 中绿色坐标系
O
a
O_a
Oa 按箭头旋转到红色坐标系
O
b
O_b
Ob 称为从
z
z
z 轴负方向看向正方向时的顺时针旋转。
1.1 使用平面向量基本定理推导旋转
向量基本定理:任意一个 n 维向量一定可以由 n 个相同维度且线性无关的向量来线性表示。这 n 个向量称为一组基底向量,简称基底。如果这 n 个向量两两正交,称为正交基。如果这 n 个向量都是单位向量,称为单位基底。
假设坐标系 O a O_a Oa 顺时针旋转 θ \theta θ 变成坐标系 O b O_b Ob,如图 1(左)。坐标系 O a O_a Oa 的单位正交基在坐标系 O a O_a Oa 中的坐标表示是 e x a = ( 1 , 0 ) T e_x^a=(1,0)^T exa=(1,0)T 和 e y a = ( 0 , 1 ) T e_y^a=(0,1)^T eya=(0,1)T。坐标系 O b O_b Ob 的单位正交基在坐标系 O a O_a Oa 中的坐标表示是 e x b = ( c o s θ , s i n θ ) T e_x^b=(cos\theta, sin\theta)^T exb=(cosθ,sinθ)T 和 e y b = ( − s i n θ , c o s θ ) T e_y^b=(-sin\theta, cos\theta)^T eyb=(−sinθ,cosθ)T。平面上任意一点 P P P 在两个坐标系中的坐标是 P a P_a Pa 和 P b P_b Pb。由向量基本定理知
[ e x a , e y a ] ⋅ P a = [ e x b , e y b ] ⋅ P b , [e_x^a, e_y^a] \cdot P_a = [e_x^b, e_y^b] \cdot P_b, [exa,eya]⋅Pa=[exb,eyb]⋅Pb,
所以
P a = [ e x a , e y a ] − 1 ⋅ [ e x b , e y b ] ⋅ P b = [ 1 0 0 1 ] − 1 ⋅ [ c o s θ − s i n θ s i n θ c o s θ ] ⋅ P b = [ c o s θ − s i n θ s i n θ c o s θ ] ⋅ P b . (1.1) \begin{aligned} P_a &= [e_x^a, e_y^a]^{-1} \cdot [e_x^b, e_y^b] \cdot P_b \\ &= \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}^{-1} \cdot \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \cdot P_b \\ &= \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \cdot P_b. \end{aligned} \tag{1.1} Pa=[exa,eya]−1⋅[exb,eyb]⋅Pb=[1001]−1⋅[cosθsinθ−sinθcosθ]⋅Pb=[cosθsinθ−sinθcosθ]⋅Pb.(1.1)
我们令
R a b 坐标系顺 = [ c o s θ − s i n θ s i n θ c o s θ ] . (1.2) R^{坐标系顺}_{ab} = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix}. \tag{1.2} Rab坐标系顺=[cosθsinθ−sinθcosθ].(1.2)
这个 R a b 坐标系顺 R^{坐标系顺}_{ab} Rab坐标系顺 左乘平面上任意一点 P P P 在坐标系 O b O_b Ob 中的坐标,得到 P P P 在坐标系 O a O_a Oa 中的坐标。所以我们称它为坐标系顺时针旋转时 O b O_b Ob 坐标到 O a O_a Oa 坐标的变换。
1.2 使用几何关系推导旋转
平面坐标系中任一长度为 r r r 的向量 O P a → = ( x a , y a ) \overrightarrow {OP_a} = (x_a, y_a) OPa=(xa,ya) 绕原点顺时针旋转 θ \theta θ 成为向量 O P b → = ( x b , y b ) \overrightarrow {OP_b} = (x_b, y_b) OPb=(xb,yb)。假设向量 O P a → \overrightarrow {OP_a} OPa 与 x x x 轴正方向的夹角是 ϕ \phi ϕ,图 1(右)。则有
{ x a = r c o s ϕ y a = r s i n ϕ x b = r c o s ( ϕ + θ ) = r c o s ϕ c o s θ − r s i n ϕ s i n θ y b = r s i n ( ϕ + θ ) = r s i n ϕ c o s θ + r c o s ϕ s i n θ , (1.3) \left\{\begin{aligned} x_a &= r cos \phi \\ y_a &= r sin \phi \\ x_b &= r cos (\phi + \theta) = r cos \phi cos \theta - r sin \phi sin \theta\\ y_b &= r sin (\phi + \theta) = r sin \phi cos \theta + r cos \phi sin \theta, \end{aligned}\right. \tag{1.3} ⎩ ⎨ ⎧xayaxbyb=rcosϕ=rsinϕ=rcos(ϕ+θ)=rcosϕcosθ−rsinϕsinθ=rsin(ϕ+θ)=rsinϕcosθ+rcosϕsinθ,(1.3)
把前两个公式代入后两个公式得
{ x b = x a c o s θ − y a s i n θ y b = y a c o s θ + x a s i n θ . (1.4a) \left\{\begin{aligned} x_b &= x_a cos \theta - y_a sin \theta\\ y_b &= y_a cos \theta + x_a sin \theta \end{aligned}\right.. \tag{1.4a} {xbyb=xacosθ−yasinθ=yacosθ+xasinθ.(1.4a)
把公式 ( 1.4 a ) (1.4a) (1.4a) 写出矩阵相乘的形式
P b = [ c o s θ − s i n θ s i n θ c o s θ ] P a . (1.4b) P_b = \begin{bmatrix} cos \theta & -sin \theta \\ sin \theta & cos \theta \end{bmatrix} P_a. \tag{1.4b} Pb=[cosθsinθ−sinθcosθ]Pa.(1.4b)
我们令
R b a 向量顺 = [ c o s θ − s i n θ s i n θ c o s θ ] . (1.5) R^{向量顺}_{ba} = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix}. \tag{1.5} Rba向量顺=[cosθsinθ−sinθcosθ].(1.5)
这个 R b a 向量顺 R^{向量顺}_{ba} Rba向量顺 左乘平面上任意一点 P P P 在坐标系 O a O_a Oa 中的坐标,得到 P P P 在坐标系 O b O_b Ob 中的坐标。所以我们称它为向量顺时针旋转时 O a O_a Oa 坐标到 O b O_b Ob 坐标的变换。
1.3 总结
由公式 ( 1.2 ) (1.2) (1.2) 和公式 ( 1.5 ) (1.5) (1.5) 可知:坐标系顺时针旋转时,把固定向量在旋转后的坐标系中的坐标变换到它在旋转前的坐标系中的坐标的变换,与坐标系不动时,把向量顺时针旋转后的坐标变换回旋转前的坐标的变换,互逆/互为转置。总结:
{ R a b 坐标系顺 = R a b 向量逆 = [ c o s θ − s i n θ s i n θ c o s θ ] R a b 坐标系逆 = R a b 向量顺 = [ c o s θ s i n θ − s i n θ c o s θ ] R a b ∗ = ( R b a ∗ ) − 1 = ( R b a ∗ ) T . (1.6) \left\{\begin{aligned} R^{坐标系顺}_{ab} &= R^{向量逆}_{ab} = \begin{bmatrix} cos \theta & -sin \theta \\ sin \theta & cos \theta \end{bmatrix} \\ R^{坐标系逆}_{ab} &= R^{向量顺}_{ab} = \begin{bmatrix} cos \theta & sin \theta \\ -sin \theta & cos \theta \end{bmatrix} \\ R^*_{ab} &= (R^*_{ba})^{-1} = (R^*_{ba})^T \end{aligned}\right.. \tag{1.6} ⎩ ⎨ ⎧Rab坐标系顺Rab坐标系逆Rab∗=Rab向量逆=[cosθsinθ−sinθcosθ]=Rab向量顺=[cosθ−sinθsinθcosθ]=(Rba∗)−1=(Rba∗)T.(1.6)
其中,下标 a b ab ab 表示该变换矩阵把旋转后的坐标 P b P_b Pb 变换到旋转前的坐标 P a P_a Pa,下标 b a ba ba 表示该变换矩阵把旋转前的坐标 P a P_a Pa 变换到旋转后的坐标 P b P_b Pb。
以图 1(左) 为例,坐标系 O b O_b Ob 由坐标系 O a O_a Oa 顺时针旋转 45° 得到。则 O a O_a Oa 中的点 P a ( 1 , 2 ) P_a(1, 2) Pa(1,2) 在 O b O_b Ob 中的坐标
P b = ( R a b 坐标系顺 ) − 1 P a = [ c o s π 4 s i n π 4 − s i n π 4 c o s π 4 ] [ 1 2 ] = [ 3 2 1 2 ] . P_b = (R^{坐标系顺}_{ab})^{-1} P_a = \begin{bmatrix} cos \frac{\pi}{4} & sin \frac{\pi}{4} \\ -sin \frac{\pi}{4} & cos \frac{\pi}{4} \end{bmatrix} \begin{bmatrix} 1 \\ 2 \end{bmatrix} = \begin{bmatrix} \frac{3}{\sqrt{2}} \\ \frac{1}{\sqrt{2}} \end{bmatrix}. Pb=(Rab坐标系顺)−1Pa=[cos4π−sin4πsin4πcos4π][12]=[2321].
2. 平面刚体变换
假设坐标系
O
a
O_a
Oa 平移
t
⃗
a
b
=
(
t
a
b
x
,
t
a
b
y
)
T
\vec t_{ab} = (t_{ab}^x, t_{ab}^y)^T
tab=(tabx,taby)T 且顺时针旋转
θ
a
b
\theta_{ab}
θab 变成坐标系
O
b
O_b
Ob,如图 2(左)。平面上任意一点
P
P
P 在两个坐标系中的坐标是
P
a
P_a
Pa 和
P
b
P_b
Pb。
2.1 坐标变换
由公式 1.2 1.2 1.2 知向量 O b P → \overrightarrow{O_bP} ObP 在坐标系 O a O_a Oa 中的坐标是 R a b 坐标系顺 ⋅ P b R^{坐标系顺}_{ab} \cdot P_b Rab坐标系顺⋅Pb。又因为向量 O a O b → \overrightarrow{O_aO_b} OaOb 在坐标系 O a O_a Oa 中的坐标是 t ⃗ a b \vec t_{ab} tab。所以向量 O a P → \overrightarrow{O_aP} OaP 在坐标系 O a O_a Oa 中的坐标
P a = O a O b → + O b P → = t ⃗ a b + R a b 坐标系顺 ⋅ P b = [ c o s θ a b − s i n θ a b t a b x s i n θ a b c o s θ a b t a b y 0 0 1 ] ⋅ P b = T a b 坐标系顺 ⋅ P b . (2.1) P_a = \overrightarrow{O_aO_b} + \overrightarrow{O_bP} = \vec t_{ab} + R^{坐标系顺}_{ab} \cdot P_b = \begin{bmatrix} cos \theta_{ab} & -sin \theta_{ab} & t_{ab}^x \\ sin \theta_{ab} & cos \theta_{ab} & t_{ab}^y \\ 0 & 0 & 1 \end{bmatrix} \cdot P_b = T^{坐标系顺}_{ab} \cdot P_b. \tag{2.1} Pa=OaOb+ObP=tab+Rab坐标系顺⋅Pb= cosθabsinθab0−sinθabcosθab0tabxtaby1 ⋅Pb=Tab坐标系顺⋅Pb.(2.1)
一般情况下,我们默认旋转指的是坐标系顺时针旋转,因此 R a b 坐标系顺 R^{坐标系顺}_{ab} Rab坐标系顺 可以简写为 R a b R_{ab} Rab, T a b 坐标系顺 T^{坐标系顺}_{ab} Tab坐标系顺 可以简写成 T a b T_{ab} Tab。其中 R R R 称为旋转矩阵, T T T 因包含旋转和平移而称为变换矩阵。
下面是 gmapping 实现公式 ( 2.1 ) (2.1) (2.1) 的代码。
Point phit = lp;
phit.x += *r * cos(lp.theta + *angle);
phit.y += *r * sin(lp.theta + *angle);
2.2 方向点
坐标系 O a O_a Oa 与坐标系 O b O_b Ob 的关系可以用一个带方向的点表示。带方向的点是一个三元数 ξ a b = ( t a b x , t a b y , θ a b ) \xi_{ab} = (t_{ab}^x, t_{ab}^y, \theta_{ab}) ξab=(tabx,taby,θab),分别表示坐标系 O b O_b Ob 的原点在坐标系 O a O_a Oa 中的横坐标、纵坐标、从坐标系 O a O_a Oa 到坐标系 O b O_b Ob 的旋转角度。
方向点 ξ \xi ξ 可以很容易地转换为变换矩阵 T T T。与变换矩阵相比,使用方向点表示二维变换有很多好处:维度更低,正好等于平面变换的自由度;两个方向点相加仍能表示二维变换,方便使用导数优化,而两个变换矩阵相加的结果不一定是变换矩阵。二维变换中的方向点类似三维变换中的李代数。
假设坐标系 O b O_b Ob 平移 t ⃗ b c = ( t b c x , t b c y ) T \vec t_{bc} = (t_{bc}^x, t_{bc}^y)^T tbc=(tbcx,tbcy)T 且顺时针旋转 θ b c \theta_{bc} θbc 变成坐标系 O c O_c Oc,如图 2(右)。那么,坐标系 O c O_c Oc 也可以看作由坐标系 O a O_a Oa 平移 t ⃗ a c = t ⃗ a b + R a b ⋅ t ⃗ b c \vec t_{ac} = \vec t_{ab} + R_{ab} \cdot \vec t_{bc} tac=tab+Rab⋅tbc 且顺时针旋转 θ a c = θ a b + θ b c \theta_{ac} = \theta_{ab} + \theta_{bc} θac=θab+θbc 而来。因此
ξ a c = [ t a c x t a c y θ a c ] = [ t a b x t a b y θ a b ] + [ c o s θ a b − s i n θ a b 0 s i n θ a b c o s θ a b 0 0 0 1 ] ⋅ [ t b c x t b c y θ b c ] . (2.2) \xi_{ac} = \begin{bmatrix} t_{ac}^x \\ t_{ac}^y \\ \theta_{ac} \end{bmatrix} = \begin{bmatrix} t_{ab}^x \\ t_{ab}^y \\ \theta_{ab} \end{bmatrix} + \begin{bmatrix} cos \theta_{ab} & -sin \theta_{ab} & 0 \\ sin \theta_{ab} & cos \theta_{ab} & 0 \\ 0 & 0 & 1 \end{bmatrix} \cdot \begin{bmatrix} t_{bc}^x \\ t_{bc}^y \\ \theta_{bc} \end{bmatrix}. \tag{2.2} ξac= tacxtacyθac = tabxtabyθab + cosθabsinθab0−sinθabcosθab0001 ⋅ tbcxtbcyθbc .(2.2)
注意, t ⃗ a c = t ⃗ a b + R a b ⋅ t ⃗ b c \vec t_{ac} = \vec t_{ab} + R_{ab} \cdot \vec t_{bc} tac=tab+Rab⋅tbc 而不是 t ⃗ a c = t ⃗ a b + t ⃗ b c \vec t_{ac} = \vec t_{ab} + \vec t_{bc} tac=tab+tbc。这是因为 t ⃗ b c \vec t_{bc} tbc 是坐标系 O b O_b Ob 中的坐标,需要先使用 R a b R_{ab} Rab 转换成坐标系 O a O_a Oa 中的坐标,再与 t ⃗ a b \vec t_{ab} tab 相加。
下面是 gmapping 实现公式 ( 2.2 ) (2.2) (2.2) 的代码。
OrientedPoint lp = p;
lp.x += cos(p.theta) * m_laserPose.x - sin(p.theta) * m_laserPose.y;
lp.y += sin(p.theta) * m_laserPose.x + cos(p.theta) * m_laserPose.y;
lp.theta += m_laserPose.theta;
3. 使用 Eigen
使用 Eigen 库实现二维欧式变换。
// 顺时针旋转 45 度。Eigen::Rotation2D<double> 等价于 Eigen::Rotation2Dd。
Eigen::Rotation2D<double> R = Eigen::Rotation2Dd(M_PI / 4);
cout << R.angle() << endl; // 弧度值。
cout << R.matrix() << endl; // 二阶旋转矩阵。
// 二维单位变换(三阶矩阵)。
Eigen::Isometry2d T;
T.setIdentity();
cout << T.matrix() << endl;
// 二维一般变换(三阶矩阵)。
T.rotate(R);
T.pretranslate(Eigen::Vector2d(2, 1));
cout << T.matrix() << endl;
4. 误差公式
4.1 SBA
4.2 SPA
相对 SBA,论文《Efficient Sparse Pose Adjustment for 2D mapping》提出了 SPA。假设全局位姿(在世界坐标系中的位姿)是
c = [ t , θ ] = [ x y θ ] . c = [t, \theta] = \begin{bmatrix} x \\ y \\ \theta \end{bmatrix}. c=[t,θ]= xyθ .
其中, ( x , y ) (x, y) (x,y) 表示二维坐标系的平移量, θ \theta θ 表示二维坐标系逆时针旋转的角度。
5. 参考
- 二维旋转矩阵,CSDN,2020。