FAST-LIO2

关于论文 FAST-LIO2: Fast Direct LiDAR-inertial Odometry (TRO 2022) 的阅读总结。

FAST-LIO2

论文情况

1 Introduction

LiDAR 里程计和建图面临的挑战:

  1. LiDAR 产生的点数量庞大,在计算能力有限的板载平台上实时处理需要高效的算法;
  2. 特征(点、线、面)提取容易受到环境影响,且提取效果受到 LiDAR 扫描模式的影响;
  3. LiDAR 连续运动时,点采样会产生运动失真,使用 IMU 解决这一问题又会引入外部偏差;
  4. 点云是稀疏且范围较大的,维护稀疏点云地图和进行点云搜索是困难的。

本文提出了两个新技术:增量 K-D 树(incrementa k-d tree)和直接点注册(diret points registration),贡献整理如下:

  1. 提出增量 K-D 树数据结构 ikd-Tree,用于高效表示大型稠密点云。除了高效的最近邻查找,ikd-Tree 还支持增量式的地图更新(点插入、删除)和动态的再平衡。
  2. 借助 ikd-Tree 计算效率的提高,直接将原始点配准到地图上,实现更准确和可靠的扫描配准。本文将这种基于原始点的配准称为直接法,直接法使系统适用于不同的 LiDAR。
  3. 将这两项关键技术集成到 FAST-LIO[1] 中。该系统使用 IMU 通过反向传播补偿每个点的运动,并通过流形迭代卡尔曼滤波器估计系统的完整状态。为了进一步加快计算速度,使用了一个数学等价的卡尔曼增益计算公式,降低计算复杂性,新系统称为 FAST-LIO2。

2 System Overview

FAST-LIO2 的流程如图-1。

  • 采样的 LiDAR 原始点首先在 10ms 和 100ms 之间的周期内累积,累积的点云称为一次扫描。
  • 新扫描中的点将通过紧耦合迭代卡尔曼滤波框架(红虚线框)注册到大局部地图中保存的地图点。大局部地图中的全局地图点由 ikd-Tree 组织(蓝色虚线框)。
  • 如果当前 LiDAR 的 FoV 范围跨越了地图边界,则将距离 LiDAR 姿态最远的地图区域中的历史点从 ikd-Tree 中删除。因此,ikd-Tree 在一个具有一定长度的大立方体区域(称为 map size)中跟踪所有地图点,并用于状态估计模块中的残差计算。
  • 优化后的姿态最终将新扫描中的点注册到全局框架中,并插入到 ikd-Tree 中,从而合并到地图中。

3 State Estimation

FAST-LIO2 为继承了 FAST-LIO 的紧耦合迭代卡尔曼滤波器。

3.1 Kinematic Model

3.1.1 State Transition Model

取第一个 IMU 帧(IMU 帧记为 II)为全局帧(记为 GG),记 ITL=(IRL,IpL){}^I \mathbf{T}_L = ({}^I \mathbf{R}_L, {}^I \mathbf{p}_L) 为 LiDAR 和 IMU 之间的未知参数,则运动模型为:

GR˙I=GRIωmbωnω,Gp˙I=GvI,Gv˙I=GRI(ambana)+Ggb˙ω=nbω,b˙a=nba,Gg˙=0,IR˙L=0,Ip˙L=0(1)\begin{aligned} { }^G \dot{\mathbf{R}}_I & ={ }^G \mathbf{R}_I\left\lfloor\boldsymbol{\omega}_m-\mathbf{b}_{\boldsymbol{\omega}}-\mathbf{n}_{\boldsymbol{\omega}}\right\rfloor_{\wedge},{ }^G \dot{\mathbf{p}}_I={ }^G \mathbf{v}_I, \\ { }^G \dot{\mathbf{v}}_I & ={ }^G \mathbf{R}_I\left(\mathbf{a}_m-\mathbf{b}_{\mathbf{a}}-\mathbf{n}_{\mathbf{a}}\right)+{ }^G \mathbf{g} \\ \dot{\mathbf{b}}_{\boldsymbol{\omega}} & =\mathbf{n}_{\mathbf{b} \boldsymbol{\omega}}, \dot{\mathbf{b}}_{\mathbf{a}}=\mathbf{n}_{\mathbf{b a}}, \\ { }^G \dot{\mathbf{g}} & =\mathbf{0},{ }^I \dot{\mathbf{R}}_L=\mathbf{0},{ }^I \dot{\mathbf{p}}_L=\mathbf{0} \end{aligned} \tag{1}

GRI,GpI{ }^G \mathbf{R}_I, { }^G \mathbf{p}_I 表示 IMU 在全局系下的旋转和位置,Gg{ }^G \mathbf{g} 为全局系下的重力向量,am,ωm\mathbf{a}_m, \boldsymbol{\omega}_m 为 IMU 测量,a\lfloor \mathbf{a} \rfloor_{\wedge}aR3\mathbf{a} \in \mathbb{R}^3 的斜对称叉乘矩阵。

ii 为 IMU 测量的索引,由 [1] 得到连续运动模型 (1) 可以在 IMU 采样周期 Δt\Delta t 内离散化为(/\boxplus / \boxminus 见附录 A):

xi+1=xi(Δtf(xi,ui,wi))(2)\mathbf{x}_{i+1} = \mathbf{x}_i \boxplus (\Delta t \mathbf{f}(\mathbf{x}_i, \mathbf{u}_i, \mathbf{w}_i)) \\ \tag{2}

