Part IV · 第 15 章 状态估计与建图 · 15.2Part IV · Ch. 15 State Estimation & Mapping · 15.2

SLAM 与位姿图SLAM & Pose Graphs

要建地图,得知道自己在哪;要知道自己在哪,又得有地图。SLAM(同时定位与建图)把两者当成一个估计问题一起解。本节在浏览器里跑一个真正的二维激光 SLAM:里程计边、ICP 验证的回环、SE(2) 上的位姿图优化;再看它的两位前辈 EKF-SLAM 和 FastSLAM 为什么被取代,错误回环怎样毁掉地图、鲁棒核怎样救回来,以及 iSAM2 这样的增量求解器每一步到底要重算多少。 To build a map you must know where you are; to know where you are you need a map. SLAM (simultaneous localization and mapping) solves both as one estimation problem. This lesson runs a genuine 2D lidar SLAM in your browser: odometry edges, ICP-verified loop closures and pose-graph optimization on SE(2). Then it shows why its two predecessors, EKF-SLAM and FastSLAM, were superseded, how a false loop closure wrecks a map and a robust kernel saves it, and how much an incremental solver such as iSAM2 really recomputes at each step.

约 50 分钟~50 min 前置:6.9 非线性最小二乘与因子图 · 6.10 流形优化 · 4.8 卡尔曼滤波与 EKF · 4.10 粒子滤波 · 12.1 点云与 ICP · 11.5 特征匹配与 RANSACPrereqs: 6.9 Nonlinear least squares & factor graphs · 6.10 Optimization on manifolds · 4.8 Kalman filter & EKF · 4.10 Particle filter · 12.1 Point clouds & ICP · 11.5 Feature matching & RANSAC 6 个交互6 interactives

    1为什么机器人需要它Why robots need this

    把一台扫地机器人放进一套从没见过的公寓。它要规划清扫路线,就需要一张地图;它要把每一帧激光扫描拼进地图,又必须知道这一帧是在哪里扫的。4.8 节的 EKF 定位假设地图已知,12.1 节的 ICP 和 15.1 节的视觉惯性里程计只估计相邻两帧之间的相对运动。前者需要地图,后者没有地图也能工作,可是误差会一直累积:每一步的小误差叠加起来,走得越远偏得越多,而且永远不会自己变小。

    SLAM(Simultaneous Localization And Mapping,同时定位与建图)的做法是把机器人的整条轨迹和地图当作同一组未知数一起估计。关键在于回环:机器人回到以前到过的地方并认出来时,就得到一条连接“现在”和“很久以前”的测量。这一条测量足以把一路积累的漂移拉回来,并把修正分摊到整条轨迹上。

    现代 SLAM 几乎都写成6.9 节的因子图最小二乘:变量是一串机器人位姿,因子是里程计和回环。6.9 节的 FIG 3 已经在 24 个位姿的圆上演示过回环怎样修正漂移。本节再往前走四步:(1) 一个完整的系统,前端从真实的激光扫描里自己找回环(地点识别加 ICP 验证),后端在 \(\mathrm{SE}(2)\) 上优化位姿图;(2) 两种更早的方法 EKF-SLAM 和 FastSLAM,以及它们各自卡在哪里;(3) 错误回环和鲁棒核;(4) 增量求解:机器人每走一步,求解器到底要重算多少。

    Put a robot vacuum into an apartment it has never seen. To plan a cleaning route it needs a map; to stitch each lidar scan into that map it must know where the scan was taken. The EKF localization of Lesson 4.8 assumes the map is known. The ICP of Lesson 12.1 and the visual-inertial odometry of Lesson 15.1 only estimate the motion between neighbouring frames. The first needs a map; the second works without one, but its errors keep adding up: small errors at every step accumulate, the further the robot drives the further off it is, and the error never shrinks on its own.

    SLAM (simultaneous localization and mapping) estimates the robot's whole trajectory and the map together, as one set of unknowns. The key is the loop closure: when the robot comes back to a place it has visited and recognizes it, it gains a measurement linking "now" with "long ago". That single measurement is enough to pull back the drift accumulated on the way and to spread the correction over the whole trajectory.

    Almost all modern SLAM is written as the factor-graph least squares of Lesson 6.9: the variables are a chain of robot poses, the factors are odometry and loop closures. FIG 3 of Lesson 6.9 already showed on a circle of 24 poses how a loop closure fixes drift. This lesson goes four steps further: (1) a complete system, whose front end finds loop closures by itself in real lidar scans (place recognition plus ICP verification) and whose back end optimizes the pose graph on \(\mathrm{SE}(2)\); (2) two older methods, EKF-SLAM and FastSLAM, and where each one gets stuck; (3) false loop closures and robust kernels; (4) incremental solving: how much the solver really has to recompute at every step.

    2直觉:地图只和位姿一样准Intuition: a map is only as good as its poses

    下面是一个 24 m × 14 m 的室内环境:外墙、两个大的方块障碍,以及墙边一些小箱子。机器人沿“8”字形路线走一圈,共约 77 m,每走 0.8 m 记一帧 360° 激光扫描(180 束,测距噪声 2 cm),一共 92 帧。扫描本身很准,问题全出在“把扫描放到哪里”。如果用真实位姿拼,得到的地图和真实墙壁严丝合缝;如果只能用轮式里程计算出的位姿拼,每一帧都放在一个略有偏差的位置上。

    这里的里程计有两类误差:随机噪声(每一步都不同),以及航向偏差:每走一米,航向多算一个固定的小角度,比如两个轮子的半径差了一点点就会这样(9.1 节)。航向误差最致命,因为它会被距离放大:航向偏了 \(\delta\theta\),之后每走一米就多出约 \(\delta\theta\) 米的横向误差。

    Below is a 24 m × 14 m indoor environment: outer walls, two large blocks, and a few small boxes along the walls. The robot drives a figure-eight route of about 77 m and records a 360° lidar scan (180 beams, 2 cm range noise) every 0.8 m, 92 scans in all. The scans themselves are accurate; the whole problem is where to put them. Stitched at the true poses, the map matches the real walls exactly; stitched at the poses computed from wheel odometry, every scan lands in a slightly wrong place.

    The odometry here has two kinds of error: random noise (different at every step) and a heading bias: every metre driven adds a small fixed angle to the heading, as happens when the two wheel radii differ slightly (Lesson 9.1). Heading error is the most damaging, because distance amplifies it: a heading off by \(\delta\theta\) adds about \(\delta\theta\) metres of lateral error for every metre driven afterwards.

    FIG 1用里程计拼地图:墙壁会出现重影A map stitched from odometry: the walls appear twice
    灰线是真实的墙(只在这个仿真里知道),青色点是把截至当前时刻的扫描放到所选位姿上得到的地图。紫色虚线和空心紫色三角是真实轨迹与真实位姿,红线和实心红色三角是里程计推算的轨迹与位姿,绿点是起点。拖动“时间”看地图怎样一帧一帧长出来;默认航向偏差 0.2°/m。 Grey lines are the true walls (known only in this simulation); cyan dots are the map obtained by placing every scan up to the current time at the chosen poses. The dashed purple line and the hollow purple triangle are the true trajectory and pose; the red line and the filled red triangle are the trajectory and pose computed by odometry; the green dot is the start. Drag "time" to watch the map grow scan by scan; the default heading bias is 0.2°/m.
    试一试Try this
    • 保持“用里程计位姿拼图”,把时间拖到 98% 以上:机器人回到起点附近时,里程计的位置误差超过 1 m(默认设置下约 1.9 m,途中最大约 3.2 m),起点那段走廊的墙出现了两份。再切到“用真实位姿拼图”对比。Keep "place scans at odometry poses" and drag the time beyond 98%: by the time the robot is back near the start the odometry position error exceeds 1 m (about 1.9 m with the defaults, about 3.2 m at worst on the way), and the walls of the start corridor appear twice. Then switch to "place scans at true poses" to compare.

    几个值得试的设置:把航向偏差和随机噪声都调成 0,地图和真实一模一样;只去掉噪声、保留 0.2°/m 的偏差,终点误差仍有 1.4 m:系统误差和随机误差一样有害。偏差调成负值,地图向另一侧弯。还要注意:误差并不是单调增长的,在“8”字路线上,往一个方向转弯造成的误差,有一部分会被反方向的转弯抵消,所以中途的最大误差比终点大。

    Settings worth trying: set both the heading bias and the random noise to 0 and the map is perfect; remove only the noise but keep the 0.2°/m bias and the end error is still 1.4 m: systematic error hurts as much as random error. Make the bias negative and the map bends the other way. Notice too that the error does not grow monotonically: on a figure-eight, part of the error caused by turning one way is undone by turning the other way, which is why the worst error on the way is larger than the error at the end.

    核心洞见Key insight

    地图误差和位姿误差是同一回事:每一帧扫描都是在机器人坐标系里测的,它在世界里的位置完全取决于那一刻的位姿估计。所以 SLAM 不应该先定位、再建图,而是把轨迹和地图一起估计。估计时,一条把“现在”和“以前”连起来的测量(回环)比一百条相邻帧的测量更有用,因为只有它能约束累积下来的漂移。

    Map error and pose error are the same thing: every scan is measured in the robot frame, and where it ends up in the world depends entirely on the pose estimate at that moment. So SLAM should not localize first and map second; it estimates the trajectory and the map together. In that estimate, one measurement linking "now" with "before" (a loop closure) is worth more than a hundred measurements between neighbouring frames, because only it constrains the accumulated drift.

    3动手:一个真正在跑的二维激光 SLAMPlay: a 2D lidar SLAM that really runs

    下图用的是 FIG 1 的同一个世界、同一条路线、同样的扫描,跑的是一个完整的、简化但不作弊的位姿图 SLAM。系统分两部分:

    前端(从传感器数据里造出约束):每 0.8 m 建一个关键帧,即一个位姿变量 \(X_k\),并附上这一帧的扫描。相邻关键帧之间加一条里程计边,测量值是轮式里程计给出的相对位姿。然后做地点识别:在当前估计里,找出离新关键帧不到“搜索半径”、且至少早 20 帧的旧关键帧(最近的 2 个),把两帧扫描用 ICP 对齐。初值来自当前估计,并且再从 ±10° 的航向各试一次。对齐之后,用点到线距离检查:至少 75% 的点落在对方扫描 10 cm 以内、且这些点的 RMS 距离小于 5 cm,才接受为一条回环边,测量值就是 ICP 的结果。

    后端(把所有约束一起满足):每加入一条回环,就从当前估计出发做 Gauss-Newton(最多 10 次迭代,代价上升时加一点 LM 阻尼),把第一个位姿固定为规范(6.9 节)。新关键帧的初值,是把里程计接在上一个关键帧的当前估计后面得到的。地图不单独存储:每次都由“各关键帧的扫描放在各自的估计位姿上”重新画出来,所以位姿一被修正,地图也跟着修正。

    The figure below uses the same world, route and scans as FIG 1 and runs a complete pose-graph SLAM, simplified but with no shortcuts. It has two parts:

    The front end (turning sensor data into constraints): every 0.8 m it creates a keyframe, a pose variable \(X_k\) with that moment's scan attached. Consecutive keyframes get an odometry edge whose measurement is the relative pose reported by wheel odometry. Then comes place recognition: in the current estimate it looks for older keyframes (at least 20 frames back, the 2 nearest) within the "search radius" of the new keyframe and aligns the two scans with ICP, starting from the current estimate and also from headings turned by ±10°. After alignment a point-to-line check decides: only if at least 75% of the points lie within 10 cm of the other scan and their RMS distance is below 5 cm is the result accepted as a loop-closure edge, with the ICP result as its measurement.

    The back end (satisfying all constraints together): every new loop closure triggers Gauss-Newton from the current estimate (at most 10 iterations, with a little LM damping if the cost rises), with the first pose held fixed as the gauge (Lesson 6.9). A new keyframe is initialized by attaching its odometry to the current estimate of the previous keyframe. The map is not stored separately: it is redrawn every time from "each keyframe's scan placed at that keyframe's estimated pose", so when the poses are corrected, the map is corrected with them.

    FIG 2位姿图 SLAM:里程计边、ICP 回环、SE(2) 上的 Gauss-NewtonPose-graph SLAM: odometry edges, ICP loop closures, Gauss-Newton on SE(2)
    灰线是真实的墙。琥珀色是 SLAM 的估计:粗线穿过各关键帧(“位姿图”视图里每个关键帧画成一个点),实心琥珀三角是当前位姿;“地图”视图里青色点是放在估计位姿上的扫描;“不确定度”视图给出每个关键帧的 2σ 位置椭圆(由 \(H^{-1}\) 的对角块算出)。绿线是被接受的回环边,绿点标出最近一次回环。红线是纯里程计轨迹,紫色虚线和空心紫色三角是真实轨迹与位姿。右上图是每个关键帧的位置误差:红为纯里程计,琥珀为当前 SLAM 估计(整条线会在回环后一起改变),底部绿色短线标出回环发生的关键帧。 Grey lines are the true walls. Amber is the SLAM estimate: the thick line runs through the keyframes (drawn as dots in the "pose graph" view), and the filled amber triangle is the current pose; in the "map" view the cyan dots are the scans placed at the estimated poses; the "uncertainty" view adds each keyframe's 2σ position ellipse (from the diagonal blocks of \(H^{-1}\)). Green lines are accepted loop-closure edges, and a green dot marks the latest one. The red line is pure odometry; the dashed purple line and the hollow purple triangle are the true trajectory and pose. The plot at the top right is the position error of each keyframe: red for pure odometry, amber for the current SLAM estimate (the whole line changes after a loop closure); short green ticks at the bottom mark the keyframes where closures happened.
    • 保持默认设置按“运行”走完全程。约到路线 60%(关键帧 55,回到中间走廊)时第一次回环出现,当前位姿误差从约 1.1 m 一下子降到约 0.1 m;全程结束时 SLAM 的 RMS 误差约 0.07 m,而纯里程计是 1.5 m。(完成条件:回环开启、走完全程、SLAM 误差低于里程计的 60%。)Keep the defaults and press "Run" to the end. At about 60% of the route (keyframe 55, back in the middle corridor) the first loop closure arrives and the current pose error drops at once from about 1.1 m to about 0.1 m; at the end the SLAM RMS error is about 0.07 m, against 1.5 m for pure odometry. (Completes when closures are on, the route is finished and the SLAM error is below 60% of the odometry error.)
    • 切到“不确定度”视图,重置后运行:回环之前,椭圆沿路线越来越大;第一次回环的那一刻,最新关键帧的 σ 缩小超过三分之一(默认设置下从约 0.75 m 降到约 0.32 m)。Switch to the "uncertainty" view, reset and run: before the loop closure the ellipses grow along the route; at the moment of the first closure the newest keyframe's σ shrinks by more than a third (from about 0.75 m to about 0.32 m with the defaults).
    • 把航向偏差调到 0.55°/m 以上再走完全程(回环开启):一条回环也找不到。漂移出的航向误差太大(回到中间走廊时已超过 20°),ICP 从这样的初值收敛不到正确的对齐,验证全部失败,地图保持重影。把搜索半径加到 6 m 也无济于事。(默认噪声下,从约 0.35°/m 起回环就已经一条都找不到了。)Set the heading bias to 0.55°/m or more and finish the route (closures on): not a single loop closure is found. The drifted heading is too far off (more than 20° by the time the robot is back in the middle corridor), ICP cannot converge to the right alignment from such a start, every verification fails, and the map stays doubled. Widening the search radius to 6 m does not help. (With the default noise, closures already stop entirely from about 0.35°/m.)
    有意思的细节Things worth noticing

    (1) 回环一旦出现,往往是成串的:机器人沿着走过的走廊又走了一段,于是连续十几个关键帧都和旧帧对上(默认设置下全程 23 条回环)。第一条做大修正,后面的只做微调。(2) 回环把误差拉下来的同时,也改写了过去:右上图里整条琥珀线都往下掉,而不只是当前这一点。这正是平滑(smoothing,估计整条轨迹)和滤波(只估计当前状态)的区别。(3) 默认设置下的 49 次 ICP 验证里有 5 次被拒绝,被接受的回环与真实相对位姿的偏差都在 7 cm 以内:这个前端宁可错过,也不乱接,下面第 5 节会看到乱接的代价。

    (1) Loop closures tend to come in runs: the robot drives along a corridor it has driven before, so a dozen consecutive keyframes in a row match old ones (23 closures over the whole route with the defaults). The first one makes the big correction; the rest only fine-tune. (2) As the closure pulls the error down, it also rewrites the past: in the top-right plot the whole amber line drops, not just the current point. That is the difference between smoothing (estimating the whole trajectory) and filtering (estimating only the current state). (3) Of the 49 ICP verifications with the defaults, 5 are rejected, and every accepted closure is within 7 cm of the true relative pose: this front end would rather miss a closure than accept a wrong one, and Section 5 shows what a wrong one costs.

    4另外两个视角:把 SLAM 当成滤波Two more views: SLAM as a filter

    位姿图是 2000 年代后期才成为主流的。在那之前,SLAM 主要按 4.7 节的贝叶斯滤波来做:只估计当前位姿和地图,旧位姿一到就“边缘化”掉。下面两个实验用同一个场景:18 个点状路标,机器人沿 14 m × 9 m 的椭圆以 1 m/s 逆时针走两圈(约 76 s)。传感器测量前方 ±90°、4.5 m 以内路标的距离和方位(噪声 0.1 m 和 2°),并且已知每次看到的是哪个路标(数据关联已知,和 4.8 节一样);里程计速度噪声 0.1 m/s,角速度噪声 0.05 rad/s。

    Pose graphs became mainstream only in the late 2000s. Before that, SLAM was mostly done as the Bayes filter of Lesson 4.7: estimate only the current pose and the map, and "marginalize" every old pose as soon as it is passed. The two experiments below share one scene: 18 point landmarks, and a robot driving counter-clockwise twice around a 14 m × 9 m ellipse at 1 m/s (about 76 s). The sensor measures range and bearing to landmarks within ±90° of the heading and 4.5 m (noise 0.1 m and 2°), and it knows which landmark it is seeing (known data association, as in Lesson 4.8); odometry has 0.1 m/s speed noise and 0.05 rad/s turn-rate noise.

    EKF-SLAM:一个越来越大的高斯EKF-SLAM: one ever-growing Gaussian

    EKF-SLAM 把 4.8 节的 EKF 定位直接推广:状态不只是机器人的 \((x,y,\theta)\),而是把所有已看到的路标坐标都拼进去,\(\mathbf y=[\x;\mathbf m_1;\dots;\mathbf m_n]\in\R^{3+2n}\),用一个均值和一个 \((3+2n)\times(3+2n)\) 的协方差 \(P\) 表示全部信念。第一次看到一个路标时,用测量反推它的位置,把状态扩维;以后每次再看到它,就做一次普通的 EKF 更新。精髓在协方差的非对角块 \(\hl{pxm}{P_{xm}}\):路标是从一个有误差的位姿看到的,所以它的误差和机器人的误差相关,路标之间也因此相关。正因为有这些相关,机器人重新看到很早以前的路标时,修正会顺着 \(P\) 传给所有路标,包括此刻根本看不见的那些。

    EKF-SLAM generalizes the EKF localization of Lesson 4.8 directly: the state is not just the robot's \((x,y,\theta)\) but also the coordinates of every landmark seen so far, \(\mathbf y=[\x;\mathbf m_1;\dots;\mathbf m_n]\in\R^{3+2n}\), and the whole belief is one mean and one \((3+2n)\times(3+2n)\) covariance \(P\). When a landmark is seen for the first time, its position is computed back from the measurement and the state is augmented; every later sighting is an ordinary EKF update. The essence is in the off-diagonal blocks \(\hl{pxm}{P_{xm}}\) of the covariance: a landmark is seen from an uncertain pose, so its error is correlated with the robot's, and through the robot the landmarks become correlated with each other. Because of these correlations, when the robot sees a landmark from long ago, the correction flows through \(P\) to every landmark, including those it cannot see right now.

    FIG 3EKF-SLAM:相关性让回环传遍整张地图EKF-SLAM: correlations carry a loop closure through the whole map
    紫色十字是真实路标,紫色虚线和空心紫色三角是真实轨迹与位姿;琥珀色点和椭圆是路标的估计与 3σ 椭圆,实心琥珀三角及其椭圆是机器人的估计;红线是纯里程计;青色扇形是传感器视野,青线连向此刻测到的路标。右上是整个协方差的相关系数 \(|\rho_{ij}|=|P_{ij}|/\sqrt{P_{ii}P_{jj}}\):蓝色越不透明越接近 1;左上角的小框是机器人的 3 维,之后每个路标占 2 行 2 列,按被发现的先后排列。NEES 是路标误差的归一化平方 \(\mathbf e^\top P_{ii}^{-1}\mathbf e\) 在各路标上的平均,如果滤波器给出的协方差和真实误差相符,它约等于 2(每个路标 2 个自由度)。 Purple crosses are the true landmarks; the dashed purple line and hollow purple triangle are the true trajectory and pose. Amber dots and ellipses are the landmark estimates with their 3σ ellipses; the filled amber triangle and its ellipse are the robot estimate; the red line is pure odometry; the cyan wedge is the sensor's field of view, with cyan lines to the landmarks measured right now. Top right: the correlation coefficients of the whole covariance, \(|\rho_{ij}|=|P_{ij}|/\sqrt{P_{ii}P_{jj}}\), as blue cells, more opaque = closer to 1; the small box in the corner is the robot's 3 dimensions, then each landmark takes 2 rows and 2 columns in order of discovery. NEES is the normalized squared landmark error \(\mathbf e^\top P_{ii}^{-1}\mathbf e\) averaged over the landmarks; if the filter's covariance matches its real errors it is about 2 (2 degrees of freedom per landmark).
    • 保留相关性运行。第一圈快结束时(约 t = 31 s)机器人重新看到最早的路标:半秒之内,路标的平均 σ 下降约三分之一(约 0.145 m → 0.099 m),机器人的 σ 从约 0.25 m 降到 0.1 m 以下。注意右上的矩阵:这时几乎所有格子都已是深蓝,整张地图彼此相关。Run with the correlations kept. Near the end of the first lap (around t = 31 s) the robot sees the earliest landmarks again: within half a second the mean landmark σ drops by about a third (about 0.145 m → 0.099 m) and the robot's σ falls from about 0.25 m to below 0.1 m. Look at the matrix at the top right: almost every cell is now solid blue, the whole map is correlated.
    • 选“全部丢掉”(每一步之后把所有交叉协方差清零)再运行:椭圆缩得比保留相关性时还小,可路标误差卡在约 0.25 m 降不下来;15 s 之后 NEES 就超过 20(两圈后约 570),滤波器对自己的地图严重过于自信。Choose "cut them all" (all cross-covariances zeroed after every step) and run: the ellipses shrink even smaller than with correlations, yet the landmark error stays stuck near 0.25 m; after 15 s the NEES exceeds 20 (about 570 after two laps): the filter is grossly overconfident about its own map.

    保留相关性时,两圈后的路标 RMS 误差约 0.07 m,NEES 约 3:略高于理想的 2,这是 EKF-SLAM 已知的线性化不一致(见第 8 节)。代价是:每次更新都要改写整个 \(P\),状态维数 \(N=3+2n\),每次更新约 \(2N^2\) 次乘加,内存也是 \(N^2\)。18 个路标时 \(N=39\),毫无压力;一张一万个路标的地图,每次更新就是 \(8\times10^8\) 次运算。这就是 EKF-SLAM 只能用于小地图的原因。

    With the correlations kept, the landmark RMS error after two laps is about 0.07 m and the NEES about 3: a little above the ideal 2, the known linearization inconsistency of EKF-SLAM (see Section 8). The price: every update rewrites all of \(P\). With state dimension \(N=3+2n\), each update costs about \(2N^2\) multiply-adds and the memory is \(N^2\) too. With 18 landmarks \(N=39\), no problem at all; for a map of ten thousand landmarks each update is \(8\times10^8\) operations. That is why EKF-SLAM is limited to small maps.

    FastSLAM:每个粒子带一张自己的地图FastSLAM: every particle carries its own map

    FastSLAM(Montemerlo 等,2002)注意到一件事:如果整条路径已知,各路标就彼此独立了,因为它们之间的相关全是通过机器人位姿传过来的。于是用 4.10 节的粒子滤波表示路径,每个粒子是一条路径假设 \(\hl{path}{\x^{[i]}_{1:t}}\),并且带着 \(n\) 个各自独立的 2×2 小 EKF,每个路标一个。每一步:按运动模型给每个粒子采样一个新位姿,用它自己的地图更新它看到的路标,并按测量和它的地图吻合的程度更新权重;有效粒子数 \(N_\text{eff}\) 低于 \(M/2\) 时做系统重采样。每次更新只碰被看到的那个路标,代价约为 \(M\) 乘以每步测量数,与地图大小无关(用树形结构共享地图时是 \(M\log n\))。

    FastSLAM (Montemerlo et al., 2002) notices one thing: if the whole path were known, the landmarks would be independent of each other, because all their correlation comes through the robot pose. So it represents the path with the particle filter of Lesson 4.10: each particle is a path hypothesis \(\hl{path}{\x^{[i]}_{1:t}}\) carrying \(n\) independent 2×2 EKFs, one per landmark. At each step: sample a new pose for every particle from the motion model, update the landmarks it sees with its own map, and reweight it by how well the measurements agree with its map; resample systematically when the effective sample size \(N_\text{eff}\) drops below \(M/2\). An update touches only the landmark that was seen, so the cost is about \(M\) times the number of measurements per step, independent of the map size (\(M\log n\) when the maps are shared in a tree).

    FIG 4FastSLAM:粒子越多越好,可路径假设很快只剩一条FastSLAM: more particles help, but the path hypotheses soon collapse to one
    与 FIG 3 完全相同的运动和测量数据。细的琥珀色线是所有粒子的祖先树:每个仍然活着的粒子,沿着它的父辈一直画回起点,共同的祖先只画一次;琥珀色小点是各粒子的当前位置。琥珀色大点和椭圆(3σ)是权重最大的那个粒子的地图,实心琥珀三角是它的位姿;紫色是真值。右上图(对数纵轴):琥珀线是“t = 5 s 时机器人在哪”还剩多少种不同的假设,蓝线是 \(N_\text{eff}\)。 Exactly the same motion and measurement data as FIG 3. The thin amber lines are the ancestry tree of all particles: every living particle is traced back through its parents to the start, with shared ancestors drawn once; small amber dots are the particles' current positions. The larger amber dots and their 3σ ellipses are the map of the highest-weight particle, and the filled amber triangle is its pose; purple is the truth. Top right (log scale): the amber line counts how many distinct hypotheses remain for "where was the robot at t = 5 s", the blue line is \(N_\text{eff}\).
    • 先用 M = 1 运行到第一圈结束(t = 40 s):只有一个粒子,就没有任何纠正,地图就是航位推算拼出来的,路标误差约 1 m。再用 M ≥ 100 运行到 40 s:误差降到约 0.1 m。(完成条件:两次在 t = 40 s 时的误差之比小于 1/2;按“换一组粒子随机数”可以看到结果因随机数而异。)First run with M = 1 to the end of the first lap (t = 40 s): with a single particle nothing is ever corrected, the map is the dead-reckoned one, and the landmark error is about 1 m. Then run with M ≥ 100 to 40 s: the error drops to about 0.1 m. (Completes when the error at t = 40 s of the second run is below half that of the first; "New particle noise" shows how much the result varies.)
    • 用 M ≥ 20 运行,盯住读数里的“t = 5 s 时机器人在哪”:重采样一遍遍发生,到第一圈结束前就只剩 1 种假设(M = 30 时约在 t = 30 s),虽然粒子仍有 M 个。(完成条件:t ≥ 38 s 时这个数为 1。)Run with M ≥ 20 and watch "where was the robot at t = 5 s" in the readout: resampling happens again and again, and before the first lap is over only 1 hypothesis is left (around t = 30 s for M = 30), although there are still M particles. (Completes when that count is 1 at t ≥ 38 s.)
    为什么两者都让位给了位姿图Why both gave way to pose graphs

    EKF-SLAM 把过去的位姿边缘化掉,换来的是一个稠密的协方差:\(O(n^2)\) 的内存和每次更新的代价,而且每一步的线性化都被永久“焊死”,之后再也改不了。FastSLAM 用采样避开了稠密矩阵,可是粒子滤波只能表示有限条路径假设:重采样不断丢掉不吻合的假设,很快所有粒子都来自同一个祖先(FIG 4 里的这个数会掉到 1),于是早期路径的不确定性实际上被扔掉了;回环越长,需要的粒子越多。位姿图(平滑)保留了整条轨迹:信息矩阵是稀疏的(第 6 节),每次都可以在新的估计处重新线性化,过去的错误随时能被后来的回环改正。FastSLAM 的思想没有消失:GMapping 用改进提议分布的 Rao-Blackwell 粒子滤波建栅格地图,多年来一直是 ROS 里的默认 2D 建图工具之一。

    EKF-SLAM marginalizes past poses and pays with a dense covariance: \(O(n^2)\) memory and cost per update, and every linearization is welded in for good and can never be revised. FastSLAM avoids the dense matrix by sampling, but a particle filter can represent only finitely many path hypotheses: resampling keeps discarding the ones that do not fit, soon every particle descends from one ancestor (that count in FIG 4 drops to 1), and the uncertainty of the early path has effectively been thrown away; the longer the loop, the more particles it needs. A pose graph (smoothing) keeps the whole trajectory: its information matrix is sparse (Section 6), it can be relinearized at every new estimate, and a past mistake can be corrected by any later loop closure. The FastSLAM idea did not disappear: GMapping, a Rao-Blackwellized particle filter with an improved proposal that builds grid maps, was for years one of the default 2D mapping tools in ROS.

    5后端的两个难题:错误回环与增量求解Two problems of the back end: false closures and incremental solving

    一条错误的回环就能毁掉地图One false loop closure can wreck the map

    地点识别会认错:两段一样的走廊、一排相同的货架、换了季节的街道。一条错误回环说“这两个位姿在同一个地方”,在平方损失下它的拉力与偏差成正比,而且它的信息矩阵和真回环一样大,于是整张图被硬拽到一起。补救办法是 6.9 节、11.5 节讲过的鲁棒核:把回环边的代价换成增长更慢的 \(\hl{kern}{\rho}\),用 IRLS 求解,每条边按当前的归一化误差 \(\chi=\sqrt{\mathbf e^\top\Omega\mathbf e}\) 得到一个权重 \(w(\chi)\)。下面是一个 120 个位姿的“曼哈顿世界”位姿图(机器人在 1 m 网格上随机游走,回到同一个网格点就有一定概率产生真回环,共 47 条),再随机加入若干条错误回环;所有优化都从同一个里程计初值出发。鲁棒核只加在回环边上。

    Place recognition makes mistakes: two identical corridors, a row of identical shelves, a street in another season. A false closure says "these two poses are at the same place"; under the squared loss its pull grows with the discrepancy, and its information matrix is as large as a true closure's, so the whole graph is dragged together by force. The remedy is the robust kernel of Lessons 6.9 and 11.5: replace the cost of the loop-closure edges with a slower-growing \(\hl{kern}{\rho}\) and solve by IRLS, giving every edge a weight \(w(\chi)\) from its current normalized error \(\chi=\sqrt{\mathbf e^\top\Omega\mathbf e}\). Below is a 120-pose "Manhattan world" pose graph (a robot random-walking on a 1 m grid; returning to the same grid point produces a true closure with some probability, 47 in all), with a number of false closures added at random. Every optimization starts from the same odometry initialization. The robust kernel is applied to loop-closure edges only.

    FIG 5错误回环:平方损失被拽歪,鲁棒核把它们关掉False closures: the squared loss gets dragged, robust kernels switch them off
    每次改动都从里程计初值重新做 IRLS-Gauss-Newton,一帧一次迭代地显示出来。紫线是真实轨迹,琥珀线是当前估计;绿线是真回环,红色虚线是错误回环,权重越大的边画得越粗、越不透明。视图会自动缩放,把整个估计都框进来。右上:蓝线是所选核函数的权重曲线 \(w(\chi)\)(平方损失时恒为 1),点是每条回环当前的 \((\chi,w)\),绿色为真、红色为假,\(\chi>30\) 的点画在右边缘。尺度 \(k\) 的单位是 σ;对 DCS,滑块的值就是参数 \(\Phi\),它和 \(\chi^2\) 比较,所以 DCS 从 \(\chi=\sqrt\Phi\) 开始降权。“参照”是删掉全部错误回环后普通最小二乘的误差,代表这张图能达到的最好水平。 Every change re-runs IRLS Gauss-Newton from the odometry initialization, one iteration per frame. The purple line is the true trajectory, the amber line the current estimate; green lines are true closures and dashed red lines false ones, drawn thicker and more opaque the larger their weight. The view zooms itself to keep the whole estimate in frame. Top right: the blue line is the weight curve \(w(\chi)\) of the chosen kernel (constant 1 for the squared loss), and the dots are the current \((\chi,w)\) of every closure, green for true and red for false; points with \(\chi>30\) sit on the right edge. The scale \(k\) is in units of σ; for DCS the slider value is the parameter \(\Phi\), which is compared with \(\chi^2\), so DCS starts down-weighting at \(\chi=\sqrt\Phi\). The "reference" is the error of plain least squares with every false closure deleted: the best this graph can do.
    • 平方损失、至少 4 条错误回环:RMS 误差超过 1 m(默认 6 条时约 2.0 m,参照只有 0.08 m),轨迹被几条红线拽成一团。Squared loss with at least 4 false closures: the RMS error exceeds 1 m (about 2.0 m with the default 6, against a reference of only 0.08 m); a few red lines crumple the trajectory.
    • 换成 Cauchy 或 DCS(尺度 3),至少 4 条错误回环:误差回到参照水平(相差不超过 5 cm),每条错误回环的权重都低于 0.1,而真回环一条也没被误压。Switch to Cauchy or DCS (scale 3) with at least 4 false closures: the error returns to the reference level (within 5 cm), every false closure ends with weight below 0.1, and no true closure is suppressed.

    再试几种组合(默认图、6 条错误回环):Huber(尺度 3)把误差降到约 0.42 m,比平方损失好得多,但做不到参照水平:它的影响函数有界却不为零,错误回环还在用常数大小的力拉。错误回环加到 20 条时,Huber 的误差升到约 1.5 m,Cauchy 和 DCS 仍是 0.08 m。尺度太小也不行:把 DCS 的尺度降到 1,47 条真回环里有 40 条被一起关掉,误差 0.67 m;降到 0.5,47 条真回环有 46 条被关掉,结果基本停在里程计初值。原因是从里程计初值看,真回环的误差也很大(漂移有 1 m,而回环的 σ 是 5 cm,\(\chi\) 可达 20),一个太“狠”的核分不清谁真谁假。点“换一张图”可以看到,DCS 在某些图上尺度 3 也会误杀真回环,而 Cauchy 更宽容。

    Try a few more combinations (default graph, 6 false closures): Huber (scale 3) brings the error down to about 0.42 m, far better than the squared loss but not the reference: its influence function is bounded but not zero, so the false closures still pull with a constant force. With 20 false closures Huber rises to about 1.5 m, while Cauchy and DCS stay at 0.08 m. Too small a scale fails as well: at DCS scale 1, 40 of the 47 true closures are switched off along with the false ones and the error is 0.67 m; at 0.5, 46 of the 47 are switched off and the result essentially stays at the odometry initialization. The reason: seen from the odometry start, true closures have large errors too (the drift is 1 m while a closure's σ is 5 cm, so \(\chi\) reaches 20), and too aggressive a kernel cannot tell true from false. "New graph" shows that on some graphs DCS at scale 3 also kills true closures, whereas Cauchy is more forgiving.

    增量求解:每一步要重算多少?Incremental solving: how much must be redone at each step?

    机器人每秒都在加新位姿。每来一个关键帧就从头解一遍整张图,代价随地图增大而增大,迟早跟不上。增量平滑(iSAM,Kaess 等 2008;iSAM2,2012)的想法是:保留上一步的分解结果,只改动受新因子影响的那一部分。用 6.9 节的语言:正规方程矩阵 \(H=LL^\top\),Cholesky 因子 \(\hl{fill}{L}\) 的第 \(c\) 列只依赖排在它前面的变量。加入一个新因子,只会改写消元树上从这个因子最早的变量到根的那一条路径上的列,其余的列一个数也不变。下图用 FIG 2 那条“8”字路线的位姿图(按真实几何建:里程计链,加上相距不到 1 m、相隔至少 20 帧的回环,共 92 个位姿、19 条回环),逐步计算 \(L\) 的非零块(每块 3×3),并标出每一步必须重算的块。

    A robot adds new poses every second. Re-solving the whole graph from scratch at every keyframe costs more as the map grows, and sooner or later it cannot keep up. The idea of incremental smoothing (iSAM, Kaess et al. 2008; iSAM2, 2012) is to keep the previous factorization and change only the part affected by the new factors. In the language of Lesson 6.9: the normal-equation matrix is \(H=LL^\top\), and column \(c\) of the Cholesky factor \(\hl{fill}{L}\) depends only on the variables ordered before it. A new factor rewrites only the columns on the path of the elimination tree from the factor's earliest variable to the root; every other column stays exactly the same. The figure uses the pose graph of FIG 2's figure-eight route (built from the true geometry: the odometry chain plus closures between poses less than 1 m apart and at least 20 frames apart, 92 poses and 19 closures), computes the nonzero blocks of \(L\) (each 3×3) step by step, and marks the blocks that must be recomputed at each step.

    FIG 6增量求解:里程计一步只改几块,回环改一大片,顺序决定一切Incremental solving: an odometry step changes a few blocks, a closure a large region, and the ordering decides everything
    左:加入第 \(k\) 个位姿及其因子之后 \(L\) 的非零块,行列按消元顺序排列;蓝块与上一步相同、可以直接沿用,琥珀块必须重算。右(对数纵轴):每一步的琥珀色柱是“时间顺序”下增量更新要重算的块数,蓝线是同一顺序下整个 \(L\) 的块数(批量求解每步都要全部重算),绿色虚线是每步重新求一次最小度顺序时 \(L\) 的块数。“最小度”每步都换一个顺序,增量的说法不再成立,因此这时显示的是批量代价。这是对块结构的符号计算(不考虑数值巧合),也不考虑重新线性化。 Left: the nonzero blocks of \(L\) after pose \(k\) and its factors have been added, rows and columns in elimination order; blue blocks are the same as in the previous step and can be reused, amber blocks must be recomputed. Right (log scale): the amber bars are the blocks an incremental update recomputes at each step under "time order", the blue line is the size of the whole \(L\) in the same order (a batch solve recomputes all of it every step), and the dashed green line is the size of \(L\) when a minimum-degree order is recomputed at every step. "Minimum degree" changes the order every step, so incrementality no longer applies and the batch cost is shown. This is a symbolic computation on the block structure (ignoring numerical coincidences) and ignores relinearization.
    • 按时间顺序,先看第 40 步(只有里程计):只有 3 块要重算,而 \(L\) 已有约 80 块。再拖到第 54 步,第一条回环(连回位姿 12):要重算 126 块,\(L\) 共 150 块,因为消元树上从位姿 12 到根的整条路径都变了。In time order, look first at step 40 (odometry only): just 3 blocks are redone while \(L\) already holds about 80. Then drag to step 54, the first loop closure (back to pose 12): 126 blocks are redone out of 150, because the whole elimination-tree path from pose 12 to the root has changed.
    • 拖到最后一步(91),比较三种顺序:时间顺序下 \(L\) 有 1264 块,最小度顺序只有 312 块,而 \(H\) 本身只有 202 块;倒序(最新的变量最先消)每一步都要全部重算。选“最小度”并停在第 91 步即完成。Drag to the last step (91) and compare the three orders: in time order \(L\) has 1264 blocks, in minimum-degree order only 312, while \(H\) itself has 202; in reverse order (newest variable eliminated first) every step recomputes everything. Completes with "minimum degree" selected at step 91.
    一个想法,几种看法One idea, several views

    整条路线累计下来,按时间顺序的增量更新共重算 11106 块,每步都批量重算是 26832 块:省了约 2.4 倍。但更重要的是延迟:91 步里有 72 步只是里程计,每步固定 3 块,与地图多大无关;只有回环那几步才贵。时间顺序还有一个问题:回环把两个时刻之间的所有变量连成一片,填充迅速增长(1264 对 312 块)。事实上,每步都用最小度顺序批量重算,全程累计 11274 块,和按时间顺序的增量更新(11106 块)几乎一样:只要顺序,或只要增量,都不够,两者要结合起来。所以 iSAM2 用 Bayes 树表示分解,只对受影响的部分重新排序(受约束的 COLAMD,让最新的变量排在最后),并且只对估计变化超过阈值的变量重新线性化(fluid relinearization)。批量求解器(g2o、Ceres、GTSAM 的 LM)则在每次求解前用 AMD/COLAMD 求一个低填充的顺序。

    Over the whole route the incremental update in time order recomputes 11106 blocks in total, against 26832 for a batch re-solve at every step: about 2.4 times less. More important is latency: 72 of the 91 steps are odometry only and cost a fixed 3 blocks each, however big the map; only the closure steps are expensive. Time order has another problem: a loop closure links every variable between its two ends, so fill-in grows quickly (1264 versus 312 blocks). In fact a batch re-solve with a minimum-degree order at every step adds up to 11274 blocks over the run, almost the same as the time-ordered incremental update (11106): a good order alone, or incrementality alone, is not enough; the two have to be combined. That is why iSAM2 represents the factorization as a Bayes tree, reorders only the affected part (constrained COLAMD, keeping the newest variables last) and relinearizes only the variables whose estimate moved by more than a threshold (fluid relinearization). Batch solvers (g2o, Ceres, GTSAM's LM) compute a low-fill order with AMD/COLAMD before each solve.

    6再看数学The math

    提示:把鼠标悬停在公式中带底色的符号上,图中对应的元素会被高亮:里程计边和回环边(FIG 2)、机器人与路标的协方差块和路标椭圆(FIG 3)、粒子路径(FIG 4)、核函数权重曲线(FIG 5)、需要重算的 \(L\) 块(FIG 6)。Tip: hover the highlighted symbols in the formulas and the matching elements light up in the figures: odometry and loop-closure edges (FIG 2), the robot-landmark covariance blocks and the landmark ellipses (FIG 3), the particle paths (FIG 4), the kernel's weight curve (FIG 5) and the blocks of \(L\) to be recomputed (FIG 6).

    SLAM 的后验:完整 SLAM 与在线 SLAMThe SLAM posterior: full SLAM and online SLAM

    记位姿 \(\x_{0:t}\)、地图 \(\mathbf m\)、控制(里程计)\(\mathbf u_{1:t}\)、测量 \(\mathbf z_{1:t}\)。在马尔可夫假设下(4.7 节),整个后验分解成一串小因子的乘积:

    Write the poses \(\x_{0:t}\), the map \(\mathbf m\), the controls (odometry) \(\mathbf u_{1:t}\) and the measurements \(\mathbf z_{1:t}\). Under the Markov assumptions (Lesson 4.7) the whole posterior factors into a product of small pieces:

    $$ p(\x_{0:t},\mathbf m\mid\mathbf z_{1:t},\mathbf u_{1:t})\ \propto\ p(\x_0)\prod_{s=1}^{t}\underbrace{p(\x_s\mid\x_{s-1},\mathbf u_s)}_{\text{motion}}\ \prod_{k}\underbrace{p(\mathbf z_k\mid\x_{s_k},\mathbf m_{j_k})}_{\text{measurement}} $$

    估计整个左边叫完整 SLAM(平滑),就是位姿图和 BA 做的事。只要当前状态 \(p(\x_t,\mathbf m\mid\cdot)=\int p(\x_{0:t},\mathbf m\mid\cdot)\,d\x_{0:t-1}\) 叫在线 SLAM(滤波),就是 EKF-SLAM 做的事。在高斯近似下,“积分掉”一个变量就是对信息矩阵做 Schur 补(11.6 节):被消去的位姿的所有邻居两两连起来。每个路标都是从某个位姿上看到的,消掉一串位姿之后,所有路标都互相连上,这就是 FIG 3 那个越来越满的矩阵的来历。不做边缘化,信息矩阵保持稀疏:每个块只对应一个因子。

    Estimating the whole left-hand side is full SLAM (smoothing), which is what pose graphs and BA do. Keeping only the current state, \(p(\x_t,\mathbf m\mid\cdot)=\int p(\x_{0:t},\mathbf m\mid\cdot)\,d\x_{0:t-1}\), is online SLAM (filtering), which is what EKF-SLAM does. Under a Gaussian approximation, "integrating out" a variable is a Schur complement on the information matrix (Lesson 11.6): all neighbours of the eliminated pose become mutually linked. Every landmark was seen from some pose, so once a chain of poses has been eliminated all landmarks are linked to each other: that is where the ever-fuller matrix of FIG 3 comes from. Without marginalization the information matrix stays sparse, with one block per factor.

    EKF-SLAM 的更新The EKF-SLAM update

    状态 \(\mathbf y=[\x;\mathbf m_1;\dots;\mathbf m_n]\),协方差按块写成下式。对路标 \(j\) 的距离-方位测量 \(\mathbf z=(r,\phi)\),记 \(\boldsymbol\delta=\mathbf m_j-\mathbf t\),\(q=\|\boldsymbol\delta\|^2\),预测为 \(\hat r=\sqrt q\),\(\hat\phi=\operatorname{atan2}(\delta_y,\delta_x)-\theta\)。雅可比 \(H\) 只在机器人的 3 列和路标 \(j\) 的 2 列上非零:

    The state is \(\mathbf y=[\x;\mathbf m_1;\dots;\mathbf m_n]\) with the block covariance below. For a range-bearing measurement \(\mathbf z=(r,\phi)\) of landmark \(j\), let \(\boldsymbol\delta=\mathbf m_j-\mathbf t\) and \(q=\|\boldsymbol\delta\|^2\); the prediction is \(\hat r=\sqrt q\), \(\hat\phi=\operatorname{atan2}(\delta_y,\delta_x)-\theta\). The Jacobian \(H\) is nonzero only in the robot's 3 columns and landmark \(j\)'s 2 columns:

    $$ P=\begin{bmatrix}P_{xx}&\hl{pxm}{P_{xm}}\\P_{mx}&P_{mm}\end{bmatrix},\qquad H=\Big[\underbrace{\tfrac{1}{q}\begin{bmatrix}-\sqrt q\,\delta_x&-\sqrt q\,\delta_y&0\\ \delta_y&-\delta_x&-q\end{bmatrix}}_{\text{robot}}\ \ 0\ \cdots\ 0\ \ \underbrace{\tfrac1q\begin{bmatrix}\sqrt q\,\delta_x&\sqrt q\,\delta_y\\-\delta_y&\delta_x\end{bmatrix}}_{\text{landmark } j}\ \ 0\ \cdots\Big] $$ $$ S=HPH^\top+R,\qquad K=PH^\top S^{-1}\in\R^{(3+2n)\times2},\qquad \mathbf y\leftarrow\mathbf y+K(\mathbf z-\hat{\mathbf z}),\qquad \hl{lmcov}{P}\leftarrow P-KSK^\top $$

    虽然 \(H\) 很稀疏,\(PH^\top\) 却是一整列稠密的块:只要 \(P_{xm}\) 和 \(P_{mm}\) 非零,增益 \(K\) 在每个路标上都有分量,\(KSK^\top\) 改写 \(P\) 的全部 \((3+2n)^2\) 个元素。这就是 \(O(n^2)\) 的来源,也是回环时“看不见的路标也被修正”的来源。新路标 \(\mathbf m=\mathbf t+r\,(\cos(\theta+\phi),\sin(\theta+\phi))\) 的扩维要用 \(G_x=\partial\mathbf m/\partial\x\) 和 \(G_z=\partial\mathbf m/\partial\mathbf z\):新的协方差块是 \(G_xP_{xx}G_x^\top+G_zRG_z^\top\),与已有状态的交叉块是 \(G_xP_{x\,\cdot}\)。FIG 3 的“全部丢掉”就是每一步之后把 \(P_{xm}\) 和 \(P_{mm}\) 的非对角块置零。

    Sparse as \(H\) is, \(PH^\top\) is a full dense block column: as long as \(P_{xm}\) and \(P_{mm}\) are nonzero, the gain \(K\) has a component on every landmark, and \(KSK^\top\) rewrites all \((3+2n)^2\) entries of \(P\). That is where the \(O(n^2)\) comes from, and also why "landmarks out of view get corrected" at a loop closure. Augmenting with a new landmark \(\mathbf m=\mathbf t+r\,(\cos(\theta+\phi),\sin(\theta+\phi))\) uses \(G_x=\partial\mathbf m/\partial\x\) and \(G_z=\partial\mathbf m/\partial\mathbf z\): the new covariance block is \(G_xP_{xx}G_x^\top+G_zRG_z^\top\) and its cross block with the existing state is \(G_xP_{x\,\cdot}\). The "cut them all" option of FIG 3 sets the off-diagonal blocks of \(P_{xm}\) and \(P_{mm}\) to zero after every step.

    FastSLAM 的分解The FastSLAM factorization

    $$ p(\x_{1:t},\mathbf m\mid\mathbf z_{1:t},\mathbf u_{1:t})=\underbrace{p(\hl{path}{\x_{1:t}}\mid\mathbf z_{1:t},\mathbf u_{1:t})}_{M\ \text{particles}}\ \prod_{j=1}^{n}\underbrace{p(\mathbf m_j\mid\x_{1:t},\mathbf z_{1:t})}_{\text{one }2\times2\text{ EKF each}},\qquad w^{[i]}\propto\mathcal N\big(\mathbf z-\hat{\mathbf z}^{[i]};\ \mathbf 0,\ H_m\Sigma_j^{[i]}H_m^\top+R\big) $$

    这一步是精确的(不是近似),因为给定整条路径,各路标的测量互不相干:这叫 Rao-Blackwell 化,能解析处理的部分(路标)用高斯解析处理,只对剩下的部分(路径)采样。权重按 4.10 节的重要性采样推出:提议分布是运动模型,所以权重就是测量似然,\(H_m\) 是测量对路标的 2×2 雅可比。FastSLAM 2.0 把最新的测量也放进提议分布,粒子更集中,所需粒子数少得多。

    This step is exact, not an approximation: given the whole path, the measurements of different landmarks are independent. It is called Rao-Blackwellization: the part that can be handled analytically (the landmarks) is handled with Gaussians, and only the rest (the path) is sampled. The weight follows from the importance sampling of Lesson 4.10: the proposal is the motion model, so the weight is the measurement likelihood, with \(H_m\) the 2×2 Jacobian of the measurement with respect to the landmark. FastSLAM 2.0 puts the latest measurement into the proposal as well, which concentrates the particles and needs far fewer of them.

    SE(2) 上的位姿图The pose graph on SE(2)

    位姿 \(X_i=(\mathbf t_i,\theta_i)\)。一条边 \((i,j)\) 带一个相对位姿测量 \(Z_{ij}=(\Delta\mathbf t,\Delta\theta)\) 和信息矩阵 \(\Omega_{ij}\)(协方差的逆)。误差是“测量的逆乘以预测”这个变换 \(E_{ij}=Z_{ij}^{-1}X_i^{-1}X_j\) 写成向量(预测与测量完全一致时 \(E_{ij}=I\),误差为零):

    Poses are \(X_i=(\mathbf t_i,\theta_i)\). An edge \((i,j)\) carries a relative-pose measurement \(Z_{ij}=(\Delta\mathbf t,\Delta\theta)\) and an information matrix \(\Omega_{ij}\) (the inverse covariance). The error is the transform "inverse measurement times prediction", \(E_{ij}=Z_{ij}^{-1}X_i^{-1}X_j\), written as a vector (when prediction and measurement agree, \(E_{ij}=I\) and the error is zero):

    $$ \mathbf e_{ij}=\begin{bmatrix}R(\Delta\theta)^\top\big(R(\theta_i)^\top(\mathbf t_j-\mathbf t_i)-\Delta\mathbf t\big)\\ \operatorname{wrap}(\theta_j-\theta_i-\Delta\theta)\end{bmatrix},\qquad F(X)=\sum_{\text{odometry}}\hl{odo}{\mathbf e_{ij}^\top\Omega_{ij}\mathbf e_{ij}}\ +\sum_{\text{loop closures}}\hl{loop}{\rho\big(\mathbf e_{ij}^\top\Omega_{ij}\mathbf e_{ij}\big)} $$

    这和 6.9 节的残差几乎一样,只是平移误差再转到测量 \(Z_{ij}\) 的坐标系里:这是 g2o 的约定;GTSAM 用 \(\Log(E_{ij})\),两者零点相同、在零附近一阶相同(6.10 节:\(V(\varphi)\approx I\))。在二维里,旋转只是一个角度,\(\theta\leftarrow\operatorname{wrap}(\theta+\delta\theta)\) 本身就是 SO(2) 上的指数映射更新,平移在世界坐标里直接相加,所以 FIG 2 直接用 \((\mathbf t,\theta)\) 加增量;三维时必须用 6.10 节的 \(\Exp\)。令 \(\mathbf a=R_i^\top(\mathbf t_j-\mathbf t_i)\),\(R=R(\Delta\theta)^\top R(\theta_i)^\top\),两个 3×3 雅可比块是

    This is almost the residual of Lesson 6.9, except that the translation error is rotated once more into the frame of the measurement \(Z_{ij}\): that is g2o's convention; GTSAM uses \(\Log(E_{ij})\). The two have the same zero and agree to first order near it (Lesson 6.10: \(V(\varphi)\approx I\)). In 2D a rotation is a single angle, so \(\theta\leftarrow\operatorname{wrap}(\theta+\delta\theta)\) is itself the exponential-map update on SO(2), and translations add in world coordinates; FIG 2 therefore adds increments to \((\mathbf t,\theta)\) directly. In 3D you need the \(\Exp\) of Lesson 6.10. With \(\mathbf a=R_i^\top(\mathbf t_j-\mathbf t_i)\) and \(R=R(\Delta\theta)^\top R(\theta_i)^\top\), the two 3×3 Jacobian blocks are

    $$ A_{ij}=\frac{\partial\mathbf e_{ij}}{\partial X_i}=\begin{bmatrix}-R & R(\Delta\theta)^\top\begin{bmatrix}a_y\\-a_x\end{bmatrix}\\ \mathbf 0^\top&-1\end{bmatrix},\qquad B_{ij}=\frac{\partial\mathbf e_{ij}}{\partial X_j}=\begin{bmatrix}R&\mathbf 0\\\mathbf 0^\top&1\end{bmatrix} $$ $$ H=\sum_{(i,j)}J_{ij}^\top\,w_{ij}\Omega_{ij}\,J_{ij},\qquad \mathbf g=\sum_{(i,j)}J_{ij}^\top\,w_{ij}\Omega_{ij}\,\mathbf e_{ij},\qquad H\boldsymbol\delta=-\mathbf g,\qquad J_{ij}=[\,\cdots A_{ij}\cdots B_{ij}\cdots] $$

    上面这行是页面加载时现算的:把解析雅可比和中心差分逐元素比较。\(H\) 的块 \((i,j)\) 非零当且仅当 \(i,j\) 之间有边,所以它是“对角带 + 回环处的几块”。全图在整体平移和旋转下不变,\(H\) 有 3 维零空间,固定 \(X_0\)(规范,6.9 节)后才可逆。\(w_{ij}\) 是 IRLS 权重:里程计边取 1,回环边按下面的核函数取值。

    The line above is computed when the page loads: it compares the analytic Jacobians entry by entry with central differences. Block \((i,j)\) of \(H\) is nonzero exactly when there is an edge between \(i\) and \(j\), so \(H\) is "a diagonal band plus a few blocks at the loop closures". The whole graph is invariant to a global translation and rotation, so \(H\) has a 3-dimensional null space and becomes invertible only once \(X_0\) is fixed (the gauge, Lesson 6.9). \(w_{ij}\) is the IRLS weight: 1 for odometry edges, and for loop closures the value given by the kernels below.

    鲁棒核的权重Robust kernel weights

    $$ \chi=\sqrt{\mathbf e^\top\Omega\,\mathbf e},\qquad \hl{kern}{w(\chi)}=\begin{cases}1 & \text{squared}\\ \min(1,\,k/\chi) & \text{Huber}\\ 1/(1+\chi^2/k^2) & \text{Cauchy}\\ s^2,\ \ s=\min\!\big(1,\ 2\Phi/(\Phi+\chi^2)\big) & \text{DCS}\end{cases} $$

    Huber 对大误差只给 \(k/\chi\) 的权重,力的大小 \(w\chi=k\) 有界但不为零。Cauchy 和 DCS 是“回落”型:\(\chi\) 很大时权重趋于零,错误回环几乎被关掉,但代价不再是凸的,结果依赖初值。DCS(dynamic covariance scaling,Agarwal 等 2013)是从 switchable constraints(Sünderhauf 与 Protzel 2012)推出来的:后者给每条回环配一个要和位姿一起优化的“开关” \(s\in[0,1]\),回环的信息矩阵乘以 \(s^2\),再加一项先验 \(\Phi(1-s)^2\)(\(\Phi\) 是开关先验方差的倒数)。于是这条边的代价是 \(s^2\chi^2+\Phi(1-s)^2\),完全关掉(\(s=0\))时等于 \(\Phi\)。Agarwal 等分析收敛点时要求这个代价不超过 \(\Phi\),得到 \(0\le s\le2\Phi/(\Phi+\chi^2)\),取其中不超过 1 的最大值,就是上面的闭式 \(s\):开关不再是要优化的变量,信息矩阵直接按 \(s^2\) 缩放。注意 \(\Phi\) 是和 \(\chi^2\) 比较的,不是和 \(\chi\):\(\chi^2\le\Phi\) 时权重为 1。

    Huber gives a large error only the weight \(k/\chi\): the force \(w\chi=k\) is bounded but not zero. Cauchy and DCS "redescend": as \(\chi\) grows the weight goes to zero and a false closure is all but switched off, at the price of a non-convex cost whose result depends on the start. DCS (dynamic covariance scaling, Agarwal et al. 2013) was derived from the switchable constraints of Sünderhauf and Protzel (2012). Those give every closure a "switch" \(s\in[0,1]\) that is optimized along with the poses; the closure's information matrix is multiplied by \(s^2\), and a prior term \(\Phi(1-s)^2\) is added (\(\Phi\) is the inverse of the switch prior's variance). The edge's cost is then \(s^2\chi^2+\Phi(1-s)^2\), which equals \(\Phi\) when the closure is fully switched off (\(s=0\)). Analysing the converged solution, Agarwal et al. require this cost never to exceed \(\Phi\), which gives \(0\le s\le2\Phi/(\Phi+\chi^2)\); taking the largest such value not above 1 yields the closed-form \(s\) above. The switch is no longer a variable to optimize: the information matrix is simply scaled by \(s^2\). Note that \(\Phi\) is compared with \(\chi^2\), not \(\chi\): the weight is 1 while \(\chi^2\le\Phi\).

    不确定度与增量更新Uncertainty and incremental updates

    在最优点附近,位姿的协方差约为 \(H^{-1}\)(和 11.6 节 BA 的协方差同理)。FIG 2 的椭圆用的是它的 3×3 对角块:先分解 \(H=LL^\top\),再对每个位姿解两次三角方程,不需要求出整个 \(H^{-1}\)。增量更新也建立在这个分解上:加入一个新因子相当于 \(H\leftarrow H+J^\top\Omega J\),其中 \(J\) 只在几个变量上非零;Cholesky 因子 \(\hl{fill}{L}\) 中改变的列,恰好是消元树上从这几个变量中最早的那个到根的路径(Davis 与 Hager 的秩更新理论)。所以按时间排序时,一条里程计边只改动最后两列,一条连回很早位姿的回环会改动从那一位姿以后的几乎所有列。

    Near the optimum the pose covariance is approximately \(H^{-1}\) (as for the BA covariance of Lesson 11.6). FIG 2's ellipses use its 3×3 diagonal blocks: factor \(H=LL^\top\) once, then solve two triangular systems per pose, without ever forming all of \(H^{-1}\). Incremental updates build on the same factorization: a new factor means \(H\leftarrow H+J^\top\Omega J\) with \(J\) nonzero on only a few variables, and the columns of the Cholesky factor \(\hl{fill}{L}\) that change are exactly those on the elimination-tree path from the earliest of these variables to the root (the rank-update theory of Davis and Hager). So in time order an odometry edge changes only the last two columns, and a closure back to a very old pose changes nearly every column after that pose.

    与光束法平差的关系The relation to bundle adjustment

    11.6 节说过,BA 消去所有三维点之后剩下的约化相机系统,就是相机位姿的信息矩阵;位姿图用相对位姿测量代替了这些块,相当于把结构“边缘化后近似”。代价小了几个数量级(每条边 3 或 6 维,而不是成百上千个像素观测),但丢掉了点的细节,也丢掉了边与边之间的相关(每条边被当成独立的测量)。所以视觉 SLAM 常常回环后先做一次位姿图优化,把大的漂移拉回来,再跑一次完整 BA 精修。

    Lesson 11.6 showed that eliminating all 3D points from BA leaves a reduced camera system that is the information matrix of the camera poses; a pose graph replaces those blocks by relative-pose measurements, i.e. it marginalizes the structure and approximates the result. It is orders of magnitude cheaper (each edge has 3 or 6 dimensions instead of hundreds or thousands of pixel observations), but it loses the point detail and the correlations between edges (each edge is treated as an independent measurement). That is why visual SLAM often runs a pose-graph optimization after a loop closure to pull back the large drift, and then a full BA to refine.

    7机器人中的它:真实的 SLAM 系统In robotics: real SLAM systems

    真实系统的结构和 FIG 2 一样分成前端和后端,差别在于每一块都做得更结实。前端:连续帧之间不只靠轮式里程计,而是用扫描匹配或视觉/视觉惯性里程计(12.1、15.1 节)给出相对位姿;地点识别不依赖当前估计的位置(那正是漂移之后最不可信的东西),而是比较外观或几何描述子;候选回环要经过几何验证。后端:稀疏求解器、好的消元顺序、鲁棒核,以及增量更新。SLAM 给出的是位姿和挂在位姿上的测量;把它们做成哪一种地图(占据栅格、代价地图、距离场、拓扑图……),取决于谁来读地图,这是 15.3 节的内容。

    Real systems are split into a front end and a back end just like FIG 2; the difference is that every part is made sturdier. Front end: consecutive frames are linked not only by wheel odometry but by scan matching or visual / visual-inertial odometry (Lessons 12.1 and 15.1); place recognition does not rely on the position in the current estimate (exactly what is least trustworthy after drift) but compares appearance or geometric descriptors; candidate closures go through geometric verification. Back end: sparse solvers, good elimination orders, robust kernels and incremental updates. SLAM delivers poses with measurements attached to them; which kind of map to build from them (an occupancy grid, a costmap, a distance field, a topological graph…) depends on who reads the map, and that is the subject of Lesson 15.3.

    真实系统里In real systems

    激光 SLAM:Google 的 Cartographer(Hess 等,ICRA 2016)在“局部 SLAM”里把每一帧扫描用 Ceres 匹配到一个子图(submap)上,在“全局 SLAM”里用分支定界(branch-and-bound)扫描匹配在子图之间找回环,再做稀疏位姿调整(sparse pose adjustment)。slam_toolbox(Macenski 与 Jambrecic,2021;ROS 2 导航栈 Nav2 的启动文件建图时调用的就是它)也是“扫描匹配 + 位姿图”的结构。LIO-SAM(Shan 等,IROS 2020)把激光里程计、IMU 预积分、GPS 和回环都写成因子,用 GTSAM 的 iSAM2 增量求解。GMapping(Grisetti、Stachniss 与 Burgard,2007)则是 FastSLAM 一脉的 Rao-Blackwell 粒子滤波栅格建图。视觉 SLAM:ORB-SLAM 用 DBoW2 词袋做地点识别,用几何验证确认回环后,先在“本质图”(essential graph,位姿图的一个稀疏子集)上优化位姿,单目时用 Sim(3) 以同时修正尺度漂移;ORB-SLAM2(2017)在这之后再在后台线程里跑一次全局 BA;ORB-SLAM3(Campos 等,2021)加入了 IMU 和多地图(Atlas)。EKF-SLAM 的代表 MonoSLAM(Davison 等,2007)能用单个相机实时运行,代价是地图只能保持很小,因为每次更新是 \(O(n^2)\)。地点识别:图像上有 DBoW2 这类词袋和 NetVLAD(Arandjelović 等,2016)这类学习描述子,三维激光上有 Scan Context(Kim 与 Kim,2018)。抗错误回环:除了鲁棒核,Kimera-RPGO 用成对一致性最大化(PCM,Mangelson 等 2018)先挑出彼此一致的回环子集,渐进非凸(GNC,Yang 等 2020)则从凸的代价逐步过渡到鲁棒代价,降低对初值的依赖。库:GTSAM(因子图、iSAM2)、g2o(Kümmerle 等,2011)、Ceres Solver。

    Lidar SLAM: Google's Cartographer (Hess et al., ICRA 2016) matches every scan against a submap with Ceres in its "local SLAM", and in its "global SLAM" finds loop closures between submaps with branch-and-bound scan matching followed by sparse pose adjustment. slam_toolbox (Macenski and Jambrecic, 2021), the SLAM package that the launch files of the ROS 2 navigation stack Nav2 start for mapping, has the same "scan matching + pose graph" structure. LIO-SAM (Shan et al., IROS 2020) writes lidar odometry, IMU preintegration, GPS and loop closures as factors and solves them incrementally with GTSAM's iSAM2. GMapping (Grisetti, Stachniss and Burgard, 2007) is a Rao-Blackwellized particle filter for grid maps in the FastSLAM line. Visual SLAM: ORB-SLAM does place recognition with the DBoW2 bag of words; after geometric verification of a closure it first optimizes the poses over the "essential graph" (a sparse subset of the pose graph), using Sim(3) in the monocular case so that scale drift is corrected too; ORB-SLAM2 (2017) then runs a full BA in a background thread; ORB-SLAM3 (Campos et al., 2021) adds the IMU and multiple maps (Atlas). MonoSLAM (Davison et al., 2007), the landmark example of EKF-SLAM, runs in real time with a single camera, at the price of keeping the map small because every update is \(O(n^2)\). Place recognition: bag-of-words methods such as DBoW2 and learned descriptors such as NetVLAD (Arandjelović et al., 2016) for images, Scan Context (Kim and Kim, 2018) for 3D lidar. Surviving false closures: besides robust kernels, Kimera-RPGO uses pairwise consistency maximization (PCM, Mangelson et al. 2018) to select a mutually consistent subset of closures first, and graduated non-convexity (GNC, Yang et al. 2020) moves gradually from a convex cost to the robust one to reduce the dependence on the start. Libraries: GTSAM (factor graphs, iSAM2), g2o (Kümmerle et al., 2011), Ceres Solver.

    还有一个 12.1 节留下的问题:位姿图里每条边的信息矩阵 \(\Omega\) 从哪来?对 ICP 边,常用的是高斯牛顿近似 \(\Omega\approx A/\sigma^2\)(\(A=\sum J_i^\top J_i\)),但 12.1 节已经指出它只是下界,没有算上错误对应和采样间距,真实的不确定度更大;直接用它,回环边会显得过于自信。FIG 2 采用的是固定的保守值(里程计边 σ = 5 cm、0.015 rad,回环边 3 cm、0.008 rad)。退化场景(长走廊)里 \(A\) 在沿走廊方向接近奇异,这时把它当信息矩阵反而是对的:它告诉后端“这个方向我不知道”。

    One question left open by Lesson 12.1: where does the information matrix \(\Omega\) of each edge come from? For an ICP edge the usual choice is the Gauss-Newton approximation \(\Omega\approx A/\sigma^2\) (with \(A=\sum J_i^\top J_i\)), but Lesson 12.1 already warned that it is only a lower bound on the uncertainty: it ignores wrong correspondences and sampling spacing, the real uncertainty is larger, and used as-is it makes loop-closure edges look overconfident. FIG 2 uses fixed, conservative values (odometry edges σ = 5 cm and 0.015 rad, closures 3 cm and 0.008 rad). In a degenerate scene (a long corridor) \(A\) is nearly singular along the corridor, and there using it as the information matrix is exactly right: it tells the back end "I don't know this direction".

    8常见误区Common pitfalls

    误区 1:只要找到了就接受回环Pitfall 1: accepting every closure that is found

    错误回环的破坏是全局的(FIG 5:6 条就能让误差从 0.08 m 变成 2 m),漏掉一条真回环的代价却只是少一次修正。所以前端应当保守:几何验证(ICP 的重叠率与残差、视觉里的 RANSAC 内点数,11.5 节)、时间一致性(连续几帧都能对上才接受)、成对一致性检查。鲁棒核是最后一道防线,不是第一道。

    A false closure does global damage (FIG 5: six of them take the error from 0.08 m to 2 m), while missing a true one only costs one correction. So the front end should be conservative: geometric verification (ICP overlap and residual, RANSAC inlier counts in vision, Lesson 11.5), temporal consistency (accept only when several consecutive frames agree) and pairwise consistency checks. The robust kernel is the last line of defence, not the first.

    误区 2:用漂移后的估计去找回环Pitfall 2: searching for closures around the drifted estimate

    FIG 2 的地点识别是在当前估计附近找候选,ICP 也从当前估计出发。漂移小时这很好用;漂移一大(FIG 2 里航向偏差约 0.35°/m 起),候选位置和初值都错得离谱,回环恰恰在最需要的时候失效。真实系统用不依赖位姿的外观或几何描述子来找候选(DBoW2、NetVLAD、Scan Context),再用一个对初值不敏感的方法(RANSAC、分支定界匹配)求相对位姿。

    FIG 2 looks for candidates near the current estimate and starts ICP from it too. That works while drift is small; once it is large (in FIG 2, from a heading bias of about 0.35°/m) both the candidate positions and the initial guess are badly wrong, and loop closure fails exactly when it is needed most. Real systems find candidates with pose-independent appearance or geometric descriptors (DBoW2, NetVLAD, Scan Context) and compute the relative pose with a method insensitive to the start (RANSAC, branch-and-bound matching).

    误区 3:信息矩阵随便填Pitfall 3: making up the information matrices

    后端只能按 \(\Omega\) 来权衡各条边。回环边过于自信,它会把里程计硬掰弯;过于谦虚,回环几乎不起作用。未建模的系统误差(FIG 1 的航向偏差)尤其危险:它不是白噪声,任何 \(\Omega\) 都描述不了它,两个回环之间的那段轨迹会整体弯曲。更好的做法是把这类偏差当成要估计的变量(例如里程计标定参数、IMU 零偏,15.1 节),而不是指望回环去吸收。

    The back end can weigh the edges only by their \(\Omega\). Make a closure overconfident and it bends the odometry by force; make it too modest and the closure does almost nothing. Unmodelled systematic error (the heading bias of FIG 1) is especially dangerous: it is not white noise, no \(\Omega\) describes it, and the trajectory between two closures bends as a whole. It is better to make such biases variables to be estimated (odometry calibration parameters, IMU biases, Lesson 15.1) than to hope the closures absorb them.

    误区 4:相信 EKF-SLAM 给出的协方差Pitfall 4: trusting the covariance of EKF-SLAM

    EKF 在每一步的估计处线性化,之后再也不改。对 SLAM 来说,这会让滤波器在不可观测的方向(全局平移和航向)上“凭空”获得信息,协方差随时间变得过于自信(Julier 与 Uhlmann 2001;Huang 与 Dissanayake 2007)。FIG 3 里保留相关性的 NEES 约为 3 而不是 2,就是这种轻度不一致;时间更长、噪声更大时会严重得多。至于把相关性丢掉,FIG 3 已经给出了答案:NEES 约 570。

    The EKF linearizes at each step's estimate and never revisits it. In SLAM this lets the filter "invent" information in unobservable directions (global translation and heading), and the covariance becomes overconfident over time (Julier and Uhlmann 2001; Huang and Dissanayake 2007). The NEES of about 3 instead of 2 in FIG 3 with correlations kept is this mild inconsistency; with longer runs and more noise it gets far worse. As for dropping the correlations, FIG 3 has already answered: a NEES of about 570.

    误区 5:把地图存在世界坐标里Pitfall 5: storing the map in world coordinates

    如果每来一帧扫描就把它变换到世界坐标、写进一张全局地图,那么回环修正了位姿之后,已经写进去的那些点并不会跟着动,地图依旧是重影。正确的做法是像 FIG 2 那样,把测量挂在关键帧(或子图)上,地图需要时由“当前估计的位姿 × 局部测量”重新生成。栅格地图也可以这样做:Cartographer 把扫描插进局部子图,回环后只移动子图的位姿;或者在位姿图优化后用新位姿把扫描重新插一遍(15.3 节)。

    If every scan is transformed to world coordinates and written into one global map as it arrives, then after a loop closure corrects the poses, the points already written do not move with them and the map stays doubled. The right way is FIG 2's: attach measurements to keyframes (or submaps) and regenerate the map when needed from "current pose estimate × local measurement". Grid maps can be handled the same way: Cartographer inserts scans into local submaps and after a closure moves only the submap poses; alternatively, re-insert every scan with the new poses after the pose-graph optimization (Lesson 15.3).

    9小练习Check yourself

    1. EKF-SLAM 的地图里有 \(n\) 个路标。处理一次路标测量的代价随 \(n\) 怎样增长?1. An EKF-SLAM map has \(n\) landmarks. How does the cost of processing one landmark measurement grow with \(n\)?
    \(H\) 只在 5 列上非零,但 \(K=PH^\top S^{-1}\) 是稠密的,\(P\leftarrow P-KSK^\top\) 要改写全部 \((3+2n)^2\) 个元素,所以是 \(O(n^2)\)。选项 A 错在忽略了相关性;选项 D 错在只需要对 2×2 的 \(S\) 求逆。\(H\) is nonzero in only 5 columns, but \(K=PH^\top S^{-1}\) is dense and \(P\leftarrow P-KSK^\top\) rewrites all \((3+2n)^2\) entries, hence \(O(n^2)\). Option A forgets the correlations; option D is wrong because only the 2×2 matrix \(S\) is inverted.
    2. EKF-SLAM 中,机器人在一圈结束时重新看到路标 1。为什么此刻看不见的路标 9 的椭圆也会缩小?2. In EKF-SLAM the robot sees landmark 1 again at the end of a lap. Why does the ellipse of landmark 9, which it cannot see now, shrink as well?
    路标 9 是从带误差的位姿上看到的,它的误差和当时的机器人误差、进而和其他路标的误差相关(FIG 3 的矩阵里那些蓝格)。测到路标 1 修正了机器人位姿,\(K\) 通过 \(P_{mm}\) 的非对角块把修正传给路标 9。预测步只会增大不确定度(选项 A 错);把相关性丢掉之后,这种传递就消失了。Landmark 9 was seen from an uncertain pose, so its error is correlated with the robot's error at the time and through it with the other landmarks (the blue cells of FIG 3's matrix). Measuring landmark 1 corrects the robot pose, and \(K\) carries the correction to landmark 9 through the off-diagonal blocks of \(P_{mm}\). Prediction only ever increases uncertainty (option A is wrong); once the correlations are cut, this transfer disappears.
    3. FastSLAM 只用 1 个粒子(M = 1)。结果相当于什么?3. FastSLAM with a single particle (M = 1). What does it amount to?
    FastSLAM 1.0 里粒子的位姿只从运动模型采样,测量只更新路标和权重;位姿被“纠正”只能靠重采样在不同粒子之间挑选。只有一个粒子时无从挑选,路径就是带噪声的航位推算,FIG 4 里 M = 1 时路标误差约 1 m。选项 C 正好说反了。In FastSLAM 1.0 a particle's pose is only ever sampled from the motion model; measurements update only the landmarks and the weight. A pose can be "corrected" only by resampling choosing between particles. With one particle there is nothing to choose from, so the path is noisy dead reckoning: in FIG 4 the landmark error is about 1 m for M = 1. Option C has it backwards.
    4. 为了“保险”,你把 DCS 的尺度 \(\Phi\) 调得很小(比如 0.5),然后从漂移约 1 m 的里程计初值开始优化。最可能发生什么?4. To be "safe" you set the DCS scale \(\Phi\) very small (say 0.5) and optimize from an odometry start with about 1 m of drift. What is most likely to happen?
    从里程计初值看,1 m 的漂移在 σ = 5 cm 的回环上是 \(\chi\approx20\),真假回环一样“难看”。尺度太小的回落核把它们一起压到权重接近 0,图里只剩里程计链,正好是一个自洽的解,于是停在那里。FIG 5 里 DCS 尺度 0.5 时 47 条真回环有 46 条被压掉,误差等于里程计初值的 1.01 m。H 不会奇异,因为里程计链和固定的 \(X_0\) 仍在(选项 D 错)。Seen from the odometry start, 1 m of drift on a closure with σ = 5 cm is \(\chi\approx20\): true and false closures look equally bad. A redescending kernel with too small a scale pushes both to nearly zero weight, leaving only the odometry chain, which is a self-consistent solution, so the optimizer stays there. In FIG 5, DCS at scale 0.5 suppresses 46 of the 47 true closures and the error equals that of the odometry start, 1.01 m. \(H\) does not become singular, because the odometry chain and the fixed \(X_0\) remain (option D is wrong).
    5. 用 iSAM2 这样的增量求解器,按时间顺序消元。机器人加入一个只带里程计边的新位姿,因子 \(L\) 要重算多少?5. With an incremental solver such as iSAM2 and time-ordered elimination, the robot adds a new pose with only an odometry edge. How much of the factor \(L\) must be recomputed?
    新因子只涉及位姿 \(k-1\) 和 \(k\)。按时间顺序,\(k-1\) 在消元树里的父节点就是 \(k\),也就是根,所以只有这两列改变:FIG 6 里每个里程计步都是 3 块。回环连回很早的位姿时,从那个位姿到根的整条路径都要重算,这才是增量求解贵的时候。The new factor involves only poses \(k-1\) and \(k\). In time order the parent of \(k-1\) in the elimination tree is \(k\), the root, so only these two columns change: 3 blocks at every odometry step in FIG 6. When a closure links back to a very old pose, the whole path from that pose to the root must be redone, and that is when incremental solving gets expensive.

    10延伸阅读Further reading

    • H. Durrant-Whyte & T. Bailey, Simultaneous Localization and Mapping: Part I, IEEE Robotics & Automation Magazine, 2006; T. Bailey & H. Durrant-Whyte, Part II, same year — 经典入门综述:问题表述、EKF-SLAM、FastSLAMthe classic tutorial: problem statement, EKF-SLAM, FastSLAM
    • S. Thrun, W. Burgard & D. Fox, Probabilistic Robotics, MIT Press, 2005, Ch. 10–13 — EKF-SLAM、GraphSLAM、稀疏扩展信息滤波与 FastSLAM 的标准教材the standard textbook on EKF-SLAM, GraphSLAM, sparse extended information filters and FastSLAM
    • F. Lu & E. Milios, Globally Consistent Range Scan Alignment for Environment Mapping, Autonomous Robots, 1997 — 位姿图思想的起点where the pose-graph idea starts
    • M. Montemerlo, S. Thrun, D. Koller & B. Wegbreit, FastSLAM: A Factored Solution to the Simultaneous Localization and Mapping Problem, AAAI 2002 — Rao-Blackwell 化的粒子滤波 SLAMRao-Blackwellized particle-filter SLAM
    • G. Grisetti, R. Kümmerle, C. Stachniss & W. Burgard, A Tutorial on Graph-Based SLAM, IEEE Intelligent Transportation Systems Magazine, 2010 — 前端/后端、SE(2) 误差与雅可比,本节的直接参考front end / back end, SE(2) errors and Jacobians; the direct reference for this lesson
    • E. Olson, J. Leonard & S. Teller, Fast Iterative Alignment of Pose Graphs with Poor Initial Estimates, ICRA 2006 — 曼哈顿世界数据集的来源the origin of the Manhattan-world datasets
    • F. Dellaert & M. Kaess, Square Root SAM, IJRR 2006; M. Kaess, A. Ranganathan & F. Dellaert, iSAM: Incremental Smoothing and Mapping, IEEE T-RO 2008; M. Kaess et al., iSAM2: Incremental Smoothing and Mapping Using the Bayes Tree, IJRR 2012 — 平滑优于滤波的论证、增量分解与 Bayes 树why smoothing beats filtering, incremental factorization and the Bayes tree
    • N. Sünderhauf & P. Protzel, Switchable Constraints for Robust Pose Graph SLAM, IROS 2012; P. Agarwal, G. D. Tipaldi, L. Spinello, C. Stachniss & W. Burgard, Robust Map Optimization Using Dynamic Covariance Scaling, ICRA 2013 — FIG 5 里的开关与 DCSthe switches and DCS of FIG 5
    • C. Cadena, L. Carlone, H. Carrillo, Y. Latif, D. Scaramuzza, J. Neira, I. Reid & J. J. Leonard, Past, Present, and Future of Simultaneous Localization and Mapping: Toward the Robust-Perception Age, IEEE T-RO 2016 — 现代 SLAM 的全景综述the panoramic survey of modern SLAM
    • W. Hess, D. Kohler, H. Rapp & D. Andor, Real-Time Loop Closure in 2D LIDAR SLAM, ICRA 2016 — Cartographer:子图与分支定界回环Cartographer: submaps and branch-and-bound loop closure
    • R. Mur-Artal, J. M. M. Montiel & J. D. Tardós, ORB-SLAM: A Versatile and Accurate Monocular SLAM System, IEEE T-RO 2015 — 词袋回环、本质图与 Sim(3) 位姿图bag-of-words loop closing, the essential graph and the Sim(3) pose graph