函数 f\mathbf{f},状态 x\mathbf{x},输入 u\mathbf{u},噪声 w\mathbf{w} 的定义如下:

MSO(3)×R15×SO(3)×R3;dim(M)=24x[GRITGpITGvITbωTbaTGgTIRLTIpLT]TMu[ωmTamT]T,w[nωTnaTnbωTnbaT]Tf(x,u,w)=[ωmbωnωGvI+12(GRI(ambana)+Gg)ΔtRI(ambana)+Ggnbωnba03×103×103×1]R24(3)\begin{aligned} & \mathcal{M} \triangleq S O(3) \times \mathbb{R}^{15} \times S O(3) \times \mathbb{R}^3 ; \operatorname{dim}(\mathcal{M})=24 \\ & \mathbf{x} \triangleq\left[\begin{array}{llllllll} { }^G \mathbf{R}_I^T & { }^G \mathbf{p}_I^T & { }^G \mathbf{v}_I^T & \mathbf{b}_{\boldsymbol{\omega}}^T & \mathbf{b}_{\mathbf{a}}^T & { }^G \mathbf{g}^T & { }^I \mathbf{R}_L^T & { }^I \mathbf{p}_L^T \end{array}\right]^T \in \mathcal{M} \\ & \mathbf{u} \triangleq\left[\begin{array}{ll} \boldsymbol{\omega}_m^T & \mathbf{a}_m^T \end{array}\right]^T, \mathbf{w} \triangleq\left[\begin{array}{llll} \mathbf{n}_{\boldsymbol{\omega}}^T & \mathbf{n}_{\mathbf{a}}^T & \mathbf{n}_{\mathbf{b} \boldsymbol{\omega}}^T & \mathbf{n}_{\mathbf{b a}}^T \end{array}\right]^T \\ & \mathbf{f}(\mathbf{x}, \mathbf{u}, \mathbf{w})=\left[\begin{array}{c} \boldsymbol{\omega}_m-\mathbf{b}_{\boldsymbol{\omega}}-\mathbf{n}_{\boldsymbol{\omega}} \\ { }^G \mathbf{v}_I+\frac{1}{2}\left({ }^G \mathbf{R}_I\left(\mathbf{a}_m-\mathbf{b}_{\mathbf{a}}-\mathbf{n}_{\mathbf{a}}\right)+{ }^G \mathbf{g}\right) \Delta t \\ \mathbf{R}_I\left(\mathbf{a}_m-\mathbf{b}_{\mathbf{a}}-\mathbf{n}_{\mathbf{a}}\right)+{ }^G \mathbf{g} \\ \mathbf{n}_{\mathbf{b} \boldsymbol{\omega}} \\ \mathbf{n}_{\mathbf{b a}} \\ \mathbf{0}_{3 \times 1} \\ \mathbf{0}_{3 \times 1} \\ \mathbf{0}_{3 \times 1} \end{array}\right] \in \mathbb{R}^{24} \\ & \end{aligned} \tag{3}

3.1.2 Measurement Model

LiDAR 通常逐个进行点采样。因此,LiDAR 连续运动时会以不同的姿态对点进行采样。为了纠正这种扫描内运动,采用 [1] 中提出的反向传播,根据 IMU 测量值估计扫描中每个点的 LiDAR 姿态相对于扫描结束时间的姿态。估计的相对姿态使得能够基于扫描中每个单独点的精确采样时间,将所有点投影到扫描结束时间。因此,可以得到扫描中的点在扫描结束时被同时采样。

kk 为 LiDAR 扫描的索引,在 LiDAR 坐标系 LL 下第 kk 个扫描在扫描结束时刻的采样点集为 {Lpj,j=1,...,m}\lbrace {}^L \mathbf{p}_j, j = 1, ..., m \rbrace。由于误差,每个 Lpj{}^L \mathbf{p}_j 受到噪声 Lnj{}^L \mathbf{n}_j 污染:

Lpjgt=Lpj+Lnj(3){}^L \mathbf{p}_j^{gt} = {}^L \mathbf{p}_j + {}^L \mathbf{n}_j \tag{3}

如图-2,真实的点通过位姿应该准确地落在地图的一个局部小平面段上:

0=GujT(GTIkITL(Lpj+Lnj)Gqj)(4)\mathbf{0} = {}^G \mathbf{u}_j^T ({}^G \mathbf{T}_{I_k} {}^I \mathbf{T}_L ({}^L \mathbf{p}_j + {}^L \mathbf{n}_j) - {}^G \mathbf{q}_j) \tag{4}

Guj{}^G \mathbf{u}_j 为平面法向量,GqjT{}^G \mathbf{q}_j^T 为平面上的一个点。注意到 GTIk,ITL{}^G \mathbf{T}_{I_k}, {}^I \mathbf{T}_L 包含在状态 xk\mathbf{x}_k 中。由第 jj 个点测量表达的式子 (4) 可以总结为如下的形式:

0=hj(xk,Lpj+Lnj)(5)\mathbf{0} = \mathbf{h}_j(\mathbf{x}_k, {}^L \mathbf{p}_j + {}^L \mathbf{n}_j) \tag{5}

(5) 定义了状态 xk\mathbf{x}_k 的隐式测量。

3.2 Iterated Kalman Filter

基于流形 MSO(3)×R15×SO(3)×R3\mathcal{M} \triangleq SO(3) \times \mathbb{R}^{15} \times SO(3) \times \mathbb{R}^3 形成的状态模型 (2) 和测量模型 (5),使用一个运算于 M\mathcal{M} 的(参考 [1] 和 [2])迭代卡尔曼滤波器。其包含两个步骤:沿 IMU 测量传播,沿 LiDAR 扫描更新。由于 IMU 频率高于 LiDAR,因此在更新前通常存在多个传播步骤。

3.2.1 Propagation

设前一个扫描的优化后状态估计为 xˉk1\bar{\mathbf{x}}_{k-1},协方差为 Pˉk1\bar{\mathbf{P}}_{k-1}。当 IMU 测量到来时,执行前向传播。具体来说,状态和协方差按照 (2) 通过将过程噪声 wi\mathbf{w}_i 设为 0 来传播:

x^i+1=x^i(Δtf(x^i,ui,0));x^0=xˉk1P^i+1=Fx~iP^iFx~iT+FwiQiFwiT;P^0=Pˉk1(6)\begin{aligned} &\widehat{\mathbf{x}}_{i+1} = \widehat{\mathbf{x}}_i \boxplus (\Delta t \mathbf{f}(\widehat{\mathbf{x}}_i, \mathbf{u}_i, \mathbf{0})); \widehat{\mathbf{x}}_0 = \bar{\mathbf{x}}_{k-1} \\ &\widehat{\mathbf{P}}_{i+1} = \mathbf{F}_{\widetilde{\mathbf{x}}_{i}} \widehat{\mathbf{P}}_i \mathbf{F}_{\widetilde{\mathbf{x}}_{i}}^T + \mathbf{F}_{\mathbf{w}_i} \mathbf{Q}_i \mathbf{F}_{\mathbf{w}_i}^T; \widehat{\mathbf{P}}_0 = \bar{\mathbf{P}}_{k-1} \end{aligned} \tag{6}

其中 Qi\mathbf{Q}_iwi\mathbf{w}_i 的协方差,Fx~i\mathbf{F}_{\widetilde{\mathbf{x}}_{i}}Fwi\mathbf{F}_{\mathbf{w}_i} 的计算如下(参考 [1] 和 [2]):

Fx~i=(xi+1x^i+1)x~ix~i=0,wi=0Fwi=(xi+1x^i+1)wix~i=0,wi=0(7)\begin{aligned} &\mathbf{F}_{\widetilde{\mathbf{x}}_{i}} = \left. \frac{\partial (\mathbf{x}_{i+1} \boxminus \widehat{\mathbf{x}}_{i+1})}{\partial \widetilde{\mathbf{x}}_i} \right|_{\widetilde{\mathbf{x}}_i = \mathbf{0}, \mathbf{w}_i = \mathbf{0}} \\ &\mathbf{F}_{\mathbf{w}_i} = \left. \frac{\partial (\mathbf{x}_{i+1} \boxminus \widehat{\mathbf{x}}_{i+1})}{\partial \mathbf{w}_i} \right|_{\widetilde{\mathbf{x}}_i = \mathbf{0}, \mathbf{w}_i = \mathbf{0}} \end{aligned} \tag{7}

前向传播持续到新扫描(第 kk 次扫描)的结束,传播状态和协方差记为 x^k,P^k\widehat{\mathbf{x}}_k, \widehat{\mathbf{P}}_k

3.2.2 Residual Computation

设当前迭代的状态估计为 x^kκ\widehat{\mathbf{x}}_k^{\kappa} 且有 κ=0\kappa = 0x^kκ=x^k\widehat{\mathbf{x}}_k^{\kappa} = \widehat{\mathbf{x}}_k,即 (6) 中传播的预测状态。然后,将点 Lpj{}^L \mathbf{p}_j 投影到全局系下 Gp^j=GT^IkκIT^LkκLpj{}^G \widehat{\mathbf{p}}_j = {}^G \widehat{\mathbf{T}}_{I_k}^{\kappa} {}^I \widehat{\mathbf{T}}_{L_k}^{\kappa} {}^L \mathbf{p}_j 并通过 ikd-Tree 在地图中搜索其最近的 5 个点。这些最近点用于拟合局部小平面分段,得到用于 (4) (5) 的法向量为 Guj{}^G \mathbf{u}_j 和重心 Gqj{}^G \mathbf{q}_j

测量方程 (5) 在 x^kκ\widehat{\mathbf{x}}_k^{\kappa} 的一阶近似:

0=hj(xk,Lnj)hj(x^kκ,0)+Hjκx~kκ+vj=zjκ+Hjκx~kκ+vj(8)\begin{aligned} \mathbf{0} & =\mathbf{h}_j\left(\mathbf{x}_k,{ }^L \mathbf{n}_j\right) \simeq \mathbf{h}_j\left(\widehat{\mathbf{x}}_k^\kappa, \mathbf{0}\right)+\mathbf{H}_j^\kappa \widetilde{\mathbf{x}}_k^\kappa+\mathbf{v}_j \\ & =\mathbf{z}_j^\kappa+\mathbf{H}_j^\kappa \widetilde{\mathbf{x}}_k^\kappa+\mathbf{v}_j \end{aligned} \tag{8}

其中 x~kκ=xkx^kκ\widetilde{\mathbf{x}}_k^{\kappa} = \mathbf{x}_k \boxminus \widehat{\mathbf{x}}_k^{\kappa}Hjκ\mathbf{H}_j^{\kappa}0=hj(x^kκx~kκ,Lnj)\mathbf{0} =\mathbf{h}_j\left(\widehat{\mathbf{x}}_k^{\kappa} \boxplus \widetilde{\mathbf{x}}_k^{\kappa},{ }^L \mathbf{n}_j\right)x~kκ\widetilde{\mathbf{x}}_k^{\kappa} 的雅可比矩阵,vjN(0,Rj)\mathbf{v}_j \in \mathcal{N}(\mathbf{0}, \mathbf{R}_j)zjκ\mathbf{z}_j^{\kappa} 为残差:

zjκ=hj(x^kκ,0)=GujT(GT^IkκIT^LkκLpjGqj)(9)\mathbf{z}_j^{\kappa} = \mathbf{h}_j(\widehat{\mathbf{x}}_k^{\kappa}, \mathbf{0}) = {}^G \mathbf{u}_j^T ({}^G \widehat{\mathbf{T}}_{I_k}^{\kappa} {}^I \widehat{\mathbf{T}}_{L_k}^{\kappa} {}^L \mathbf{p}_j - {}^G \mathbf{q}_j) \tag{9}

3.2.3 Iterated Update

x^k,P^k\widehat{\mathbf{x}}_k, \widehat{\mathbf{P}}_k 产生了一个先验高斯分布:

xkx^k=(x^kκx~kκ)x^k=x^kκx^k+Jκx~kκN(0,P^k)(10)\mathbf{x}_k \boxminus \widehat{\mathbf{x}}_k = (\widehat{\mathbf{x}}_k^{\kappa} \boxplus \widetilde{\mathbf{x}}_k^{\kappa}) \boxminus \widehat{\mathbf{x}}_k = \widehat{\mathbf{x}}_k^{\kappa} \boxminus \widehat{\mathbf{x}}_k + \mathbf{J}^{\kappa} \widetilde{\mathbf{x}}_k^{\kappa} \sim \mathcal{N}(\mathbf{0}, \widehat{\mathbf{P}}_k) \tag{10}

Jκ\mathbf{J}^{\kappa}(x^kκx~kκ)x^k(\widehat{\mathbf{x}}_k^{\kappa} \boxplus \widetilde{\mathbf{x}}_k^{\kappa}) \boxminus \widehat{\mathbf{x}}_kx~kκ\widetilde{\mathbf{x}}_k^{\kappa} 在 0 处的偏导:

Jκ=[A(δGθIk)T03×1503×303×3015×3I15×1503×303×303×303×15A(δIθLk)T03×303×303×1503×3I3×3](11)\mathbf{J}^\kappa=\left[\begin{array}{cccc} \mathbf{A}\left(\delta^G \boldsymbol{\theta}_{I_k}\right)^{-T} & \mathbf{0}_{3 \times 15} & \mathbf{0}_{3 \times 3} & \mathbf{0}_{3 \times 3} \\ \mathbf{0}_{15 \times 3} & \mathbf{I}_{15 \times 15} & \mathbf{0}_{3 \times 3} & \mathbf{0}_{3 \times 3} \\ \mathbf{0}_{3 \times 3} & \mathbf{0}_{3 \times 15} & \mathbf{A}\left(\delta^I \boldsymbol{\theta}_{L_k}\right)^{-T} & \mathbf{0}_{3 \times 3} \\ \mathbf{0}_{3 \times 3} & \mathbf{0}_{3 \times 15} & \mathbf{0}_{3 \times 3} & \mathbf{I}_{3 \times 3} \end{array}\right] \tag{11}

A()1\mathbf{A}(\cdot)^{-1} 的定义如附录 B,δGθIk=GR^IkκGR^Ik\delta {}^G \boldsymbol{\theta}_{I_k} = {}^G \widehat{\mathbf{R}}_{I_k}^{\kappa} \boxminus {}^G \widehat{\mathbf{R}}_{I_k}δIθLk=IR^LkκIR^Lk\delta {}^I \boldsymbol{\theta}_{L_k} = {}^I \widehat{\mathbf{R}}_{L_k}^{\kappa} \boxminus {}^I \widehat{\mathbf{R}}_{L_k} 是 IMU 的旋转外参。对于第一次迭代,有 x^kκ=x^k,Jκ=I\widehat{\mathbf{x}}_k^{\kappa} = \widehat{\mathbf{x}}_k, \mathbf{J}^{\kappa} = \mathbf{I}

对于先验分布,根据测量 (8) 可以得到状态分布:

vj=zjκ+Hjκx~kκN(0,Rj)(12)- \mathbf{v}_j = \mathbf{z}_j^\kappa + \mathbf{H}_j^\kappa \widetilde{\mathbf{x}}_k^\kappa \sim \mathcal{N}(\mathbf{0}, \mathbf{R}_j) \tag{12}

联合 (10) 和 (12) 得到状态 xk\mathbf{x}_k 的后验分布,等价于表示为 x~k\widetilde{\mathbf{x}}_k 的最大后验估计:

minx~kκ(xkx^kP^k2+j=1mzjκ+Hjκx~kκRj2)(13)\min_{\widetilde{\mathbf{x}}_k^{\kappa}} \left( \| \mathbf{x}_k \boxminus \widehat{\mathbf{x}}_k \|^2_{\widehat{\mathbf{P}}_k} + \sum_{j=1}^m \| \mathbf{z}_j^{\kappa} + \mathbf{H}_j^{\kappa} \widetilde{\mathbf{x}}_k^{\kappa} \|^2_{\mathbf{R}_j} \right) \tag{13}

MAP 问题可以通过卡尔曼滤波解决(取 H=[H1κ,,Hmκ]T\mathbf{H} = [\mathbf{H}_1^{\kappa}, \dots, \mathbf{H}_m^{\kappa}]^TR=diag(R1,,Rm)\mathbf{R} = \operatorname{diag}(\mathbf{R}_1, \dots, \mathbf{R}_m)P=(Jκ)1P^k(Jκ)T\mathbf{P} = (\mathbf{J^{\kappa}})^{-1} \widehat{\mathbf{P}}_k (\mathbf{J}^{\kappa})^{-T}zkκ=[z1κT,,zmκT]T\mathbf{z}_k^{\kappa} = [{\mathbf{z}_1^{\kappa}}^T, \dots, {\mathbf{z}_m^{\kappa}}^T]^T):

K=(HTR1H+P1)1HTR1x^kκ+1=x^kκ(Kzkκ(IKH)(Jκ)1(x^kκx^k))(14)\begin{aligned} &\mathbf{K} = (\mathbf{H}^T \mathbf{R}^{-1} \mathbf{H} + \mathbf{P}^{-1})^{-1} \mathbf{H}^T \mathbf{R}^{-1} \\ &\widehat{\mathbf{x}}_k^{\kappa+1} = \widehat{\mathbf{x}}_k^{\kappa} \boxplus \left(- \mathbf{K} \mathbf{z}_k^{\kappa} - (\mathbf{I} - \mathbf{KH})(\mathbf{J}^{\kappa})^{-1}(\widehat{\mathbf{x}}_k^{\kappa} \boxminus \widehat{\mathbf{x}}_k) \right) \end{aligned} \tag{14}

迭代上述过程至收敛后,优化的状态和协方差为:

x^k=x^kκ+1,P^k=(IKH)P(15)\widehat{\mathbf{x}}_k = \widehat{\mathbf{x}}_k^{\kappa+1}, \widehat{\mathbf{P}}_k = (\mathbf{I} - \mathbf{KH}) \mathbf{P} \tag{15}

透过优化状态,可以将第 kk 个扫描的 LiDAR 点 Lpj{}^L \mathbf{p}_j 投影到世界坐标系:

Gpˉj=GTˉIkITˉLkLpj;j=1,...,m(16){}^G \bar{\mathbf{p}}_j = {}^G \bar{\mathbf{T}}_{I_k} {}^I \bar{\mathbf{T}}_{L_k} {}^L \mathbf{p}_j; \quad j = 1, ..., m \tag{16}

转换后的点集 {Gpˉj}\lbrace {}^G \bar{\mathbf{p}}_j \rbrace 被插入到 ikd-Tree 管理的地图中。

整个状态估计算法如下:

4 Mapping

4.1 Map Management

地图点被组织成 ikd-Tree,通过合并新的点云扫描来动态增长。为防止地图尺寸失控,ikd-Tree 只保留 LiDAR 当前位置周围一个长度 LL 的局部区域内的地图点,如图-3。

将地图区域初始化为长度 LL 的立方体,以初始 LiDAR 位置 p0\mathbf{p}_0 为中心。假设 LiDAR 的检测区域是以 (15) 得到的 LiDAR 当前位置为中心的检测球,球半径 r=γRr = \gamma RRR 是 LiDAR 的视场范围,γ\gamma 是大于 1 的松弛参数。

当 LiDAR 移动到新位置 p\mathbf{p}^{\prime}(检测球此时到达了地图区域的边缘)时,地图区域向 LiDAR 检测球与地图边界之间距离增加的方向移动。地图区域移动的距离设置为常数 d=(γ1)Rd = (\gamma−1)R

对于新的地图区域和旧的地图区域之间的差值区域,所有的点都将通过 4.3 中的算法-3 从 ikd-Tree 中删除。

4.2 Tree Structure and Construction

4.2.1 Data Structure

ikd-Tree 为二叉搜索树,数据结构如下:

由于点对应于 ikd-Tree 中的单个节点:

  • 点的信息(如点坐标、强度)存储在 point 中。leftchildrightchild 是指向左右子节点的指针。
  • 用于分割空间的分割轴存储在 axis 中。
  • 根在当前节点的(子)树的节点数(包括有效节点和无效节点)保存在 treesize 中。
  • 当从地图中删除点时,这些节点不会立即从树中删除,只将 deleted 设为 true。
  • 如果根在当前节点的整个(子)树被删除,则 treedeleted 设为 true。
  • 从(子)树中删除的点数为 invalidnum
  • range 存储(子)树上点的范围信息,解释为一个包含所有点的轴向外接长方体。

4.2.2 Construction

ikd-Tree 的构建过程与构建 KD 树类似。ikd-Tree 沿着最长维度递归地在中点对空间进行分割,直到子空间中只剩下一个点。在构造过程中对数据结构中的属性进行初始化,包括计算树的大小和(子)树的范围信息。

4.3 Incremental Updates

ikd-Tree 支持两种增量操作:逐点操作和逐框(box-wise)操作:

  • 逐点操作在 KD 树之间插入、删除或重新插入单个点;
  • 逐框操作在给定的轴对齐长方体中插入、删除或重新插入所有点。

4.3.1 Point Insertion with On-tree Downsampling

ikd-Tree 支持点插入和地图下采样,具体算法见算法-2。

对于从算法-1 得到的点 p{Gpˉj}\mathbf{p} \in \lbrace{}^G \bar{\mathbf{p}}_j \rbrace 和下采样分辨率 ll,算法将空间平均分为长度为 ll 的立方,找到包含 p\mathbf{p} 的立方 CD\mathbf{C}_D(第 2 行)。算法只保留靠近 CD\mathbf{C}_D 的中心 pcenter\mathbf{p}_{center} 的点:先在 KD 树中找到 CD\mathbf{C}_D 内的所有点并存到堆 VV 中,同时 VV 中存入 p\mathbf{p};然后找到 VV 中与 pcenter\mathbf{p}_{center} 最近的点;接着删除 CD\mathbf{C}_D 中的点并在 KD 树中插入最近点 pnearest\mathbf{p}_{nearest}BoxwiseSearch 类似于算法-3 的 BoxwiseDelete

ikd-Tree 上的点插入(第 11-24 行)递归实现,算法从根节点开始向下搜索,直到找到一个空节点来添加新节点(第 12-14 行)。新叶节点的初始化如表-1:

访问过的节点的属性(如 treesizerange)会被更新(第 21 行)。对于更新后的子树,检查并维护平衡(第 22 行),以保持 ikd-Tree 的平衡性(参见 4.4)。

4.3.2 Box-wise Delete using Lazy Labels

通过设置节点属性 deleted 为 true 来标记点删除,实现“懒”删除。如果根为 TT 的子树的所有节点都被删除,则 TTtreedeleted 标记为 true。deletedtreedeleted 为“懒”标签。被标记为“deleted”的节点会在树的重建过程删除(参见 4.4)。

使用属性 range(长方体 CT\mathbf{C}_T)和懒标签完成逐框删除,如算法-3:

给定根在 TT 的(子)树上要删除的点的长方体 CO\mathbf{C}_O,算法递归的向下搜索:

  • 如果 CT\mathbf{C}_TCO\mathbf{C}_O 不相交,则终止递归;
  • 如果 CTCO\mathbf{C}_T \subseteq \mathbf{C}_O,则将 deletedtreedeleted 标记为 true,且此时节点为根的子树的所有点被删除,因此 invalidnum 的值为树的大小;
  • 当不满足上述两种情况,则当前点 p\mathbf{p}(如果在 CO\mathbf{C}_O 中)首次被删除,然后算法递归进入该点的子树。

4.3.3 Attribute Update

完成增量操作后,使用函数 AttributeUpdate 进行属性更新。该函数通过汇总当前节点的子节点的相关信息完成更新。range 的更新通过合并子节点和当前节点的信息完成。如果当前节点的子节点的 treedeleted 都为 true 且当前节点的 deleted 为 true,则当前节点的 treedeleted 设为 true。

4.4 Re-balancing

每次增量操作后,ikd-Tree 通过重建相关子树重建树平衡。

4.4.1 Balancing Criterion

平衡准则包含 α\alpha-平衡准则和 α\alpha-删除准则:

  • 假设一个 ikd-Tree 的子树根为 TT,则该子树是 α\alpha-平衡的当切仅当:

    S(T.leftchild)<αbal(S(T)1)S(T.rightchild)<αbal(s(T)1)(17)\begin{aligned} S(T.leftchild) &< \alpha_{bal}\left( S(T) - 1 \right) \newline S(T.rightchild) &< \alpha_{bal}\left( s(T) - 1 \right) \end{aligned} \tag{17}

    其中 αbal(0.5,1)\alpha_{bal} \in (0.5, 1)S(T)S(T) 为节点 TTtreesize

  • 根为 TT 的子树的 α\alpha-删除准则为:

    I(T)<αdelS(T)(18)I(T) < \alpha_{del}S(T) \tag{18}

    其中 αdel(0,1)\alpha_{del} \in (0, 1)I(T)I(T) 为节点 TTinvalidnum

如果 ikd-Tree 的子树满足上述两个准则,则子树是平衡的;如果所有子树都是平衡的,则整棵树是平衡的。

违反任何一个准则都会触发重建过程:

  • α\alpha-平衡准则保持树的最大高度。树的最大高度为 log1/αbal(n)\log 1/ \alpha_{bal} (n),其中 nn 是树的大小;
  • α\alpha-删除准则确保删除子树上标记为“deleted”的节点。

4.4.2 Re-build & Parallel Re-build

如图-4,假设在子树 T\mathcal{T} 上触发重建:

子树首先被展开为点列 VV,标记为“deleted”的节点在展开过程中被丢弃。然后,以 VV 中的所有点为剖面,构建一棵新的完全平衡 KD 树(使用两个线程完成重建)。算法-4 给出重建方法:

当打破平衡准则,子树大小小于阈值 NmaxN_{\max} 时,在主线程中重建子树;否则,子树将在第二个线程中重新构建。

第二个线程的重建如 ParRebuild 函数(将第二个线程中要重建的子树表示为 T\mathcal{T},其根节点为 TT):

  1. 线程锁住所有增量更新(点插入和删除),但不锁住查询(第 12 行)。
  2. 将子树 T\mathcal{T} 中包含的所有有效点复制到点数组 VV 中,同时保持原始子树不变,以便可能的查询(第 13 行)。
  3. 展开之后,原子树被解锁,以便主线程接受增量更新请求(第 14 行),这些请求将记录在 operation logger 的队列中。
  4. 一旦线程完成从 VV 构建新的 KD 树 T\mathcal{T}^{\prime}(第 15 行),记录下的更新请求将通过 IncrementalUpdates 再次对 T\mathcal{T}^{\prime} 执行(第 16-18 行)。注意,并行重建开关被设置为 false。
  5. 所有请求处理完后,原子树 T\mathcal{T} 上的点信息与新子树 T\mathcal{T}^{\prime} 相同,只是新子树更平衡。线程从增量更新和查询中锁住节点 TT,并将其替换为新的节点 TT^{\prime}(第 20-22 行)。
  6. 最后,释放原子树的内存(第 23 行)。

注意,LockUpdates 不会阻塞查询,查询可以在主线程中并行执行;LockAll 阻塞所有的访问,包括查询。LockUpdatesLockAll 通过互斥(mutex)实现。

利用节点上的范围信息,通过 [3] 中介绍的“bounds-overlap-ball”测试,加快最近邻搜索的速度。维护一个优先队列 q 来存储到目前遇到的 kk 个最近邻以及它们到目标点的距离。从根节点开始向下递归搜索时,首先计算目标点到树节点的长方体 CT\mathbf{C}_T 的最小距离 dmind_{\min},如果 dmind_{\min} 不小于 q 中的最大距离,则不需要处理该节点及其子节点。

此外,在 FAST-LIO2 中,只有当近邻点在目标点周围的给定阈值内时才被视为内点用于状态估计,这为 kk 近邻的远距搜索提供了最大搜索范围。

ikd-Tree 支持多线程的 kk 近邻搜索。

4.6 Time Complexity Analysis

4.6.1 Incremental Operations

由于树上下采样的插入依赖于逐框删除和逐框搜索,因此首先讨论逐框操作。设 nn 为 ikd-Tree 的大小,则逐框操作时间复杂度为:

**定理-1:**设 ikd-Tree 上的点在空间 Sx×Sy×SzS_x \times S_y \times S_z 内,操作的长方体 CD=Lx×Ly×Lz\mathbf{C}_D = L_x \times L_y \times L_z,则算法-3 的时间复杂度为:

O(H(n))={O(logn) if Δminα(23)()O(n1abc) if Δmax1α(13)()O(nα(13)ΔminΔmed) if () and () fail and Δmed <α(13)α(23)O(nα(23)Δmin) otherwise. (19)O(H(n))= \begin{cases}O(\log n) & \text { if } \Delta_{\min } \geqslant \alpha\left(\frac{2}{3}\right)\left({ }^*\right) \\ O\left(n^{1-a-b-c}\right) & \text { if } \Delta_{\max } \leqslant 1-\alpha\left(\frac{1}{3}\right)(* *) \\ O\left(n^{\alpha\left(\frac{1}{3}\right)-\Delta_{\min }-\Delta_{\operatorname{med}}}\right) & \text { if }\left(^*\right) \text { and }(* *) \text { fail and } \\ & \Delta_{\text {med }}<\alpha\left(\frac{1}{3}\right)-\alpha\left(\frac{2}{3}\right) \\ O\left(n^{\alpha\left(\frac{2}{3}\right)-\Delta_{\min }}\right) & \text { otherwise. }\end{cases} \tag{19}

其中 a=lognSxLx,b=lognSyLy,c=lognSzLza = \log_n \frac{S_x}{L_x}, b = \log_n \frac{S_y}{L_y}, c = \log_n \frac{S_z}{L_z}a,b,c0a, b, c \ge 0Δmin,Δmed,Δmax\Delta_{\min}, \Delta_{\text{med}}, \Delta_{\max}a,b,ca, b, c 的最小、中间、最大值。α(u)\alpha(u) 为 flajolet-puech 函数,u[0,1],α(13)=0.7162,α(23)=0.3949u \in [0, 1], \alpha(\frac{1}{3}) = 0.7162, \alpha(\frac{2}{3}) = 0.3949

树上下采样的插入时间复杂度为:

**定理-2:**算法-2 的时间复杂度为 O(logn)O(\log n)

4.6.2 Re-build

单线程重建的时间复杂度为:O(nlogn)O(n \log n)

双线程并行重建的时间复杂度为:O(n)O(n)

ikd-Tree 上执行 kk 近邻搜索的时间复杂度为:O(logn)O(\log n)

5 Benchmark Results

5.1 Implementation

  • ROS,C++
  • 迭代卡尔曼滤波器基于 IKFOM
  • 局部地图的大小 L=1000mL = 1000 \text{m},LiDAR 原始点在 1:4 (四分之一的 LiDAR 点)的时间下采样后直接输入到状态估计中
  • 算法-2 中 l=0.5ml = 0.5\text{m}
  • ikd-Tree 的参数 αbal=0.6,αdel=0.5,Nmax=1500\alpha_{bal} = 0.6, \alpha_{del} = 0.5, N_{\max} = 1500
  • 实验平台:
    • DJI Manifold 2-C7{}^7:i7-8550U 1.8 GHz,8 GB RAM
    • Khadas VIM38{}^8(ARM 平台):Cortex-A73 2.2 GHz,4 GB RAM

5.2 Data Structure Evaluation

5.3 Accuracy Evaluation

对比 L=2000m,1000m,800m,600mL = 2000\text{m}, 1000\text{m}, 800\text{m}, 600\text{m} 的实验结果,“Feature”表示使用基于 FAST-LIO 和 BALM[4] 的特征提取方法。

6 Real-World Experiments

6.1 Platforms

6.2 Private Dataset

6.3 Outdoor Aerial Experiment

参考

  • [1] W. Xu and F. Zhang, “Fast-lio: A fast, robust lidar-inertial odometry package by tightly-coupled iterated kalman filter,” IEEE Robotics and Automation Letters, pp. 1–1, 2021.
  • [2] D. He, W. Xu, and F. Zhang, “Embedding manifold structures into kalman filters,” arXiv preprint arXiv:2102.03804, 2021.
  • [3] J. H. Friedman, J. L. Bentley, and R. A. Finkel, “an algorithm for finding best matches in logarithmic expected time,” ACM Transactions on Mathematical Software (TOMS), vol. 3, no. 3, pp. 209–226, 1977.
  • [4] Z. Liu and F. Zhang, “Balm: Bundle adjustment for lidar mapping,” IEEE Robotics and Automation Letters, vol. 6, no. 2, pp. 3184–3191, 2021.

附录

A 两种运算

M\mathcal{M} 是考虑的维数 nn 的流形(例如 M=SO(3)\mathcal{M}=SO(3))。由于流形是 Rn\mathbf{R}_n 的局部同胚,因此可以通过两个封装算子 /\boxplus / \boxminus 建立从 M\mathcal{M} 上的局部邻域到其切空间 RnRnRn\mathbf{R}_n 的双射映射:

:M×RnM;:M×MRnMSO(3):Rr=RExp(r);R1R2=Log(R2TR1)MRn:ab=a+b;ab=ab(A-1)\begin{matrix} \boxplus: \mathcal{M} \times \mathbb{R}^n \rightarrow \mathcal{M}; \quad \boxminus: \mathcal{M \times M} \rightarrow \mathbb{R}^n \\ \mathcal{M} \in SO(3): \mathbf{R \boxplus r = R} \operatorname{Exp}(\mathbf{r}); \quad \mathbf{R}_1 \boxminus \mathbf{R}_2 = \operatorname{Log}(\mathbf{R}_2^T \mathbf{R}_1) \\ \mathcal{M} \in \mathbb{R}^n: \mathbf{a \boxplus b} = \mathbf{a} + \mathbf{b}; \quad \mathbf{a \boxminus b} = \mathbf{a} - \mathbf{b} \end{matrix} \tag{A-1}

对于复合流形 MSO(3)×Rn\mathcal{M} \in SO(3) \times \mathbb{R}^n,则有:

[Ra][rb]=[Rra+b],[R1a][R2b]=[R1R1ab](A-2)\left[ \begin{matrix} \mathbf{R} \\ \mathbf{a} \end{matrix} \right] \boxplus \left[ \begin{matrix} \mathbf{r} \\ \mathbf{b} \end{matrix} \right] = \left[ \begin{matrix} \mathbf{R \boxplus r} \\ \mathbf{a + b} \end{matrix} \right] , \quad \left[ \begin{matrix} \mathbf{R}_1 \\ \mathbf{a} \end{matrix} \right] \boxminus \left[ \begin{matrix} \mathbf{R}_2 \\ \mathbf{b} \end{matrix} \right] = \left[ \begin{matrix} \mathbf{R}_1 \boxminus \mathbf{R}_1 \\ \mathbf{a} - \mathbf{b} \end{matrix} \right] \tag{A-2}

易验证:

(xu)x=u,x(yx)=y;x,yM,uRn(A-3)(\mathbf{x} \boxplus \mathbf{u}) \boxminus \mathbf{x} = \mathbf{u}, \mathbf{x} \boxplus (\mathbf{y} \boxminus \mathbf{x}) = \mathbf{y}; \forall \mathbf{x}, \mathbf{y} \in \mathcal{M}, \mathbf{u} \in \mathbb{R}^n \tag{A-3}

B FAST-LIO 中的偏导算子 A()1\mathbf{A}(\cdot)^{-1}

A()1\mathbf{A}(\cdot)^{-1},有如下定义:

A(u)1=I12u+(1α(u))uΛ2u2α(m)=m2cot(m2)=m2cos(m/2)sin(m/2)(B-1)\begin{aligned} \mathbf{A}(\mathbf{u})^{-1} & =\mathbf{I}-\frac{1}{2}\lfloor\mathbf{u}\rfloor_{\wedge}+(1-\boldsymbol{\alpha}(\|\mathbf{u}\|)) \frac{\lfloor\mathbf{u}\rfloor_{\Lambda}^2}{\|\mathbf{u}\|^2} \\ \alpha(\mathrm{m}) & =\frac{\mathrm{m}}{2} \cot \left(\frac{\mathrm{m}}{2}\right)=\frac{\mathrm{m}}{2} \frac{\cos (\mathrm{m} / 2)}{\sin (\mathrm{m} / 2)} \end{aligned} \tag{B-1}