GEODE Hard sequences: RKO-LIO v8 and the profile rivals (2026-10)¶
Summary¶
Correction (2026-10-16): the comparisons on the Hard sequences and the stairs are not held out. - Development data. From v13 on, every GEODE configuration was chosen by its results on the 18 Hard sequences: the handheld options (v13, v14, v17, v18) on the twelve handheld sequences, the vehicle options (v15, v16) on the six α sequences. v18 was also developed on the stairs, after v17 failed there, and adopted under a rule chosen after its results. - The rivals are not tuned. They run their own configurations with only the sensor settings changed (see "Inputs"). On these sequences the comparisons therefore favour RKO-LIO. - Held out. Only GEODE's Metro Tunneling bags, each run once under rules fixed before the run: - tunnel1–3 (7 bags). RKO-LIO is the only method without a failure, but BIEVR-LIO's median ATE is lower (0.35 against 0.84 m). - tunnel4–5 (6 bags, configurations per sensor and platform). RKO-LIO has no failure, and neither has BIEVR-LIO, whose median ATE is lower (0.34 against 0.36 m). - The vehicle options. On the six road α sequences they were developed on, RKO-LIO beats BIEVR-LIO on five. On the four UGV α bags BIEVR-LIO is 4–17 times more accurate on three. On the fourth, tunnel2 α, the rivals diverge in its LiDAR gaps and RKO-LIO tracks it. - What the held-out bags support. RKO-LIO has the fewest failures (none in 13 bags), not the best accuracy.
Correction (2026-10-13): the γ results were measured with an unsynchronised IMU.
- The offset. Every method was given the Xsens IMU (/imu/data). On the γ device (Livox AVIA) its stamps are 7.5–80 ms early against the Livox internal IMU (/livox/imu), which runs on the LiDAR's clock. The offset differs on every sequence:
| sequence | Xsens offset |
|---|---|
| Shield_tunnel1 | 47.5 ms |
| Shield_tunnel2 | 42.5 ms |
| Shield_tunnel3 | 35 ms |
| Shield_tunnel4 | 30 ms |
| flat_surfaces_aggressive | 32.5 ms |
| Shield_tunnel5 | 12.5 ms |
| Shield_tunnel6 | 7.5 ms |
| flat_surfaces_smooth | 80 ms |
The offsets come from cross-correlating the two gyros. - β is not affected. Its Xsens is 7.5 ms off the Ouster internal IMU on all four sequences. - BIEVR-LIO. Its own configuration for this device uses the internal IMU. With it, BIEVR-LIO tracks Shield_tunnel1 at 0.26 m (its paper reports 0.256 m), against 995,841 m with the Xsens. It diverged only where the offset is 30 ms or more and the motion is fast. - RKO-LIO. v16 also improves on the internal IMU: Shield_tunnel1 goes from 6.38 to 0.82 m. - Withdrawn. The γ results of BIEVR-LIO and RKO-LIO in this note were not valid, and the earlier medians that included them are withdrawn. - Re-run. Every method has been re-run on the internal IMU (see "Re-run on the Livox internal IMU"). - Over all 18 sequences. RKO-LIO v16 still has the lowest median ATE (8.5 m, against 78.7 m for BIEVR-LIO) and the most sequences below 10 m (9, against 8). Its lead comes from the β and α sequences. - On the six γ shield tunnels. BIEVR-LIO is better: median 0.85 m, against 6.6 m. - The γ gap is in the prediction. In a fixed-point test on Shield_tunnel2, neither registration pulls a 0.3 m offset back along the tunnel, so BIEVR-LIO's lead comes from its inertial window. RKO-LIO's window with a gravity estimate (W1) matches it on the six γ shield tunnels (median 0.84 m against 0.85 m). W1 is not adopted: it diverges on flat_surfaces_aggressive, as BIEVR-LIO does, and loses all four β sequences (see "The γ shield tunnels are decided by the prediction").
GEODE (thisparticle.github.io/geode) marks 18 of its 64 sequences "Hard": flat surfaces, shield tunnels, urban tunnels and bridges. This note runs RKO-LIO (v8, the ENWIDE candidate; v9, v10 and v7) and the five profile rivals on all 18.
- On these sequences every method fails almost everywhere. Few runs stay under 20 % 10 m RTE: Shield_tunnel6 (v8, v10, v7, BIEVR-LIO), Shield_tunnel5 and Shield_tunnel10 (BIEVR-LIO), and bridge01 (v8, v9, v10).
- Among the failures, v10 has the lowest median ATE (81 m), ahead of v7 (86 m), v9 (89 m), Point-LIO (94 m), v8 (160 m) and BIEVR-LIO (180 m).
- v8's bump image registration makes it the best on the vehicle-mounted urban tunnels and bridges. The same registration hurts the handheld shield tunnels.
- v9 falls back to point-to-point when the bump terms turn the pose too far. On the four sequences that arrived after v9 was frozen, it beats v8 on two and loses on two.
-
v10 falls back only when large corrections persist (3 of the last 10 scans). It keeps v8's results where v8 is right (Shield_tunnel6, the vehicle sequences, ENWIDE) and is the best RKO-LIO configuration on the two sequences that arrived after it was frozen, Shield_tunnel8 and 10.
-
v12 (2026-10-13) changes the registration step (Levenberg-Marquardt, rko_lio #31) and keeps the speed of a handheld walker from the gait (rko_lio #32). It brings the median to 10.1 m and tracks eight sequences below 10 m (v10 three, BIEVR-LIO four), winning 13 of 18 against v10. ENWIDE keeps v10.
- v13 lets the gait set the whole speed and the scans only its direction (rko_lio #33). A walker stopping and turning with the sensor no longer pumps the speed up. It brings the median to 5.6 m with eleven sequences below 10 m.
- v14 turns off the gait's IMU reversal check, which under v13 fired only on Shield_tunnel2 and always wrongly (165 → 26.9 m). Every other sequence is unchanged.
- v15 holds the vehicle's roll and pitch with the gyro and the gravity window (rko_lio #34). On the vehicle-mounted α sequences the estimated up direction had drifted 40–80° from the true one. The median of the six α sequences drops from 196 to 84 m.
- v16 holds the vehicle's speed while its registration stalls (rko_lio #35). Urban_Tunnel01 drops from 272 to 23.7 m and the α median from 84 to 48.9 m; the other five α sequences are byte-identical.
- v17 keeps a walker's bounds when the registration runs away between steps (rko_lio #38). At a stop or a turnaround the gait loses the cadence, and the tunnel registration runs away with its own prediction. v17 holds such scans to the last pace, or to zero while the walker stands. Shield_tunnel4 drops from 24.4 to 4.21 m and Shield_tunnel6 from 12.6 to 0.55 m. The median over the 18 sequences drops from 8.5 to 3.8 m, with eleven below 10 m.
- v18 limits the gait's correction only where the scan cannot see some translation (rko_lio #39). On GEODE's stairs, two handheld sequences outside the development set until then, v17's gait loses 6.3–6.5 m. v18 was developed on them and tracks them at 0.18 and 0.24 m, the best and the second best of the rivals. The median over the 18 sequences drops from 3.8 to 2.85 m, with twelve below 10 m. It is the GEODE configuration. It was adopted under a rule set after its results (see "v18").
- The Metro Tunneling holdout, a UGV, is fixed before any run. tunnel1–3 test the GEODE configurations, with β and γ in vehicle configurations; tunnel4–5 stay sealed for one parameter set (see "The Metro Tunneling holdout").
- On those seven bags v18 is the only method without a failure. BIEVR-LIO (0.35 m) and FAST-LIO2 (0.36 m) have a lower median ATE than v18 (0.84 m), from the three γ bags (see "The Metro Tunneling holdout: results").
- After the holdout, the UGV's γ gap traces to the tilt limit taken over from α. Without it RKO-LIO tracks the γ bags at BIEVR-LIO's level, but the road α sequences need it, and a speed gate fails (see "After the holdout").
- Since 2026-10-15 a configuration may depend on the sensor and the platform. β and γ on a vehicle drop the tilt limit (v19), and the sealed tunnel4–5 test these configurations (see "Per-sensor configurations and the sealed half").
- On the sealed tunnel4–5 every method ran once. RKO-LIO has no failure and matches BIEVR-LIO on β and γ to 3 mm, but BIEVR-LIO's median ATE is lower (0.34 against 0.36 m), from the two α bags, where α keeps the tilt limit (see "The sealed half: results").
No SOTA claim follows: the profile needs zero catastrophic failures, and no method has that on GEODE Hard.
Inputs¶
GEODE has three devices with the same Xsens MTi-30 IMU (/imu/data, 100 Hz):
| device | LiDAR | topic | sequences here |
|---|---|---|---|
| α | Velodyne VLP-16 | /velodyne_points |
Urban_Tunnel01–03, bridge01–03 (vehicle); Stairs_Alpha (handheld, used to develop v18) |
| β | Ouster OS1-64 | /ouster/points |
Shield_tunnel7–10 (handheld); Stairs_Beta (handheld, used to develop v18) |
| γ | Livox AVIA | /livox/lidar (CustomMsg) |
Shield_tunnel1–6, flat_surfaces_* (handheld) |
Every method gets the same data:
- Inputs. The IMU depends on the device:
- α and β. Every method uses the Xsens IMU and the dataset's
T_IMU_LiDAR({alpha,beta}_config.yaml). - γ. Every method uses the Livox internal IMU (
/livox/imu), because there the Xsens is 7.5–80 ms off the LiDAR clock (see the correction in the Summary). The extrinsic is the one in BIEVR-LIO's and FAST-LIO's Avia configurations: no rotation and a translation of (0.04165, 0.02326, −0.0284) m. - Older results. γ results measured before 2026-10-13 used the Xsens.
- Conversion.
scripts/convert_geode_bag.pywrites the LiDAR and the IMUs to a ROS 2 bag for RKO-LIO and BIEVR-LIO: the Xsens and, where there is one, the LiDAR's internal IMU (/livox/imu,/ouster/imu). - Livox CustomMsg becomes PointCloud2 with a uint32
t(ns from the scan start). - The VLP-16
timefield is in seconds relative to a stamp at the scan end, so most offsets are negative. FAST-LIO2 and Point-LIO expect offsets from the scan start and would leave the earlier part of each scan undeskewed, which costs metres at 40 km/h. The converter moves the stamp to the first point and makestimenon-negative. Every point's absolute time is unchanged. --ros1-outwrites the same normalized data as ROS 1 for the ROS 1 rivals. The γ and β rivals play the original bags.- β metadata.
metadata_beta.jsonlistspixel_shift_by_rowfor only 62 of 64 rows. All 64 areround(beam_azimuth_deg * 1024 / 360), the rule the listed rows follow and ENWIDE'sos_enwide.jsonfollows for all 128 rows. - Ground truth. The trajectories are not always in time order.
scripts/prepare_geode_ground_truth.pysorts them. - The shield tunnels have laser-tracker positions at about 3 Hz.
- The urban tunnels and bridges have GNSS/INS, with gaps of up to 70 s inside the tunnels; those gaps are not scored.
- The flat surfaces have Vicon.
- The lever arm between the IMU and the ground-truth point is not published, so the IMU trajectory is scored directly.
- Scoring.
score_position_only_trajectory.pyaligns with SE(3) and reports ATE and 10 m RTE, as on ENWIDE.
Configurations (configs/geode/):
rko_lio_{alpha,beta,gamma}_v8.yamlis ENWIDE v8 with GEODE's sensor settings only. It has photometric terms on β only, because they need an Ouster intensity image.- v7 is the same configuration without the three v8 options.
rivals/holds each rival's own configuration for the closest sensor. Only the topics, the extrinsic, the 0.65 m blind range and, for the VLP-16,timestamp_unitchange.- COIN-LIO needs an Ouster intensity image, so it runs on β only.
Development split, declared after the first three pilot runs:
- Development: flat_surfaces_smooth, Urban_Tunnel01 and Shield_tunnel9.
- Validation: the other sequences, which no configuration was tuned on.
The split holds for v8–v11. v12 was tuned on six handheld sequences and checked on the other six. From v13 on, every version was chosen by its results on all 18 (see the 2026-10-16 correction in the Summary).
Results (18 sequences)¶
ATE in metres.
- *: development sequences for v8, v9 and v10.
- †: arrived after v9 was frozen. ‡: arrived after v10 was frozen, so unseen by every configuration.
- incomplete: a run that diverged until it stopped producing poses (counted as the worst value in the medians).
| sequence (device) | v8 | v9 | v10 | v7 | COIN-LIO | BIEVR-LIO | FAST-LIO2 | Point-LIO |
|---|---|---|---|---|---|---|---|---|
| Shield_tunnel1 (γ) | 303 | 97.6 | 82.9 | 78.3 | – | 995,841 | 295 | 93.7 |
| Shield_tunnel2 (γ) | 119 | 105 | 108 | 75.6 | – | 259,303 | 554 | 82.7 |
| Shield_tunnel3 (γ) † | 59.7 | 63.9 | 72.4 | 53.3 | – | 150,049 | 16,629 | 73.8 |
| Shield_tunnel4 (γ) † | 159 | 66.5 | 70.1 | 69.6 | – | 117,016 | 77,795 | 69.1 |
| Shield_tunnel5 (γ) † | 40.4 | 27.2 | 40.4 | 21.7 | – | 1.54 | 46,928 | 37.0 |
| Shield_tunnel6 (γ) | 0.56 | 25.3 | 0.56 | 4.12 | – | 0.47 | 39.9 | 32.2 |
| Shield_tunnel7 (β) † | 58.6 | 82.8 | 90.2 | 75.5 | 314 | 132 | 328 | 96.5 |
| Shield_tunnel8 (β) ‡ | 130 | 107 | 78.9 | 93.0 | 289 | 73.6 | 289 | 102 |
| Shield_tunnel9 (β) * | 441 | 67.2 | 56.6 | 59.1 | 852 | 83.7 | 254 | 83.1 |
| Shield_tunnel10 (β) ‡ | 227 | 95.7 | 86.6 | 93.1 | 349 | 7.10 | 358 | 94.6 |
| Urban_Tunnel01 (α) * | 560 | 560 | 560 | 888 | – | 169 | 1010 | 983 |
| Urban_Tunnel02 (α) | 260 | 260 | 260 | 816 | – | 680 | 1158 | 1173 |
| Urban_Tunnel03 (α) | 160.2 | 160.1 | 158.6 | 1202 | – | 69,283 | 1721 | 149,732 |
| bridge01 (α) | 46.2 | 46.2 | 46.2 | 167 | – | 109 | 933 | 984 |
| bridge02 (α) | 246 | 246 | 246 | 885 | – | 190 | 1830 | 23,649 |
| bridge03 (α) | 1095 | 1035 | 1088 | 697 | – | 879 | 1091 | 1100 |
| flat_surfaces_aggressive (γ) | incomplete | 2.62 | 3.02 | incomplete | – | 9304 | 1047 | 4.38 |
| flat_surfaces_smooth (γ) * | 3.66 | 2.01 | 2.00 | 2.47 | – | 1.34 | 2229 | 2.77 |
| median | 160 | 89.2 | 80.9 | 85.7 | 332 (β only) | 180 | 1029 | 94.2 |
| runs under 20 % RTE | 2 | 1 | 2 | 1 | 0 | 3 | 0 | 0 |
Why v8 fails in the shield tunnels¶
The ablations below are on the development sequences only, with ATE in metres:
| change to v8 | Shield_tunnel9 * | Urban_Tunnel01 * | flat_surfaces_smooth * |
|---|---|---|---|
| v8 | 441 | 560 | 3.66 |
| without bump image registration | 68.5 | 895 | |
| v7 (without all three v8 options) | 59.1 | 888 | 2.47 |
| degeneracy-aware solve, ratio 0.01 | 546 | 1356 | |
| bump plus a gyro rotation prior, weight 30 / 300 | 127 / 207 | – / 662 | |
| bump plus point-to-point, bump weight 1 | 58.3 | 873 | 2.12 |
| bump plus point-to-point, bump weight 5 / 20 | 69.9 / 75.1 | 779 / 725 |
- Where the error comes from. A per-scan log of v8 on Shield_tunnel9 shows the registration turning the pose by several degrees per scan after about 20 s, up to 11.7° in one scan. The Xsens gyro predicts that rotation to well under a degree.
- Hypothesis. A circular shield tunnel leaves the roll about its axis and the along-axis translation unobservable, and the bump images' periodic segment rings let the registration slip along them. The ring explanation has not been tested.
- The fixes tried. None of them keeps v8's gain on the vehicle sequences and removes the shield-tunnel failure: the generic degeneracy-aware solve, a gyro rotation prior, and mixing in point-to-point.
v9: fall back to point-to-point when the bump terms turn the pose too far¶
A correctly registered scan stays close to the gyro prediction. The rotation correction of v8's registration (degrees, per scan) separates the cases cleanly:
| development sequence | v8 result | median | 99th percentile | scans over 2° |
|---|---|---|---|---|
| GEODE Urban_Tunnel01 | best of all methods | 0.15 | 1.07 | 0 % |
| ENWIDE FieldD | good | 0.40 | 1.60 | 0.3 % |
| ENWIDE RunwayD | good | 0.42 | 1.53 | 0.3 % |
| GEODE flat_surfaces_smooth | fails | 1.70 | 50.9 | 46 % |
| GEODE Shield_tunnel9 | fails | 5.16 | 31.3 | 68 % |
- What v9 does. v9 is v8 plus
bump_image_max_rotation_correction_deg: 2.0(rko_lio #28). A scan whose bump result turns more than 2° away from the IMU guess is registered again without the bump terms. - How it was frozen. The threshold was set on the six development sequences and frozen before any validation sequence was run.
- Determinism fix. rko_lio #27 makes the point-to-point system deterministic first. Without it, the chaotic fallback scans varied by about ±0.2 m between runs of the same build.
- Configurations.
configs/geode/rko_lio_{alpha,beta,gamma}_v9.yaml.
The GEODE numbers are in the results table above. The four sequences that arrived after v9 was frozen are the only validation that no configuration has seen:
| unseen GEODE sequence | v8 | v9 |
|---|---|---|
| Shield_tunnel3 (γ) | 59.7 | 63.9 |
| Shield_tunnel4 (γ) | 159 | 66.5 |
| Shield_tunnel5 (γ) | 40.4 | 27.2 |
| Shield_tunnel7 (β) | 58.6 | 82.8 |
| ENWIDE sequence | v8 | v9 |
|---|---|---|
| IntersectionD | 0.38 | 0.52 |
| TunnelD * | 0.32 | 0.41 |
| FieldD * | 0.24 | 0.28 |
| RunwayD * | 2.34 | 1.70 |
| the other six | same | same |
| median of 10 | 0.29 | 0.35 |
On GEODE, v9 halves v8's median (75 m against 160 m over 16 sequences). It is the best method on flat_surfaces_aggressive, where v8 lost track, but it loses Shield_tunnel6. On the unseen sequences it is level with v8, two each. On ENWIDE it costs up to 0.14 m. It still has no ENWIDE failure and stays below COIN-LIO on every sequence.
The profile allows at most 2 % regression on sequences that are not degenerate. v9 regresses more than that on IntersectionD, so v8 stays the candidate. v9 is the configuration for strongly degenerate scenes such as GEODE Hard.
The fallback fires per scan, so a single noisy scan switches registration even where the bump terms were right. v10 below adds a persistence condition.
v10: fall back only when the slip persists¶
rko_lio #29 logs every scan's bump rotation correction (bump_rotation_corrections.csv)
and adds a persistence gate. The v8 logs on the six development sequences show that the
cases differ in persistence, not size:
| development sequence | v8 result | scans over 2° | longest run over 2° | largest correction |
|---|---|---|---|---|
| GEODE Urban_Tunnel01 | best of all methods | 0 % | 0 | 1.8° |
| ENWIDE FieldD / RunwayD | good | 0.3 % | 1 | 3.1° |
| ENWIDE TunnelD | good | 1.6 % | 2 | 14.4° |
| GEODE flat_surfaces_smooth | fails | 46 % | 30 | 102° |
| GEODE Shield_tunnel9 | fails | 68 % | 34 | 48° |
- What v10 does. v10 is v9 plus
bump_image_rotation_fallback_window: 10andbump_image_rotation_fallback_min_count: 3. A scan falls back only when at least 3 of the last 10 scans exceeded 2°. - How it was frozen. Chosen on the development sequences and frozen before Shield_tunnel8 and 10 were read. A 20° hard limit (fall back at once) changed nothing there and was left out.
- Check. With the default 1 / 1 the new build reproduces v9 and v8 bit for bit.
- Configurations.
configs/geode/rko_lio_{alpha,beta,gamma}_v10.yaml.
| development sequence | v8 | v9 | v10 |
|---|---|---|---|
| ENWIDE FieldD | 0.24 | 0.28 | 0.24 |
| ENWIDE RunwayD | 2.34 | 1.70 | 2.34 |
| ENWIDE TunnelD | 0.32 | 0.41 | 0.34 |
| GEODE flat_surfaces_smooth | 3.66 | 2.01 | 2.00 |
| GEODE Urban_Tunnel01 | 560 | 560 | 560 |
| GEODE Shield_tunnel9 | 441 | 67.2 | 56.6 |
On Shield_tunnel8 and 10, unseen by every configuration, v10 is the best RKO-LIO configuration (78.9 and 86.6 m against v8's 130 and 227 m, v9's 107 and 96 m, v7's 93 and 93 m). BIEVR-LIO is better on both (73.6 and 7.10 m) and is the only method that tracks Shield_tunnel10.
On the sequences already seen during v9:
- GEODE. v10 keeps v8's Shield_tunnel6 (0.56 m, which v9 lost) and the vehicle results. Against v8 it wins 9 of 18 sequences and loses 2 (Shield_tunnel3 and 7). Against v9 it wins 6 and loses 7; v9 is better on the γ shield tunnels 1–5.
- ENWIDE. v10 equals v8 on FieldS, IntersectionD/S, KatzenseeD/S and RunwayS. It differs only on the development sequence TunnelD (0.34 against 0.32 m, a tunnel). TunnelS was not rerun because its bag had been deleted to save disk.
v10 is not yet the ENWIDE candidate. Replacing v8 would need the official ten-sequence record with TunnelS.
Why RKO-LIO slips where BIEVR-LIO does not (2026-10-11)¶
A windowed error profile shows how the shield-tunnel runs fail. Each 30 s window is aligned to the ground truth on its own. For each window it reports the local RMSE and the difference between the estimated and the true path length.
- Shield_tunnel10. BIEVR-LIO stays at about 0.2 m per window with the correct path length. v8 and v10 overestimate the path by 20–100 m per window: the trajectory runs ahead along the tunnel axis.
- γ shield tunnels 1–5. v7, v9 and v10 slip back and forth along the axis by 10–170 m per window. Which of them ends with the lowest ATE is chance among failing runs, not a systematic difference. BIEVR-LIO diverges from the start on Shield_tunnel1 and 3 but tracks 5 and 6.
- Velocity window. Lengthening
velocity_window_secfrom 0.3 to 2 s only changes the sign of the slip on Shield_tunnel10 (111 m against 86.6 m; Shield_tunnel9 63.5 against 56.6 m). The registration itself slips, presumably to a neighbouring ring of the periodic lining, rather than the velocity running away.
RKO-LIO uses the IMU for the prediction and for a gravity (roll/pitch) regularisation only; nothing in it constrains translation, velocity or accelerometer bias with the IMU. BIEVR-LIO optimises velocity, biases and gravity over a 10 s IMU window together with its bump-image registration.
An experiment added this to RKO-LIO (rko_lio tag archive/feat/inertial-velocity-filter, not merged):
- Velocity filter. A Kalman filter on the world velocity and the accelerometer bias. It propagates with IMU preintegration and corrects with the registered displacement, weighted by the registration's Hessian.
- Translation prior. Optionally, the predicted position with its covariance is added to the registration.
It did not help on the development sequences:
| variant | FieldD | RunwayD | TunnelD | flat_surfaces_smooth | Shield_tunnel9 | Shield_tunnel10 |
|---|---|---|---|---|---|---|
| v10 | 0.24 | 2.34 | 0.34 | 2.00 | 56.6 | 86.6 |
| filter | 0.20 | 2.36 | 0.48 | 2.91 | diverges | 181 |
| filter + translation prior | – | – | – | – | diverges | – |
In a circular tunnel the roll about the axis is as unobservable as the translation along it. Once the registration turns the attitude, gravity leaks into the horizontal acceleration. The filter then estimates 4–7 m/s² of bias and integrates the leak into the velocity. Gating outlier updates and bounding the bias made it worse: Shield_tunnel9 diverged further and TunnelD reached 39 m, because a gated filter integrates the wrong acceleration alone.
Using the IMU to hold the translation therefore needs the attitude and gravity estimated jointly over a window, as BIEVR-LIO does. That is a tightly coupled estimator rather than an addition to RKO-LIO's per-scan registration.
Attitude in the filter (2026-10-11)¶
A second experiment (rko_lio tag archive/feat/inertial-pose-filter, not merged) adds the attitude. It is an error-state Kalman filter on attitude, position, velocity and accelerometer bias. The filter propagates with every IMU sample and is corrected by each registered pose, with a 6×6 covariance from the registration's Hessian. The fused pose replaces the registered one, and the filter's prediction is the registration's initial guess.
| variant | FieldD | TunnelD | flat_surfaces_smooth | Shield_tunnel9 |
|---|---|---|---|---|
| v10 | 0.24 | 0.34 | 2.00 | 56.6 |
| filter follows the registration (prediction as initial guess only) | 0.17 | 2.18 | 2.42 | 50.4 |
| registration rotation floor 0.1°, gyro 0.01 rad/s/√Hz | 0.24 | 0.49 | 2.55 | 73.4 |
| registration rotation floor 0.5°, gyro 0.005 rad/s/√Hz | 261 | 64.9 | 2.28 | 57.6 |
No setting improves on v10. Shield_tunnel9 differences of this size are within the run-to-run spread noted above. Four findings came out of the experiment:
- The registration's roll in the shield tunnels is noise. Per scan, v10's trajectory on Shield_tunnel9 turns about the tunnel axis by 9.7° RMS, and this does not follow the gyro: the residual against the integrated gyro is 9.6° in roll, against 1.7° and 0.8° in pitch and yaw. The bump and photometric terms set the roll, yet the Hessian reports it to about 0.1°.
- Holding roll with the gyro does not stop the slip. The 0.5° floor lets the gyro carry the attitude, and Shield_tunnel9 does not improve. The same setting diverges on FieldD and TunnelD, so the registration's rotation cannot be distrusted globally.
- The covariance must be about the sensor. The registration's left perturbation rotates about the world origin. A floor on that rotation becomes a position uncertainty of |t| times the angle (0.9 m for 0.5° at 100 m), and the filter then dead-reckons and diverges. The Hessian has to be moved to sensor-centred coordinates before the floors and caps.
- The filter's velocity must not drive the deskew. Feeding it to the deskew and the next prediction turned FieldD from 0.17 into 2.5 m, even with the filter following the registration exactly.
A per-block innovation gate, which leaves the position or attitude out of a scan's update when it disagrees, diverged on every sequence once the gated filter drifted. Inflating the block instead lets the filter creep toward whichever wrong value lands closer.
BIEVR-LIO's inertial window (2026-10-12)¶
BIEVR-LIO's source shows that it is not tightly coupled in the pose:
- Registration. It registers each scan against its map without the IMU.
- Fixed poses. It keeps the registered pose as it is.
- Window solve. It then holds the last 10 s of poses fixed and solves only the velocity at every scan, the two IMU biases and the gravity direction from the IMU preintegration between them.
- What the IMU feeds. The IMU feeds only the next scan's prediction and deskew.
The third experiment adds that window to RKO-LIO. It was merged default-off as inertial_window (rko_lio #30), and configs/enwide/rko_lio_os0_open_ground_v10_inertial_window.yaml turns it on for ENWIDE-like data. It is a Gauss-Newton solve over the velocities and both biases with gravity fixed. The newest velocity replaces RKO-LIO's pose-difference velocity, and the biases replace imu_bias.
On ENWIDE it helps on several sequences (ATE in m, v10 from the profile record):
| TunnelS | TunnelD | KatzenseeD | KatzenseeS | FieldD | FieldS | IntersectionD | IntersectionS | RunwayD | RunwayS | |
|---|---|---|---|---|---|---|---|---|---|---|
| v10 | 0.71 | 0.34 | 0.25 | 0.17 | 0.24 | 0.18 | 0.38 | 0.19 | 2.34 | 0.45 |
| window | 0.69 | 0.44 | 0.25 | 0.16 | 0.18 | 0.18 | 0.34 | 0.19 | 0.86 | 0.55 |
It is better on five sequences and worse on two, and the median does not move (0.295 m against 0.293 m).
On GEODE it is worse in the shield tunnels. Ten sequences ran: it wins on Shield_tunnel3, 4 and 9 and Urban_Tunnel01, and loses on the other six, by up to 108 → 895 m on Shield_tunnel2. Three findings came out of it:
- The window fits the slip. With an Xsens IMU, whose bias is a few hundredths of m/s², the window's accelerometer bias runs to the 0.5–1 m/s² limit in the shield tunnels. It explains the registered positions sliding along the axis as acceleration, and the bias then carries the slip into the prediction.
- Anchoring the biases does not help. A strong prior holding the biases at the static initialization keeps them at a few mm/s². Shield_tunnel2 and 8 still diverge (43 and 49 km), because the window's velocity between slipping positions feeds the slip back the same way.
- The rotation residual matters. Dropping it and fixing the gyroscope bias made TunnelD 20 m and Shield_tunnel9 diverge.
BIEVR-LIO succeeds on Shield_tunnel10 because its registration does not slip much, not because of its IMU window. Three ways of adding the IMU to RKO-LIO now agree on this: the velocity filter, the error-state filter and the inertial window. The shield-tunnel failure is in the registration, which locks to a neighbouring ring of the periodic lining, and the IMU cannot undo that after the fact.
Revised (2026-10-13). This conclusion came from the Xsens runs. On γ with the internal IMU it does not hold: neither registration holds the position along the tunnel, and BIEVR-LIO's lead comes from its inertial window (see "The γ shield tunnels are decided by the prediction").
What the slip looks like, and the roll jitter (2026-10-12)¶
The slip is a speed oscillation, not ring jumps. Over 1 s windows, v10's estimated speed swings between a quarter and three to four times the true walking speed on Shield_tunnel1, 8 and 10. The median ratio is 1.0. On Shield_tunnel6, which succeeds, it stays within 0.86–1.15. The top 5 % of seconds carry about half of the excess distance. No single scan moves by a lining ring (>1 m), so the registration slides rather than jumps.
RKO-LIO's attitude jitters; BIEVR-LIO's does not. Per scan on Shield_tunnel10, the rotation between registered poses differs from the integrated gyro by this much:
| roll | pitch | yaw | |
|---|---|---|---|
| BIEVR-LIO | 0.15° | 0.08° | 0.10° |
| v10 | 3.6° | 0.79° | 0.45° |
The jitter comes from the gravity regularisation (min_beta). First 80 s of Shield_tunnel10, gyro residual RMS (roll / pitch / yaw):
| v10 with… | roll | pitch | yaw |
|---|---|---|---|
| nothing changed | 1.87° | 0.41° | 0.28° |
| photometric off | 1.83° | 0.39° | 0.29° |
| bump off | 1.91° | 0.42° | 0.29° |
| bump fallback off | 2.44° | 0.52° | 0.34° |
| gravity regularisation off | 0.29° | 0.10° | 0.13° |
In a circular tunnel nothing geometric fixes the roll, so the tilt read from the accelerometer, polluted by the walking motion, sets it. With the regularisation off, the attitude is as clean as BIEVR-LIO's and the node runs about twice as fast.
A clean attitude alone does not stop the slip. ATE in m:
| Shield_tunnel8 | Shield_tunnel9 | Shield_tunnel10 | |
|---|---|---|---|
| v10 | 78.9 | 56.6 | 86.6 |
| gravity regularisation off | – | 68.2 | 111 |
| … plus inertial window | 126 | 216 | 229 |
| … bump only (no photometric, no fallback) | 75.5 | 37.4 | 108 |
| … bump only plus inertial window | 129 | 43.2 | 140 |
| BIEVR-LIO | 73.6 | 83.7 | 7.1 |
The last RKO-LIO rows use the same parts as BIEVR-LIO: bump-image registration with informed sampling, the same map parameters, no gravity term in the registration, and an inertial window. They still slip on Shield_tunnel10, although bump only is the best RKO-LIO result on Shield_tunnel9 (37.4 m, BIEVR-LIO 83.7 m). Turning the regularisation off on ENWIDE costs FieldD (0.24 → 0.43 m) and TunnelD's 10 m RTE (1.7 → 2.2 %).
The remaining difference is inside the registration step: the optimiser, the deskew or the sampling, not the choice of terms. The next step is to give both registrations the same scan, map and initial guess and compare one step.
The registration step: Gauss-Newton against Levenberg-Marquardt (v11, 2026-10-12)¶
A fixed-point test. The test takes BIEVR-LIO's Shield_tunnel10 trajectory as the true pose:
- Setup. RKO-LIO builds its map from the true poses, registers every scan starting from the true pose, and logs how far the registration moves away.
- Bump only. The registration moves 0.8 mm per scan forward on average, with 38 mm RMS along the axis.
- With the photometric terms. It moves 5–8 mm per scan forward (3–5 % of the distance walked), with 93–101 mm RMS: the lining's periodic intensity pattern pulls the tracked patches.
- Restoring force. Started 0.2 m ahead or behind, bump-only registration comes back by 80–90 %, so it is not missing a basin.
- Closed loop. RKO-LIO's along-axis jitter is three times BIEVR-LIO's (second difference 148–172 mm against 56 mm).
The optimisers differ. RKO-LIO takes plain Gauss-Newton steps, H dx = -b, always applied. BIEVR-LIO takes Levenberg-Marquardt steps: damped, and accepted only when the cost drops. Along an axis the scan barely constrains, Gauss-Newton turns residual noise into large moves. rko_lio #31 adds Levenberg-Marquardt as icp_levenberg_marquardt, default off, damped in body coordinates. With it the fixed-point jitter falls from 15 to 11 mm over the first two minutes.
On Shield_tunnel10, each variant with Levenberg-Marquardt (ATE in m):
| variant | ATE |
|---|---|
| v10 | 131 |
| without photometric | 64.1 |
| without gravity regularisation | 201 |
| without photometric and gravity regularisation | 0.76 |
That last row is v11, configs/geode/rko_lio_{alpha,beta,gamma}_v11.yaml: v10 plus icp_levenberg_marquardt, min_beta: 1e9 and, for the Ouster β, no photometric terms. On Shield_tunnel10 every 30 s window has 0.1–0.2 m local RMSE and the right path length; BIEVR-LIO loses 7 m in one window.
The other development sequences confirmed it: flat_surfaces_smooth 2.20 m (v10 2.00), Urban_Tunnel01 334 m (560), Shield_tunnel9 24.1 m (56.6). v11 was then frozen. The rule set before running the other fifteen was to adopt v11 if the 18-sequence median improves on v10 and v11 wins more sequences than it loses.
| sequence | v10 | v11 | BIEVR-LIO |
|---|---|---|---|
| flat_surfaces_smooth * | 2.00 | 2.20 | 1.34 |
| flat_surfaces_aggressive | 3.02 | 4.25 | 9304 |
| Urban_Tunnel01 * | 560 | 334 | 169 |
| Urban_Tunnel02 | 260 | 89.8 | 680 |
| Urban_Tunnel03 | 159 | 200 | 69,283 |
| bridge01 | 46.2 | 116 | 109 |
| bridge02 | 246 | 192 | 190 |
| bridge03 | 1088 | 681 | 879 |
| Shield_tunnel1 | 82.9 | 69.7 | 995,841 |
| Shield_tunnel2 | 108 | 102 | 259,303 |
| Shield_tunnel3 | 72.4 | 76.4 | 150,049 |
| Shield_tunnel4 | 70.1 | 546 | 117,016 |
| Shield_tunnel5 | 40.4 | 1.98 | 1.54 |
| Shield_tunnel6 | 0.56 | 0.58 | 0.47 |
| Shield_tunnel7 | 90.2 | 130 | 132 |
| Shield_tunnel8 | 78.9 | 109 | 73.6 |
| Shield_tunnel9 * | 56.6 | 24.1 | 83.7 |
| Shield_tunnel10 † | 86.6 | 0.76 | 7.10 |
| median | 80.9 | 95.9 | 180 |
| below 10 m | 3 | 5 | 4 |
* development, † diagnostic (seen during development).
Verdict. v11 wins nine sequences and loses nine, and its median is worse, so it is not adopted; v10 stays the recommended configuration. v11 tracks more sequences than any method so far (five below 10 m, BIEVR-LIO four), and it fails harder elsewhere.
Where v11 still fails. On Shield_tunnel7 and 8 it no longer slides ahead; it stalls, with the speed near zero for a minute. BIEVR-LIO stalls in the same windows.
ENWIDE. Levenberg-Marquardt does not transfer: - v11's settings: FieldD 0.93 m, RunwayD 17.3 m and TunnelD 19.1 m. ENWIDE's tunnels need the photometric terms and its open ground needs the gravity term. - Levenberg-Marquardt alone with v10: FieldD 0.36 m and TunnelD 1.48 m.
v12: the walker's gait (2026-10-13)¶
Where v11 still fails, the scans say nothing along the axis. - No restoring force on Shield_tunnel8. A fixed-point test uses a reference from the ground-truth positions and v11's attitude. Started 0.3 m ahead, the registration keeps 0.28 m of the offset, in the stretches v11 tracks as well as where it stalls. - Stall or runaway. With Levenberg-Marquardt the registration follows the prediction, so the prediction's speed decides the outcome. On Shield_tunnel7 and 8 a small disturbance drops it to zero and nothing brings it back (stall). On Shield_tunnel4 it grows (runaway). - IMU integration alone is not enough. BIEVR-LIO stalls in the same windows, and the inertial window on top of v11 made Shield_tunnel4, 7 and 8 worse.
The gait is an independent speed. The operator walks, and the step rhythm shows in the specific force: - Step length is stable per sequence. Speed over cadence is 0.58–0.79 m depending on the sequence, varying by about 10 %. - Speed estimate. Cadence times the median step length matches the true speed within 0.12–0.28 m/s RMS, with mean errors of a few cm/s.
gait_speed_prior (rko_lio #32, default off) uses it:
- Cadence. Dominant 1.2–3 Hz frequency of the specific-force magnitude over 4 s, with a clear peak required.
- Step length. The median of registered speed over cadence while the registration runs free and the ratio is plausible (0.5–1.0 m), frozen after 100 scans. Before that, the default 0.7 m is used only on implausible scans.
- Prediction. While walking, the predicted speed along the direction of travel is cadence times step length.
- Correction limit. The registration may correct along that direction by at most 2 cm per scan. Otherwise a stalled scan enters the map at the stalled pose and holds the next scans back.
- Direction of travel. It is kept in the body frame, so a walker turning with the sensor keeps it. The IMU detects walking back without turning the sensor: the velocity over the last 4 s, detrended over 30 s, is checked only when the sensor has not turned in the last 12 s.
Every shield-tunnel sequence is walked out and back, so the turn handling decided most of the iterations.
Validation. Tuning used Shield_tunnel4, 5, 7, 8, 9 and 10. v12 was then frozen: v11 plus gait_speed_prior and gait_max_correction_m: 0.02 for the handheld β and γ, with α unchanged from v11 (configs/geode/rko_lio_{alpha,beta,gamma}_v12.yaml). The gait was then run on the six sequences it had not seen, under the same rule as v11.
| sequence | v10 | v11 | v12 | BIEVR-LIO |
|---|---|---|---|---|
| flat_surfaces_smooth ‡ | 2.00 | 2.20 | 2.20 | 1.34 |
| flat_surfaces_aggressive ‡ | 3.02 | 4.25 | 3.04 | 9304 |
| Urban_Tunnel01 (α) | 560 | 334 | 334 | 169 |
| Urban_Tunnel02 (α) | 260 | 89.8 | 89.8 | 680 |
| Urban_Tunnel03 (α) | 159 | 200 | 200 | 69,283 |
| bridge01 (α) | 46.2 | 116 | 116 | 109 |
| bridge02 (α) | 246 | 192 | 192 | 190 |
| bridge03 (α) | 1088 | 681 | 681 | 879 |
| Shield_tunnel1 ‡ | 82.9 | 69.7 | 10.2 | 995,841 |
| Shield_tunnel2 ‡ | 108 | 102 | 57.4 | 259,303 |
| Shield_tunnel3 ‡ | 72.4 | 76.4 | 1.78 | 150,049 |
| Shield_tunnel4 * | 70.1 | 546 | 69.4 | 117,016 |
| Shield_tunnel5 * | 40.4 | 1.98 | 3.30 | 1.54 |
| Shield_tunnel6 ‡ | 0.56 | 0.58 | 8.61 | 0.47 |
| Shield_tunnel7 * | 90.2 | 130 | 2.09 | 132 |
| Shield_tunnel8 * | 78.9 | 109 | 3.85 | 73.6 |
| Shield_tunnel9 * | 56.6 | 24.1 | 1.51 | 83.7 |
| Shield_tunnel10 * | 86.6 | 0.76 | 10.0 | 7.10 |
| median | 80.9 | 95.9 | 10.1 | 180 |
| below 10 m | 3 | 5 | 8 | 4 |
* tuning sequences for the gait, ‡ held out from it; α is unchanged from v11.
Verdict: adopted for GEODE. - Against v10. v12 wins 13 sequences and loses five. Of the losses, flat_surfaces_aggressive is a tie, and Urban_Tunnel03 and bridge01 are v11's α results. - Held-out sequences. Shield_tunnel1 and 3 track, and Shield_tunnel2 halves. - Shield_tunnel6 gets worse (0.56 → 8.61 m). This was first put down to the learned step, 10 % short (0.54 against 0.60 m). The scan-level trace in the v13 section shows the error comes from the turn at the far end instead. - ENWIDE keeps v10. The ENWIDE configurations are not changed: the gait is for handheld walking, and Levenberg-Marquardt did not help there.
v13: speed from the gait, direction from the scans¶
Shield_tunnel6 fails at the turn, not on the step. All of v12's 8.6 m error builds up in one 20 s window, the out-and-back turn at 131 s, while the speed elsewhere matches the ground truth. - What happens. The walker stops and turns with the sensor at about 60°/s. The cadence window (4 s) still shows walking, so the gait keeps setting 0.9 m/s along the direction of travel. That direction is fixed in the body frame and sweeps round with the sensor. - The pump. v12 replaced only the velocity component along that direction and kept the rest from the registration. Each scan the old forward speed survives as a sideways component, and the new direction gets 0.9 m/s again. Within half a second the speed reached 2.2 m/s, and then 3.9 m/s while the walker stood still. - No hold to stop it. At the turn the registration has almost no information along the tunnel (smallest translation eigenvalue 0.2–0.6 % of the largest). It accepts the predicted motion, so the run-away outlives the gait, which switches off at 131.9 s.
gait_sets_speed (rko_lio #33, default off) scales the whole velocity to cadence times step length. The registration gives the direction and the gait the speed. v13 is v12 plus this option for β and γ, with α unchanged (configs/geode/rko_lio_{alpha,beta,gamma}_v13.yaml). It was decided on Shield_tunnel6's trace alone and then run once on all twelve handheld sequences.
| sequence | v10 | v12 | v13 |
|---|---|---|---|
| flat_surfaces_smooth | 2.00 | 2.20 | 2.20 |
| flat_surfaces_aggressive | 3.02 | 3.04 | 3.13 |
| Shield_tunnel1 | 82.9 | 10.2 | 6.38 |
| Shield_tunnel2 | 108 | 57.4 | 165 |
| Shield_tunnel3 | 72.4 | 1.78 | 2.28 |
| Shield_tunnel4 | 70.1 | 69.4 | 4.82 |
| Shield_tunnel5 | 40.4 | 3.30 | 2.71 |
| Shield_tunnel6 | 0.56 | 8.61 | 0.94 |
| Shield_tunnel7 | 90.2 | 2.09 | 1.87 |
| Shield_tunnel8 | 78.9 | 3.85 | 6.28 |
| Shield_tunnel9 | 56.6 | 1.51 | 1.69 |
| Shield_tunnel10 | 86.6 | 10.0 | 2.88 |
| median of all 18 | 80.9 | 10.1 | 5.6 |
| below 10 m (of 18) | 3 | 8 | 11 |
The six α sequences are v12's (unchanged).
Verdict: adopted for GEODE. The rule was set before the run: the median of the 18 is not worse than v12's, v13 wins at least as many sequences as it loses against v12 (differences within 5 % count as ties), and Shield_tunnel6 improves. - Against v12. v13 wins six sequences and loses four. Shield_tunnel4 tracks for the first time (69.4 → 4.82 m), and Shield_tunnel6 comes back to 0.94 m. - Losses. Shield_tunnel2 was already lost and drifts further (57 → 165 m). Shield_tunnel8 goes from 3.85 to 6.28 m.
What did not work. Both of these were tried before the cause was found: - Information gate. Leaving a scan to the registration when it constrains the direction of travel (u'Hu above 10 % of the largest eigenvalue) fixes Shield_tunnel6 (0.58 m). It also fires on 2000–3400 scans of the γ sequences where the registration still slips, and the median rises to 49.4 m (2 wins, 8 losses against v12). - Turn gate. Releasing the gait while the heading changes by more than 1.5 rad in 2 s keeps sensor swings out. It comes about a second into the turn, after the speed has been pumped up (Shield_tunnel6 9.52 m).
v14: no IMU reversal check¶
Shield_tunnel2 runs backwards. Its speed matches the ground truth, but from 32 s on the estimate moves 180° against it, while the walker keeps going at 2.3 m/s. - Four false reversals. The gait's reversal check flipped the direction of travel at 30, 53, 69 and 166 s. None was a reversal. - Why it fires. The check integrates the IMU over 4 s, and on this sequence that drifts by about 3 m/s. The IMU velocity over the last 1–2 s still reads +2 m/s at the moment of the flip. Shield_tunnel2 is the fastest walk (about 2.2 m/s). - It never fires correctly under v13. On the other eleven handheld sequences it does not fire at all. The walkers always turn with the sensor, and the body-fixed direction handles that.
v14 is v13 with gait_reversal_lookback_sec: 0 for β and γ (configs/geode/rko_lio_{alpha,beta,gamma}_v14.yaml), with no code change.
- Shield_tunnel2: 165 → 26.9 m. The remaining error is a heading drift of 20–40°, not the direction of travel.
- Every other sequence: unchanged. The check never fired on them, and Shield_tunnel1, 7 and 8 were rerun and give byte-identical trajectories.
- Totals over the 18 sequences: median 5.6 m, eleven below 10 m.
This was decided by looking at Shield_tunnel2 itself, so Shield_tunnel2 is no longer a held-out result.
Step length: learning longer does not help. The learned steps are mostly short of the ground truth (Shield_tunnel6 −9 %, Shield_tunnel5 −8 %, Shield_tunnel8 −4.5 %), and that is Shield_tunnel8's loss under v13: its featureless stretches come out 6 % short. - 300 samples instead of 100. Learning from 300 plausible scans (30 s) instead of 100 does not bring the steps closer to the truth (Shield_tunnel1 0.69 against 0.74 m). The registered speed itself is short while learning, not just at the onset of the walk. - Result. The median rises to 6.1 m (4 wins, 6 losses against v13), so it was not adopted. - Sensitivity. Single runs are sensitive. Shield_tunnel10 goes from 2.88 to 6.53 m with the step changed from 0.772 to 0.771 m, so small differences between configurations are not resolved by one run per sequence. - Other step models. A step that depends on cadence explains little (RMS speed error 0.105 → 0.099 m/s on Shield_tunnel8). Weinberg's amplitude model helps on eight of ten shield sequences but adds a −0.11 m/s bias on Shield_tunnel1 and 7.
v15: the vehicle's attitude¶
The α trajectories dive into the ground. On the vehicle-mounted α device (16-beam Velodyne, 9–31 m/s), every method we ran tilts its up direction away from the true one: 40–80° by the end of bridge02 and Urban_Tunnel03, for v10, v14 and BIEVR-LIO alike. The estimated motion climbs or dives at 10–60° on roads whose grade stays under 4°. The speed itself is mostly right.
Two causes: - The registration pulls the pitch. On Urban_Tunnel03 the estimated pitch turns at about 1.5°/s for 15 s, while the car drives straight at 17–20 m/s and the gyro sees about 0.3°/s. - The gyro bias is wrong from the start. The gyro has an x bias of about 0.3°/s. The static initialization takes it from one scan interval, and so gets 0–0.6°/s depending on how the sequence starts. On bridge03, which starts at 13.5 m/s, it gets 4°/s.
What did not help: the gravity regularization alone (min_beta, removed in v11), LiDAR time offsets of ±50 ms, and turning deskew off.
The fix (rko_lio #34, default off). v15 is v14 plus the following for α only (configs/geode/rko_lio_{alpha,beta,gamma}_v15.yaml):
- Roll and pitch from the gyro. max_tilt_correction_deg: 0.02 limits each scan's change to the gyro-predicted roll and pitch. Yaw stays with the registration.
- Absolute tilt from gravity. The gravity window alignment re-levels the absolute tilt. The window alone already halves the tilt.
- Moving start. initialization_max_gyro_rad_s: 0.02 leaves the IMU biases at zero when the vehicle is already turning at the start (bridge03).
The estimated tilt stays within about 9°.
| sequence (α) | v10 | v14 | v15 | BIEVR-LIO |
|---|---|---|---|---|
| bridge01 | 46.2 | 116 | 22.7 | 109 |
| bridge02 | 246 | 192 | 109 | 190 |
| bridge03 | 1088 | 681 | 1075 | 879 |
| Urban_Tunnel01 | 560 | 334 | 272 | 169 |
| Urban_Tunnel02 | 260 | 89.8 | 38.4 | 680 |
| Urban_Tunnel03 | 159 | 200 | 59.3 | 69,283 |
| median | 253 | 196 | 84 | 435 |
Verdict: adopted for GEODE. - Against v14. v15 wins five of the six α sequences. - bridge03 still fails. It starts at 13.5 m/s on a bridge that gives no hold along the road, so the registration starts from zero speed and stays there for 150 s. Without the moving-start guard, the tilt limit locks in the bad bias and the run stops producing poses. - No held-out sequence. The variants were tried on all six α sequences, so none of them is held out. - Overall median unchanged. The median of all 18 stays at 5.6 m, because every α sequence is above it. - Online gyro bias rejected. An online gyro bias estimate from the registration's rotation was tried and rejected: it absorbs the registration's pitch pull into the lateral bias (±0.6°/s) and does not beat v15.
v16: the vehicle's stalls¶
Urban_Tunnel01 stalls twice. Under v15 the registration locks to the map behind it at 112 s and at 195 s. Each time the speed falls from 9 m/s to zero within about two seconds (about −4.5 m/s²), and the second stall lasts about 60 s while the car drives on at about 10 m/s; BIEVR-LIO keeps that speed through both. When the stall ends, the speed jumps back from zero to 10.8 m/s within a second. Neither change is possible for a car without the accelerometer seeing it.
Integrating the accelerometer for longer than a few seconds does not work on α. The tilt error that v15 leaves (up to about 9°) leaks up to 1.5 m/s² of gravity into the forward acceleration. Every variant that integrated it beyond a short window failed, as listed under "What did not work" below.
The fix (rko_lio #35, default off). vehicle_stall_guard uses the accelerometer over a 2 s window only:
- Detect. A stall is a registered speed that falls more than 3 m/s below what the accelerometer allows over the window and below half of it.
- Hold. While the stall lasts, the guard keeps the pre-drop speed constant.
- Release. The hold ends when the registration agrees with it within 1 m/s for 10 scans.
The parameters were fixed before the runs. v16 is v15 plus vehicle_stall_guard: true for α only (configs/geode/rko_lio_{alpha,beta,gamma}_v16.yaml).
| sequence (α) | v15 | v16 | BIEVR-LIO |
|---|---|---|---|
| bridge01 | 22.7 | 22.7 | 109 |
| bridge02 | 109 | 109 | 190 |
| bridge03 | 1075 | 1075 | 879 |
| Urban_Tunnel01 | 272 | 23.7 | 169 |
| Urban_Tunnel02 | 38.4 | 38.4 | 680 |
| Urban_Tunnel03 | 59.3 | 59.3 | 69,283 |
| median | 84 | 48.9 | 435 |
Where the guard acts. - Urban_Tunnel01. The guard fires twice and holds the speed for 24 scans in all, about 1.2 s. That is enough: the registration leaves both stalls and then follows BIEVR-LIO's speed within about 1 m/s. - The other five sequences. It never fires, and the trajectories are byte-identical to v15.
What did not work:
- kinematic_velocity_gate. The hard per-scan clamp fires on scan noise in 58 % of the scans, skips their map insertion, and runs away to 28 m/s (233 m).
- kinematic_velocity_blend, as built for walking. It seeds the accelerometer propagation from the registration only once, so over minutes the propagation drifts to the 40 m/s cap (1476 m).
- The blend re-seeded on every agreement. This fixes Urban_Tunnel01 (24.7 m), but the gravity leak drags correct registrations with it: bridge01 69.4 m, Urban_Tunnel02 645 m. With a looser agreement threshold of 2 m/s, the gradual collapse passes as agreement and Urban_Tunnel01 stays at 266 m.
- The guard without the speed-ratio condition. Ordinary slowdowns that the accelerometer misses trip it. The held speed then builds the map, each release looks like a new drop, and the speed ratchets up to 25 m/s (Urban_Tunnel01 637 m, Urban_Tunnel03 349 m).
Verdict: adopted for GEODE. - Pre-declared rule. The α median had to improve and no α sequence could worsen by more than 20 %. v16 meets it: the median goes from 84 to 48.9 m and nothing worsens. - No held-out sequence. As for v15, no α sequence is held out. - Overall median unchanged. The 18-sequence median stays at 5.6 m with eleven sequences below 10 m: Urban_Tunnel01 at 23.7 m is still above both.
Re-run on the Livox internal IMU (2026-10-13)¶
All eight γ sequences were re-run on the Livox internal IMU (see Inputs). α and β keep the Xsens and are unchanged. RKO-LIO v11 here is v16 without the gait options, which for γ is exactly the v11 configuration. ATE in metres:
| sequence (γ) | Xsens offset | RKO-LIO v16 on the Xsens | RKO-LIO v11 | RKO-LIO v16 | BIEVR-LIO | FAST-LIO2 | Point-LIO |
|---|---|---|---|---|---|---|---|
| Shield_tunnel1 | 47.5 ms | 6.38 | 99.5 | 0.82 | 0.26 | 269 | 90.5 |
| Shield_tunnel2 | 42.5 ms | 26.9 | 77.7 | 10.8 | 0.53 | 155 | 98.7 |
| Shield_tunnel3 | 35 ms | 2.28 | 59.7 | 1.17 | 1.17 | 428 | 65.8 |
| Shield_tunnel4 | 30 ms | 4.82 | 5.41 | 24.4 | 2.50 | 7016 | 68.9 |
| Shield_tunnel5 | 12.5 ms | 2.71 | 20.0 | 2.47 | 3.19 | 46,833 | 156 |
| Shield_tunnel6 | 7.5 ms | 0.94 | 0.52 | 12.6 | 0.40 | 153 | 32.6 |
| flat_surfaces_smooth | 80 ms | 2.20 | 2.43 | 1.61 | 2.00 | 408 | 2.82 |
| flat_surfaces_aggressive | 32.5 ms | 3.13 | 5.39 | 3.39 | 8646 | 496 | 6.04 |
Shield tunnels. - BIEVR-LIO is the best. It tracks all six γ shield tunnels, with a median of 0.85 m. RKO-LIO v16's median is 6.6 m, and it loses Shield_tunnel2, 4 and 6 by 10–24 m. - The gait prior does not transfer. v16 was tuned on the Xsens. On the better input it gets worse on Shield_tunnel4 (4.82 → 24.4 m) and Shield_tunnel6 (0.94 → 12.6 m). Without the gait (v11), RKO-LIO fails Shield_tunnel1, 2, 3 and 5. - Geometric LIOs still fail. FAST-LIO2 and Point-LIO fail every γ shield tunnel on the internal IMU as well.
What BIEVR-LIO needs on Shield_tunnel1. Both of the following make it diverge: - Coarse pixels. Pixels of 0.5 m, the voxel size, which removes the 5 cm surface relief of its bump images (78,984 m). - A short inertial window. An inertial window of 0.5 s instead of 10 s (24 million m). This window may simply be too short to be well posed, so the result does not show the long window's role in the tunnel.
flat_surfaces_aggressive. BIEVR-LIO diverges there on the internal IMU too.
Medians over the 18 sequences. These use the γ results above and the α and β results from the earlier tables:
| RKO-LIO v16 | BIEVR-LIO | Point-LIO | FAST-LIO2 | |
|---|---|---|---|---|
| median ATE | 8.5 m | 78.7 m | 97.6 m | 462 m |
| below 10 m (of 18) | 9 | 8 | 2 | 0 |
| median on the six γ shield tunnels | 6.6 m | 0.85 m | 79.7 m | 349 m |
RKO-LIO v16 has the lowest median over the 18 sequences because it holds the handheld Ouster (β) and vehicle (α) sequences. On the Livox shield tunnels, BIEVR-LIO is better.
The γ shield tunnels are decided by the prediction (2026-10-13)¶
Fixed-point test on Shield_tunnel2 (γ). - Setup. Each scan is registered from a reference pose built from the ground truth. The reference then replaces the result, so the map and the state stay on it. The log records the registered pose relative to the reference. - Offset. The start of each registration is moved 0.3 m ahead of or behind the reference along the motion. - Measure. Median distance between the registered pose and the reference, without the first and last 20 s:
| offset 0 | +0.3 m | −0.3 m | |
|---|---|---|---|
| RKO-LIO v11 | 0.019 m | 0.288 m | 0.293 m |
| BIEVR-LIO | 0.000 m | 0.287 m | 0.283 m |
No pull back. Neither registration pulls the pose back along the tunnel. An error the prediction brings along the axis stays, so on the γ shield tunnels the accuracy comes from the prediction, and BIEVR-LIO's prediction uses the velocity from its 10 s inertial window.
Gravity in RKO-LIO's window (W1).
- Fixed gravity. RKO-LIO's inertial window (rko_lio #30) holds gravity fixed. On Shield_tunnel4 and 5 its accelerometer bias ran away after the turnarounds.
- BIEVR-LIO's window. It estimates the gravity direction in the same window.
- W1. It adds that estimate to RKO-LIO's window (rko_lio tag archive/feat/inertial-window-gravity, not merged): two tangent unknowns on the direction, a prior of weight 5 toward the current estimate, and propagation with the estimated gravity.
- Configuration. On γ, W1 is v11 (no gait) with the window on.
ATE in metres:
| sequence (γ) | W1 | BIEVR-LIO | RKO-LIO v16 | RKO-LIO v11 |
|---|---|---|---|---|
| Shield_tunnel1 | 0.49 | 0.26 | 0.82 | 99.5 |
| Shield_tunnel2 | 0.42 | 0.53 | 10.8 | 77.7 |
| Shield_tunnel3 | 1.19 | 1.17 | 1.17 | 59.7 |
| Shield_tunnel4 | 1.95 | 2.50 | 24.4 | 5.41 |
| Shield_tunnel5 | 1.77 | 3.19 | 2.47 | 20.0 |
| Shield_tunnel6 | 0.46 | 0.40 | 12.6 | 0.52 |
| median of the six | 0.84 | 0.85 | 6.6 | 39.9 |
| flat_surfaces_smooth | 3.47 | 2.00 | 1.61 | 2.43 |
| flat_surfaces_aggressive | diverges | 8646 | 3.39 | 5.39 |
On the Xsens devices, W1 is v16 with the window on:
| sequence | W1 | W1 without the gait | RKO-LIO v16 |
|---|---|---|---|
| Shield_tunnel7 (β) | 391 | 146 | 1.87 |
| Shield_tunnel8 (β) | 152 | 547 | 6.28 |
| Shield_tunnel9 (β) | 52.8 | 154 | 1.69 |
| Shield_tunnel10 (β) | 112 | 275 | 2.88 |
| bridge01 (α) | 20.0 | 22.7 | |
| bridge02 (α) | 94.5 | 109 | |
| bridge03 (α) | 809 | 1075 | |
| Urban_Tunnel01 (α) | 27.4 | 23.7 | |
| Urban_Tunnel02 (α) | 39.8 | 38.4 | |
| Urban_Tunnel03 (α) | 63.1 | 59.3 |
- The γ gap closes. W1 matches BIEVR-LIO on the γ shield tunnels (median 0.84 m against 0.85 m) without the gait prior, and is the best on Shield_tunnel2, 4 and 5.
- Not adopted. W1 diverges on flat_surfaces_aggressive, as BIEVR-LIO does; there its gravity estimate ends 31° from vertical. It loses all four β sequences with or without the gait, and flat_surfaces_smooth doubles (1.61 → 3.47 m). On α it gains on the bridges and loses up to 16 % on the urban tunnels.
- β is open. β's Xsens runs 7.5 ms off its Ouster internal IMU. Whether β fails because of that offset or because of the window itself is not yet known.
Why W1 fails, and what it needs (2026-10-14)¶
The experiments below are on rko_lio tag archive/exp/inertial-window-gravity-tilt-limit (not merged).
β on its Ouster internal IMU. Shield_tunnel7 and 10 were converted with /ouster/imu. The Ouster IMU-to-sensor offset is the standard OS1 one: (6.253, −11.775, 7.645) mm, no rotation. ATE in metres:
| β | v16 on the Xsens | v16 | W1 | W1 without the gait | W1, gait keeps the speed |
|---|---|---|---|---|---|
| Shield_tunnel7 | 1.87 | 2.85 | 151.6 | 63.6 | 2.84 |
| Shield_tunnel10 | 2.88 | 2.38 | 0.77 | 133.0 | 2.35 |
- Not the Xsens offset. W1 still loses Shield_tunnel7 on the Ouster IMU.
- The window overrides the gait.
- Shield_tunnel7's registration stalls between 60 and 140 s on the periodic lining.
- The window holds the registered poses fixed, so it fits a velocity of nearly zero to them, and its velocity replaces the gait speed. The prediction stalls with the registration.
- After 240 s the window runs at 4–12 m/s; the ground truth is 1.3 m/s.
- The gait keeping the speed. With the gait's speed re-applied after the window solve, both β sequences match v16, so the failure is gone. Shield_tunnel10's 0.77 m with the plain window is gone too.
The γ IMU-to-LiDAR rotation. - Estimate. The Livox gyro rates against the registered trajectory's rotation rates give a rotation of about 0.9° from the LiDAR axes, mostly roll: - Shield_tunnel1: (0.86, 0.36, 0.19)°, from 5014 scan pairs; - Shield_tunnel2: (0.79, 0.37, 0.29)°, from 4270 scan pairs. - Before. BIEVR-LIO's configuration, and every γ run above, assumed none.
ATE in metres, γ:
| sequence (γ) | v16 | W1 | W1 + rotation | fixed-gravity window + rotation | BIEVR-LIO |
|---|---|---|---|---|---|
| Shield_tunnel1 | 0.82 | 0.49 | 0.69 | 0.55 | 0.26 |
| Shield_tunnel2 | 10.8 | 0.42 | 0.46 | 0.46 | 0.53 |
| Shield_tunnel3 | 1.17 | 1.19 | 1.20 | 1.18 | 1.17 |
| Shield_tunnel4 | 24.4 | 1.95 | 1.82 | 2.65 | 2.50 |
| Shield_tunnel5 | 2.47 | 1.77 | 1.73 | 11.8 | 3.19 |
| Shield_tunnel6 | 12.6 | 0.46 | 0.49 | 11.1 | 0.40 |
| flat_surfaces_smooth | 1.61 | 3.47 | 2.49 | 5.98 | 2.00 |
| flat_surfaces_aggressive | 3.39 | diverges | 55.3 | 767 | 8646 |
- The rotation helps W1 on the flats. flat_surfaces_aggressive no longer diverges (55 m), flat_surfaces_smooth goes from 3.47 to 2.49 m, and the shield tunnels barely move.
- The gravity estimate is still needed. With the rotation corrected, a window with fixed gravity still loses Shield_tunnel5 and 6. The estimated tilt of 1.6–2.7° is more than the 0.9° rotation explains.
- A tilt limit does not work. Limiting the gravity estimate to 3° or 5° around its seed keeps the other shield tunnels but loses Shield_tunnel5 (1814 / 561 m). flat_surfaces_aggressive then pins the tilt at the limit and runs both biases to their clamps (1 m/s², 0.1 rad/s). On the six good tunnels the window ends at 0.25–0.34 m/s² and below 0.005 rad/s.
Where this leaves the window. Its weakness is the one BIEVR-LIO shares: the registered poses are held fixed. A registration that stalls (β) or breaks under fast motion (flat_surfaces_aggressive) is fitted rather than rejected. The gait keeping the speed removes the β failure but also the β gain.
Six ways to make the window robust (2026-10-14)¶
Setup.
- Code. rko_lio tag archive/exp/inertial-window-gravity-tilt-limit, commit 2c618dd (not merged). Every option is off by default.
- Base. Each variant starts from W1 + rotation (W1R, above).
- Rule, fixed before each run.
- Every γ shield tunnel stays within 10 % of W1R.
- flat_surfaces_smooth ≤ 3.2 m and flat_surfaces_aggressive ≤ 6.8 m, twice v16.
- Thresholds. They come from the shield tunnels only.
ATE in metres, γ. A dash marks a run that was not made, or was stopped, once the variant had already failed the rule.
| variant | ST1 | ST2 | ST3 | ST4 | ST5 | ST6 | smooth | aggressive |
|---|---|---|---|---|---|---|---|---|
| W1R | 0.69 | 0.46 | 1.20 | 1.82 | 1.73 | 0.49 | 2.49 | 55.3 |
| drop a window whose mean cost exceeds 0.004 | 0.69 | 0.46 | 1.20 | 1.82 | 1.73 | 0.49 | 4.40 | 3.61 |
| Cauchy weight per interval, scale 0.03 | – | – | – | – | – | – | 3.16 | diverges |
| bump image off | – | – | – | – | – | – | 353 | 338 |
| attitudes pulled onto the gyro chain | 0.48 | 0.56 | – | – | – | – | 2.21 | 29.3 |
| the same with slow priors | – | – | – | – | – | – | 2.56 | 191 |
| window velocity on weak axes only | 0.54 | 0.49 | 1.21 | 2.01 | 3.46 | 0.51 | 1.60 | diverges |
| v16 | 0.82 | 10.8 | 1.17 | 24.4 | 2.47 | 12.6 | 1.61 | 3.39 |
| BIEVR-LIO | 0.26 | 0.53 | 1.17 | 2.50 | 3.19 | 0.40 | 2.00 | 8646 |
None passes. Each failure:
- The cost separates sequences, not fits.
- Values. The window's mean weighted residual stays at or below 0.0012 in the shield tunnels. On flat_surfaces_smooth its median is 0.0026, and 45 % of the windows exceed 0.004.
- Effect of the gate. It drops those windows. Smooth's prediction then has neither the window's velocity nor a hold from the flat registration. The first drop is at 32.6 s, and by 35 s the gated run is 2.75 m from the ungated one.
- Where it helps. It does stop flat_surfaces_aggressive, where the cost reaches 0.084.
- The inconsistency is spread out. On the flats, the costliest 1 % of intervals carry only 24–34 % of the cost. Down-weighting them does not stop aggressive.
- The flats' registered rotations jitter. In v16's runs, the registered rotation rate differs from the gyro by about a third of the rate: 0.115 rad/s on smooth and 0.287 rad/s on aggressive. Shield_tunnel2 shows 0.027 rad/s, 6 %.
- Not calibration. There is no scale error (1.01–1.02) and no time offset (+2.5 to +5 ms). The difference is noise of 0.7° and 1.6° per scan.
- The bump image is not the cause. It turns the flats' scans by 2.1° and 3.8° on average, and falls back to point-to-point 218 and 402 times, against 2–5 in the shield tunnels. Yet without it the window diverges on both flats.
- Smoothing the attitudes removes the jitter, not the failure.
- Method. The window pulls the registered attitudes onto the gyro chain before it solves: σ 0.005 rad per attitude, 0.001 rad per interval.
- Effect. It cuts the attitude error fourfold on synthetic data, and smooth goes to 2.21 m.
- What remains. Smooth's window cost barely moves (median 0.0024). The inconsistency left is in translation.
- Gravity follows each window's fit.
- The cause. The window's data outweigh the gravity prior (weight 5) about 4 to 1, and the accelerometer-bias prior (weight 1) about 1 to 1. Gravity therefore follows the window's own fit within a solve or two.
- Observed rates. In Shield_tunnel5 the tilt moves 0.044°/s on average. On aggressive it runs away at 0.2–1°/s.
- Slow priors do not help. With time constants of about 10 s for gravity and 30 s for the bias (weights 100 and 17), aggressive still fails (191 m).
- The registration's weak axis.
- Shield tunnels. The smallest normalised eigenvalue of the registration's translation information (world frame) has a median of 0.009–0.011. Its eigenvector lies along the motion (|cos| 0.99).
- Flats. The median is 0.11–0.14, but a third of the scans fall below 0.05.
- Result. Taking the window's velocity only along axes below 0.05 gives the best flat_surfaces_smooth of any run, 1.60 m. It doubles Shield_tunnel5, though, and diverges on aggressive at 13 s: after two weak scans the registration loses its correspondences (isotropic, then empty, information), and the window carries the state away.
Where this leaves the window. In every failure the window fits poses it should not trust: - rotations that jitter from scan to scan; - a registration that slides along its weak axes; - on aggressive, a registration lost for seconds.
A window that holds the registered poses fixed cannot tell these apart from motion.
A seventh way: soft positions (2026-10-14). - Method. The window estimates a correction of each registered position as well. Each scan's registration information is the prior: its translation block with the rotation marginalised, scaled so that the strongest direction has σ 2 cm. The IMU residuals get σ 0.03 m/s and 5 mm per interval, and the attitudes are smoothed as above. - Result. It does not help. - flat_surfaces_aggressive diverges again. - flat_surfaces_smooth goes to 3.07 m. - Synthetic stall. A registration that stalls for 1 s and then stays behind still pulls the window's speed. With σ 0.14 m along the stalled axis, the worst error is 0.68 m/s; fixed positions give 0.71 m/s. Only a much weaker prior along the axis lets the IMU win. - β's long stalls. These stay out of reach: the IMU cannot tell a constant speed from standing still.
An eighth way: the window where it agrees with the gait (2026-10-15).
- Method. v18 plus W1, its consistency gate (0.004) and, on γ, the IMU rotation. The window's velocity stays only while its speed along the gait's direction is within 30 % of the gait's speed; otherwise the gait's speed is applied (rko_lio tag archive/exp/inertial-window-hybrid).
- Rule. The method and v18's rule were fixed before the runs.
- Result. ATE in metres:
| ST1 | ST2 | ST3 | ST4 | ST5 | ST6 | smooth | aggr. | ST7 | ST8 | ST9 | ST10 | Stairs α | Stairs β | mean | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| v18 | 1.13 | 2.76 | 0.99 | 2.94 | 2.63 | 0.55 | 1.61 | 4.27 | 2.38 | 4.60 | 0.58 | 2.34 | 0.18 | 0.24 | 1.94 |
| window where it agrees | 0.40 | 3.19 | 1.24 | 2.14 | 0.95 | 5.56 | 4.41 | 2.81 | 2.80 | 9.45 | 2.75 | 5.33 | 0.18 | 0.18 | 2.96 |
- Verdict. Shield_tunnel1 and 5 reach BIEVR-LIO's level, but Shield_tunnel6, flat_surfaces_smooth and three β tunnels fail the rule. Not adopted.
- Not the stalls alone. The check gave the speed back to the gait on only 1–6 % of the solves in the shield tunnels, so β's losses are not only its stalls.
v17: a walker's bounds between steps (2026-10-14)¶
What goes wrong in v16. v16 loses Shield_tunnel4 and 6 (γ) in a single event each: - Shield_tunnel6, 112–116 s. - The walker stands (ground truth 0.1–0.5 m/s), and the gait's 4 s window loses the cadence. - The velocity then comes from the registration's displacement over 0.3 s. In the tunnel nothing holds that displacement along the travel. - After one registration jumps 2.7 m, the speed holds at 6.7–9 m/s for 4 s. - Shield_tunnel4, 156–168 s. - The walker stops and turns around. - The cadence stays lost for up to 3.7 s after walking resumes. - The speed runs to 10 m/s in the old direction.
v17. rko_lio #38 adds gait_hold_without_cadence. Once the step length is learned, it holds a scan that has no cadence and whose registered speed exceeds the last gait speed:
- Standing. If the specific force's magnitude varies by less than 0.3 m/s² (std over the last second), the velocity is zero.
- Otherwise. The speed along the direction of travel stays between 0 and the last gait speed.
- The correction limit stays on. The registration's correction along the travel stays limited to 2 cm per scan, as while the gait drives the prediction.
Rule, fixed before the runs. Two conditions: - No sequence may be more than 10 % worse than v16, or 0.1 m below 1 m. - The median on the six γ shield tunnels must drop.
ATE in metres, from one binary. "Every gap" is the first version, which held every scan without a cadence.
| sequence | v16 | every gap | v17 |
|---|---|---|---|
| Shield_tunnel1 (γ) | 0.82 | 0.66 | 0.79 |
| Shield_tunnel2 (γ) | 10.79 | 11.77 | 10.32 |
| Shield_tunnel3 (γ) | 1.17 | 1.18 | 0.95 |
| Shield_tunnel4 (γ) | 24.36 | 6.12 | 4.21 |
| Shield_tunnel5 (γ) | 2.47 | 3.62 | 2.63 |
| Shield_tunnel6 (γ) | 12.60 | 0.47 | 0.55 |
| flat_surfaces_smooth (γ) | 1.61 | 1.61 | 1.61 |
| flat_surfaces_aggressive (γ) | 3.39 | 3.39 | 3.39 |
| Shield_tunnel7 (β) | 1.87 | 1.85 | 1.87 |
| Shield_tunnel8 (β) | 6.28 | 6.60 | 6.58 |
| Shield_tunnel9 (β) | 1.69 | 0.98 | 1.69 |
| Shield_tunnel10 (β) | 2.88 | 1.29 | 2.84 |
- Every gap fails on Shield_tunnel5 (2.47 → 3.62 m).
- What happens. In its turn at 127–131 s the walker moves at 0.5–0.8 m/s, but the sensor shakes as little as in Shield_tunnel6's stand: 0.13–0.25 m/s², against 0.13–0.21 m/s². The velocity was set to zero.
- What tells the two apart. The registration's speed was below the last pace there. In Shield_tunnel6 it ran at 7–9 times the last pace.
- v17 holds only a registration faster than the last pace. It was designed after that failure and passes the rule.
- The largest loss is Shield_tunnel5, at +6.5 %.
- The γ shield tunnel median drops from 6.6 to 1.8 m. BIEVR-LIO's is 0.85 m.
- β stays within 5 %.
- The holdout is still needed. Both versions were developed on these sequences. The unseen Metro Tunneling sequences are the check (Next, item 3).
Medians over the 18 sequences. α is unchanged, because v17 is v16 there.
| RKO-LIO v17 | RKO-LIO v16 | BIEVR-LIO | |
|---|---|---|---|
| median ATE | 3.8 m | 8.5 m | 78.7 m |
| below 10 m (of 18) | 11 | 9 | 8 |
| median on the six γ shield tunnels | 1.8 m | 6.6 m | 0.85 m |
Configurations. configs/geode/rko_lio_{alpha,beta,gamma}_v17.yaml:
- α. It is v16 unchanged.
- β. It is v16 plus the hold.
- γ. It is v16 plus the hold, with the Livox internal IMU's extrinsic from Inputs. The earlier γ files hold the Xsens extrinsic, and the γ runs since 2026-10-13 used the Livox extrinsic.
What v17 leaves: the walker's stops (2026-10-14)¶
The overshoot. - Measure. Around each ground-truth stop (below 0.4 m/s), the estimated path over ±3 s is compared with the true one. - Where. On many stops of Shield_tunnel2 and 4 (γ) and Shield_tunnel8 and 10 (β), v17's path is 1.6–4.2 m longer than the true one. - Cause. The cadence comes from a 4 s window, so cadence × step is the speed of about 2 s ago. A walker who brakes to turn keeps the gait's speed until the window empties. - Shield_tunnel2. Its 10.3 m comes from one such turnaround at 184 s. After it, the map's tilt changes, and on the way back the height error grows to 30 m. W1, whose speed comes from the IMU window, keeps the height error below 6 m and ends within 0.5 m of the truth.
Carrying the gait speed over the lag with the IMU fails.
- Code. rko_lio tag archive/exp/gait-imu-lag-compensation, d977c02, not merged.
- Method. It takes cadence × step as the speed half a window ago, and carries it to now with the IMU's velocity change since then. That change is in the world frame, with the 30 s mean acceleration removed.
- Rule. The same as for v17.
ATE in metres:
| sequence | v17 | lag compensation |
|---|---|---|
| Shield_tunnel1–6 (γ) | 0.79 / 10.32 / 0.95 / 4.21 / 2.63 / 0.55 | 4.07 / 7.71 / 8.88 / 41.7 / 9.04 / 3.74 |
| Shield_tunnel7–10 (β) | 1.87 / 6.58 / 1.69 / 2.84 | 0.73 / 11.6 / 2.43 / 6.07 |
- Result. It loses eight of the ten shield tunnels. The flats are unchanged, because the step is never learned there.
- Why. On these inputs, two seconds of IMU integration are not reliable enough. v14 learned the same with the gait's IMU reversal check.
Following the steps themselves.
- Code. rko_lio tag archive/exp/gait-step-events, not merged.
- 6ac1450 is stop and restart.
- 9024b54 is stop only.
- The step events. A causal 0.8–4 Hz band-pass of the specific force magnitude finds the peaks. A peak counts if it is above a quarter of the running median peak, with a floor of 0.3 m/s².
- What they show. A stop shows 1.5–2 s before the cadence window does. On Shield_tunnel2 the last step is at 184.4 s, and the cadence is gone at 187 s. A restart shows as much earlier. While walking, the steps report a stop for 0–1.4 s per sequence, at most 0.5 % of the walk.
- A first build skipped peaks. It decided one IMU sample per call. The Livox internal IMU's stamps come in bursts, so it skipped peaks: 61 s of false stops on Shield_tunnel1, against 0.9 s after the fix. A test now feeds burst stamps.
Two uses, with the rule of v17 fixed before the runs: - Stop and restart. No step for 1 s sets the velocity to zero. Steps without a cadence keep the last gait speed. - Stop only. It keeps only the first part.
ATE in metres:
| sequence | v17 | stop and restart | stop only |
|---|---|---|---|
| Shield_tunnel1 (γ) | 0.79 | 0.82 | 0.78 |
| Shield_tunnel2 (γ) | 10.32 | 2.80 | 1.63 |
| Shield_tunnel3 (γ) | 0.95 | 1.46 | 3.82 |
| Shield_tunnel4 (γ) | 4.21 | 2.71 | 3.92 |
| Shield_tunnel5 (γ) | 2.63 | 2.76 | 4.21 |
| Shield_tunnel6 (γ) | 0.55 | 0.52 | 0.46 |
| Shield_tunnel7 (β) | 1.87 | 2.51 | 1.84 |
| Shield_tunnel8 (β) | 6.58 | 5.68 | 5.55 |
| Shield_tunnel9 (β) | 1.69 | 1.37 | 2.80 |
| Shield_tunnel10 (β) | 2.84 | 1.29 | 2.25 |
| median of the ten | 2.25 | 1.99 | 2.53 |
- Neither passes.
- Stop and restart loses Shield_tunnel3 (+0.51 m) and Shield_tunnel7 (+34 %).
- Stop only loses Shield_tunnel3, 5 and 9.
- The stop alone undershoots.
- Why. After a zeroed stop, the tunnel registration accelerates only as fast as its own prediction, so the walker's restart is lost.
- What the restart rule recovers, and where it fails. Keeping the last pace on the first steps restores most of the restart. But turning on the spot also steps, so on Shield_tunnel3 and 7 the pace runs while the walker turns.
- v17 stays. Stop and restart would bring the 18-sequence median from 3.8 to 2.8 m, with twelve sequences below 10 m. It would also bring the worst shield tunnel from 10.3 to 5.7 m. It fails the rule, though.
- The development set is used up. The twelve handheld sequences have been the development set for v12 to v17 and the variants above. Choosing a further gait variant by them alone risks fitting them. Handheld sequences it was not developed on are needed.
v18: the gait's correction limit only where the scan cannot see (2026-10-14)¶
Handheld sequences outside the development set.
- What exists. GEODE's Stairs sequences are its only handheld sequences outside the Hard set. Each device has one: Stairs_Alpha (the VLP-16 carried by hand), Stairs_Beta and Stairs_Gamma.
- Ground truth. The data folder has ground truth for α (stairs_alpha.txt) and for β (stairs_bob.txt, whose times match Stairs_Beta). It has none for γ.
- The α configuration. α has no handheld configuration. rko_lio_alpha_handheld_v18.yaml is α v16 without its five vehicle options, plus β's handheld options. The runs below with the v16 and v17 gaits use the same base.
The gait fails on stairs. ATE in metres:
| Stairs α | Stairs β | |
|---|---|---|
| v16 | 6.92 | 6.42 |
| v17 | 6.47 | 6.32 |
| without the gait (v11) | 0.16 | 0.26 |
- Why. The step learned on the flat (0.65–0.70 m) makes the gait set too high a speed on the stairs.
- The correction limit makes it worse. The limit (2 cm per scan) keeps the registration from correcting that speed. It fires on about 75 % of the scans.
Where to apply the gait. The registration's weakest translation share is the smallest eigenvalue of its translation information over the trace: - in the shield tunnels, a median of 0.005–0.012; - on the stairs, a 10th percentile of 0.11–0.16.
Two ways of gating on it fail, and the second works: - Gating the whole gait fails in the tunnels. At a turnaround the scan sees the end wall for moments, and the gait stands back: Shield_tunnel4 goes from 4.21 to 9.57 m. With a 3 s persistence it still loses Shield_tunnel1 (0.79 → 2.16 m) and Shield_tunnel7 (1.87 → 2.28 m). - Gating along the body's direction of travel fails too. Mid-turn that direction points at the wall: Shield_tunnel7 4.25 m. - v18. It keeps the gait's speed and limits only its correction to scans whose weakest share is below 0.05 (rko_lio #39). The 0.05 is the threshold set earlier from the shield tunnels. On the stairs the limit never applies, and the registration corrects the prediction freely.
ATE in metres on the fourteen handheld sequences:
| sequence | v17 | v18 |
|---|---|---|
| Shield_tunnel1 (γ) | 0.79 | 1.13 |
| Shield_tunnel2 (γ) | 10.32 | 2.76 |
| Shield_tunnel3 (γ) | 0.95 | 0.99 |
| Shield_tunnel4 (γ) | 4.21 | 2.94 |
| Shield_tunnel5 (γ) | 2.63 | 2.63 |
| Shield_tunnel6 (γ) | 0.55 | 0.55 |
| flat_surfaces_smooth (γ) | 1.61 | 1.61 |
| flat_surfaces_aggressive (γ) | 3.39 | 4.27 |
| Shield_tunnel7 (β) | 1.87 | 2.38 |
| Shield_tunnel8 (β) | 6.58 | 4.60 |
| Shield_tunnel9 (β) | 1.69 | 0.58 |
| Shield_tunnel10 (β) | 2.84 | 2.34 |
| Stairs α | 6.47 | 0.18 |
| Stairs β | 6.32 | 0.24 |
| mean | 3.59 | 1.94 |
The rule changed after the results. - Under v17's rule, v18 fails. That rule allowed no sequence more than 10 % worse than v17 (0.1 m below 1 m). v18 loses Shield_tunnel1 (+0.34 m), Shield_tunnel7 (+0.51 m) and flat_surfaces_aggressive (+0.88 m). - The new rule. v18 was adopted under a rule chosen after these results: - no sequence worse by more than 1 m or by more than 50 %; - a lower mean over the handheld sequences. - From now on that rule is fixed before the runs.
The rivals on the stairs. ATE in metres:
| Stairs α | Stairs β | |
|---|---|---|
| RKO-LIO v18 | 0.18 | 0.24 |
| BIEVR-LIO | 0.22 | 0.23 |
| FAST-LIO2 | diverges | 0.35 |
| Point-LIO | 11.1 | 0.29 |
These are not held-out results: v18 was developed on these two sequences.
Over the 18 Hard sequences. α is unchanged, because α v18 is α v17. - The median is 2.85 m (v17 3.8 m, BIEVR-LIO 78.7 m), with twelve sequences below 10 m (v17 eleven). - The median of the six γ shield tunnels is 1.9 m (v17 1.8 m, BIEVR-LIO 0.85 m).
The Metro Tunneling holdout, fixed before any run (2026-10-14)¶
Everything in this section was fixed before any method ran on these sequences. A change after the first run is reported as one.
The data.
- What it is. GEODE's Metro Tunneling sequences: a UGV carrying all three devices at once through tunnels under construction. tunnel1 has γ only; tunnel2–5 have α, β and γ, for 13 bags.
- Ground truth. One position-only trajectory per tunnel (Tunneling_tunnelN.txt) at about 3 Hz, like the shield tunnels, on the bags' clock. It covers the middle of each bag: 153 of tunnel1 γ's 209 s, 210 of tunnel2 α's 282 s.
- Lever arm. The IMU trajectory is scored directly, as on the shield tunnels. Each device has its own unpublished offset from the tracked point, the same for every method on that device.
Two halves.
- Run now: tunnel1–3 (7 bags). Tunneling_tunnel1 γ, and α, β and γ of tunnel2 and tunnel3. They test the configurations of this note on a platform and in tunnels none of them was developed on.
- Sealed: tunnel4–5 (6 bags). They stay the profile's hidden tunnel holdout. The profile allows a SOTA claim only with one parameter set across all sequences (one_parameter_set_across_all_sequences in degenerate_lio_sota_v4.yaml). The configurations here are not one: the gait is for the handheld devices, the vehicle options for the vehicle.
- No method runs on the sealed half until such a configuration is frozen, and its ground truth is not used.
- Releasing it earlier needs an entry here first.
The configurations.
- α. rko_lio_alpha_v18.yaml, the vehicle configuration developed on the six α sequences, unchanged.
- β and γ. rko_lio_{beta,gamma}_ugv_v18.yaml: v18 without its six gait options, plus α's five vehicle options with α's values. Those are gravity window alignment and relevelling, a 0.02° tilt correction limit, a 0.02 rad/s initialization gyro limit and the stall guard.
- Why no gait. Its cadence detector also fires on a vehicle's IMU: in 7–26 % of the 4 s windows on the α sequences, at 1.8–1.9 Hz.
- Untested. The vehicle options were developed on α only. These two configurations have not run on any data.
- IMUs. As on the Hard sequences: the Xsens on α and β, the Livox internal IMU on γ.
The rivals. COIN-LIO (β only), BIEVR-LIO, FAST-LIO2 and Point-LIO, with the files in configs/geode/rivals/ and the inputs of the Hard sequences.
Runs and scoring. - One run per method and bag, as on the Hard sequences. RKO-LIO runs rko_lio 80f3c1c, the submodule at this section's commit. - Scoring as on the Hard sequences (see Reproduction): SE(3) alignment, ATE and 10 m RTE. - Incomplete. A run that stops producing poses before the ground truth ends counts as the worst value in the medians. - Failure. A 10 m RTE of 20 % or more, the profile's failure line. - Faults. A harness fault, such as a wrong topic or a crash before the first pose, may be fixed and the run repeated. The fix and both outcomes are reported. The method and the configurations do not change after the first run.
What it can show, fixed now. - Reported either way. ATE and RTE per bag and method, the medians over the seven bags and per device, and the failures. - H1. RKO-LIO v18 has a lower median ATE over the seven bags than BIEVR-LIO, FAST-LIO2 and Point-LIO, and than COIN-LIO on the two β bags. - H2. RKO-LIO v18 has no failure on the seven bags. - No SOTA claim follows either way, because the configurations are not one parameter set.
The Metro Tunneling holdout: results (2026-10-14)¶
Every method ran once on the seven bags of tunnel1–3, with the configurations and the rules above. ATE in metres (10 m RTE):
| bag | RKO-LIO v18 | BIEVR-LIO | FAST-LIO2 | Point-LIO | COIN-LIO |
|---|---|---|---|---|---|
| tunnel1 γ | 0.84 (4.0 %) | 0.14 (1.6 %) | 0.19 (1.8 %) | 0.14 (1.6 %) | – |
| tunnel2 α | 2.46 (2.5 %) | 31,453 (94,074 %) | 40,335 (103,991 %) | 73,433 (185,087 %) | – |
| tunnel2 β | 0.58 (2.4 %) | 0.35 (1.9 %) | 0.35 (1.9 %) | 0.35 (1.9 %) | 7.24 (45.1 %) |
| tunnel2 γ | 2.27 (9.5 %) | 2.09 (8.8 %) | 1.58 (7.4 %) | 4.81 (17.7 %) | – |
| tunnel3 α | 0.72 (2.7 %) | 0.18 (1.4 %) | 8.33 (21.7 %) | 27.7 (97.3 %) | – |
| tunnel3 β | 0.36 (2.0 %) | 0.36 (2.1 %) | 0.36 (2.0 %) | 0.36 (2.1 %) | 9.63 (25.1 %) |
| tunnel3 γ | 2.94 (7.2 %) | 0.34 (1.8 %) | 0.33 (1.9 %) | 2.76 (5.9 %) | – |
| median | 0.84 | 0.35 | 0.36 | 2.76 | 8.44 (β only) |
| median, α | 1.59 | 15,727 | 20,172 | 36,730 | – |
| median, β | 0.47 | 0.36 | 0.36 | 0.36 | 8.44 |
| median, γ | 2.27 | 0.34 | 0.33 | 2.76 | – |
| failures | 0 of 7 | 1 of 7 | 2 of 7 | 2 of 7 | 2 of 2 |
- H1 fails. BIEVR-LIO (0.35 m) and FAST-LIO2 (0.36 m) have a lower median ATE than RKO-LIO v18 (0.84 m).
- H2 holds. RKO-LIO v18 is the only method without a failure.
- α. tunnel2 α has four LiDAR gaps of 0.4–2.9 s within 9 s. The three rivals diverge inside them, 63–67 s into the bag; RKO-LIO crosses them. On tunnel3 α BIEVR-LIO is better (0.18 against 0.72 m).
- β. Every method but COIN-LIO tracks both bags at 0.35–0.58 m.
- γ. RKO-LIO's median is 2.27 m, against 0.34 m for BIEVR-LIO and 0.33 m for FAST-LIO2. The γ device is also where BIEVR-LIO leads on the shield tunnels.
The tabulation was corrected after the run. - The first table. It counted a run as incomplete when less than 98 % of the ground truth was matched. That threshold is the profile's, and the pre-registration does not contain it. The pre-registration counts a run as incomplete when it stops producing poses before the ground truth ends. - What the 98 % caught. On the α bags every method matched 95.3–95.5 % (tunnel2) and 97.1 % (tunnel3) of the ground truth: - tunnel2 α's unmatched ground truth lies in its LiDAR gaps; - tunnel3 α's bag starts 12 s after its ground truth.
Every method produced poses until 30 s (tunnel2) and 59 s (tunnel3) after the ground truth ends. - Both outcomes. Under the first table all four methods are incomplete on both α bags: RKO-LIO's median is 2.27 m, and H1 and H2 both fail. The correction favours RKO-LIO, the only method that tracks tunnel2 α.
What follows. - On the UGV. The GEODE configurations carry over without a failure, but not with the best accuracy. On γ BIEVR-LIO and FAST-LIO2 are about seven times more accurate. - No SOTA claim, as fixed above. tunnel4–5 stay sealed.
After the holdout: where the γ gap comes from (2026-10-15)¶
tunnel1–3 are development data from here on: their holdout run is spent. tunnel4–5 stay sealed.
On the UGV: the tilt limit¶
RKO-LIO's γ error is vertical. Position errors after SE(3) alignment, split along the track, across it and vertically (RMS, m):
| bag | method | along | across | vertical |
|---|---|---|---|---|
| tunnel1 γ | RKO-LIO v18 | 0.19 | 0.64 | 0.52 |
| BIEVR-LIO | 0.14 | 0.03 | 0.02 | |
| tunnel2 γ | RKO-LIO v18 | 2.06 | 0.58 | 0.76 |
| BIEVR-LIO | 2.06 | 0.38 | 0.05 | |
| tunnel3 γ | RKO-LIO v18 | 2.66 | 1.04 | 0.72 |
| BIEVR-LIO | 0.15 | 0.31 | 0.02 |
- The re-levels do not explain it (corrected 2026-10-15). The gravity window re-levels the map 23–153 times per bag, by 0.36–0.40° each time. Without the limit the γ bags re-level even more often (45–205 times), so these counts do not show the limit's harm. An earlier version of this note read them as a drifting tilt.
- Which vehicle option. Every bag below ran once, ATE in metres:
| γ bag | v18 UGV | no vehicle options | no tilt limit | no gravity window |
|---|---|---|---|---|
| tunnel1 | 0.84 | 0.14 | 0.14 | 0.76 |
| tunnel2 | 2.27 | 2.09 | 2.09 | 2.91 |
| tunnel3 | 2.94 | 0.34 | 0.34 | 2.92 |
- The tilt limit alone. Without it RKO-LIO tracks the three γ bags at BIEVR-LIO's level (0.14, 2.09 and 0.34 m). The other devices on the UGV gain too: tunnel2 β 0.58 → 0.35 m, tunnel3 α 0.72 → 0.18 m, tunnel2 α 2.46 → 2.43 m, tunnel3 β unchanged.
On the road the limit is needed. Without it every α Hard sequence is worse:
| α sequence | v18 | no tilt limit |
|---|---|---|
| Urban_Tunnel01 | 23.7 | 266.6 |
| Urban_Tunnel02 | 38.4 | 98.6 |
| Urban_Tunnel03 | 59.3 | 94.5 |
| bridge01 | 22.7 | 105.9 |
| bridge02 | 109.1 | 220.5 |
| bridge03 | 1074.9 | 1096.9 |
A speed gate fails.
- The candidate. It applies the limit only at 3 m/s or more (rko_lio tag archive/exp/tilt-limit-speed-gate, not merged). The 3 m/s lies between the UGV (under 1 m/s) and the road (9–31 m/s). It was fixed before the runs with v18's rule, over the six α sequences and the seven UGV bags.
- What happens. On the UGV it equals running without the limit. On the road:
- Urban_Tunnel01–03 and bridge02 move by under 1.6 m.
- bridge01 goes from 22.7 to 107.2 m. The car stands or crawls for 1721 of its 3820 scans and still needs the limit there.
- bridge03's estimated speed stays near zero from its moving start, so it loses the limit throughout (1074.9 → 1096.9 m).
- Verdict. It fails the rule and is not adopted. No other threshold was run.
- What it shows. The VLP-16 needs the limit where it cannot hold the pitch, and that depends on the scene, not on the speed.
Two more criteria fail. - Weak tilt information. For every scan we took the registration's information on the two horizontal rotation axes, with translation marginalized (the Schur complement of the ICP system). The road registrations see the tilt better than the UGV's, not worse:
| road α (6 sequences) | UGV (7 bags) | |
|---|---|---|
| weakest tilt direction / rotation information | 0.04–0.19 | 0.010–0.018 |
| weakest tilt direction / translation information | 3–48 m² | 1.1–1.4 m² |
(per-run medians)
The limit on the road guards against a bias in the registration, not against weak information. A gate on weak information would limit the UGV and free the road.
- The gyro bias.
- RKO-LIO takes the gyro bias from one scan interval, 10–20 IMU samples. Against the mean over the first second, that estimate is off on the tilt axes by 0.06–0.2°/s on the UGV bags and by 0.26–0.47°/s on Urban_Tunnel01 and bridge01.
- A 1 s initialization window (rko_lio tag archive/exp/initialization-window) was fixed before its runs, under the same rule as the speed gate. It helps γ and β on the UGV: tunnel3 γ 2.94 → 0.38 m, tunnel2 β 0.58 → 0.35 m. It also helps bridge01 and bridge02.
- But it loses tunnel3 α (0.72 → 4.62 m) and Urban_Tunnel01–03 (23.7 → 124.2, 38.4 → 53.2 and 59.3 → 70.2 m), so it is not adopted.
On the handheld shield tunnels: the registration's speed¶
RKO-LIO v18's γ error there is along the tunnel. The vertical errors are alike. Per leg (between turnarounds), the distance from end to end against the ground truth:
| γ shield tunnel | v18 along (m) | v18 legs | BIEVR-LIO along (m) | BIEVR-LIO legs |
|---|---|---|---|---|
| Shield_tunnel1 | 1.10 | −0.1, +0.8 % | 0.20 | +0.1, +0.1 % |
| Shield_tunnel2 | 2.74 | +1.0, +1.9, +1.9 % | 0.48 | +0.2, −0.2, +0.1 % |
| Shield_tunnel3 | 0.97 | +0.3, +0.5 % | 1.16 | −0.1, −0.2 % |
| Shield_tunnel4 | 2.88 | −3.8, −0.9 % | 2.49 | +0.2, +0.3 % |
| Shield_tunnel5 | 2.62 | −1.3, −3.1 % | 3.17 | −1.3, −4.3 % |
| Shield_tunnel6 | 0.55 | −0.1, −0.3 % | 0.40 | −0.0, −0.2 % |
- Corrected 2026-10-15. An earlier version compared path lengths (v18 0.1–2.1 % too long). Those include the trajectory's jitter.
- Mostly not the stops. The legs themselves come out up to 3.8 % long or short, so the error grows while walking. On Shield_tunnel3 and 6 the stops and the 2 s around them add more than the walking does (the overshoot of Next, item 2).
- Not the step. v18 learns the step from the walk's first 100 plausible scans and then freezes it. On the ten shield tunnels it is off by 0–8.5 %, 3.8 % on average.
- A refinement from scans that see the travel was fixed before its runs with v18's rule (weakest share ≥ 0.05; rko_lio tag
archive/exp/gait-step-refinement). It brings the step within 2.1 % on average. - The trajectories barely change: Shield_tunnel1 and 2 keep 1.13 and 2.76 m, and the mean over the 14 handheld sequences goes from 1.94 to 1.95 m. Not adopted.
- The registration's own speed. Within the correction limit (2 cm per scan, 0.2 m/s at 10 Hz) the registration still sets the speed, and its speed carries the error: on Shield_tunnel2 it runs 2 % fast throughout. BIEVR-LIO holds the speed with its inertial window instead.
GEODE's stairs γ, against the map¶
Stairs_Gamma has no ground-truth trajectory. GEODE publishes a laser-scanned map of the stairs (stairs.las, 601 M points).
- Pseudo ground truth. Every scan is registered to the map, cropped and thinned to 5 cm. The prediction comes from the gyro and the track's own velocity; no LiDAR odometry is used, so the pseudo ground truth does not depend on the methods it scores.
- Checked on α. It keeps 3438 of 3455 scans. Against the dataset's ground truth it agrees to 4.3 cm RMS once a constant offset is removed: the ground truth's point sits 0.27 m from the IMU, turned 2.9°.
- On γ. It tracks the first 122 s: 50 s standing, then the walk to the stairs and onto them. There RKO-LIO v18 has 0.17 m and BIEVR-LIO 0.14 m.
- The stairwell. From about 125 s the tracker loses the map, and so do both methods.
- The share of each scan within 0.2 m of the map falls from over 0.9 to under 0.15 by 130 s.
- The Livox's narrow view sees surfaces the map does not hold, and 27–77 % of a scan's points come back without a return.
- The two methods end 103 m apart.
- Result. Stairs_Gamma past 122 s cannot be scored.
Per-sensor configurations and the sealed half, fixed before any run (2026-10-15)¶
The scope changes. - Why. Every experiment since the holdout splits by sensor: - The 16-beam VLP-16 needs the tilt limit on the road, and the denser LiDARs lose with it on the UGV. - The window helps the Livox shield tunnels and hurts β and the flats.
No criterion tried above lets one configuration serve both.
- Decision (2026-10-15). A configuration may now depend on the sensor and on the platform (carried by hand or mounted on a vehicle), as it already depends on the extrinsics. Everything else stays one setting, fixed before the run below.
- The profile. degenerate_lio_sota_v4.yaml still requires one parameter set across all sequences. A profile with the new scope is not written yet. Its win policy (zero catastrophic failures, ENWIDE included) is not met either, so no SOTA claim follows from this run.
- The sealed half is released for this test. This is the entry the holdout section asks for. After the run, no hidden tunnel data remains.
The configurations.
- α on a vehicle. rko_lio_alpha_v18.yaml, unchanged. The 16-beam LiDAR keeps the tilt limit.
- β and γ on a vehicle (v19). rko_lio_{beta,gamma}_ugv_v19.yaml is v18 UGV without the tilt limit. On tunnel1–3, now development data, they give γ 0.14, 2.09 and 0.34 m, and β 0.35 and 0.36 m.
- Code. rko_lio 80f3c1c, as for tunnel1–3.
The test on tunnel4–5.
- Data. The α, β and γ bags of tunnel4 and tunnel5, 6 in all, with ground truth Tunneling_tunnel4.txt and Tunneling_tunnel5.txt. Three of the bags are still downloading.
- As for tunnel1–3:
- Rivals: COIN-LIO (β only), BIEVR-LIO, FAST-LIO2 and Point-LIO, with configs/geode/rivals/.
- One run per method and bag; SE(3) ATE and 10 m RTE.
- A failure is a 10 m RTE of 20 % or more.
- A run that stops producing poses before the ground truth ends is incomplete, and counts as the worst value in the medians.
- The tabulation implements exactly these definitions.
- Faults. A harness fault may be fixed and the run repeated, and both outcomes are reported. Nothing in the method or the configurations changes after the first run.
- H1. RKO-LIO's median ATE over the six bags is lower than BIEVR-LIO's, FAST-LIO2's and Point-LIO's. On the two β bags it is also lower than COIN-LIO's.
- H2. RKO-LIO has no failure.
- A check outside H1 and H2. β and γ also run their v18 UGV configurations, with the limit. This shows whether the limit's cost on tunnel1–3 holds on fresh bags.
The sealed half: results (2026-10-15)¶
Every method ran once on the six bags of tunnel4–5, with the configurations and rules of the
section above. RKO-LIO ran rko_lio_alpha_v18.yaml on α and rko_lio_{beta,gamma}_ugv_v19.yaml
on β and γ, at rko_lio 80f3c1c. ATE in metres (10 m RTE):
| bag | RKO-LIO | BIEVR-LIO | FAST-LIO2 | Point-LIO | COIN-LIO |
|---|---|---|---|---|---|
| tunnel4 α | 1.07 (3.1 %) | 0.19 (1.5 %) | 4.24 (10.9 %) | 33.11 (98.3 %) | – |
| tunnel4 β | 0.38 (2.0 %) | 0.38 (2.1 %) | 0.38 (2.1 %) | 0.38 (2.1 %) | 1.62 (4.5 %) |
| tunnel4 γ | 0.35 (1.9 %) | 0.35 (1.9 %) | 0.35 (2.0 %) | 0.35 (1.9 %) | – |
| tunnel5 α | 2.90 (6.4 %) | 0.17 (1.3 %) | 24.26 (91.3 %) | 25.10 (94.3 %) | – |
| tunnel5 β | 0.35 (2.2 %) | 0.35 (2.1 %) | 0.35 (2.1 %) | 0.35 (2.1 %) | 7.27 (22.6 %) |
| tunnel5 γ | 0.33 (2.0 %) | 0.33 (2.0 %) | 0.36 (2.4 %) | 0.44 (2.3 %) | – |
| median | 0.36 | 0.34 | 0.37 | 0.41 | 4.44 (β only) |
| median, α | 1.98 | 0.18 | 14.25 | 29.11 | – |
| median, β | 0.36 | 0.36 | 0.36 | 0.37 | 4.44 |
| median, γ | 0.34 | 0.34 | 0.35 | 0.39 | – |
| failures | 0 of 6 | 0 of 6 | 1 of 6 | 2 of 6 | 1 of 2 |
- H1 fails. BIEVR-LIO's median ATE is lower than RKO-LIO's (0.336 against 0.362 m). RKO-LIO's is lower than FAST-LIO2's (0.368 m) and Point-LIO's (0.408 m), and on the β bags than COIN-LIO's (0.36 against 4.44 m).
- H2 holds. RKO-LIO has no failure; its largest 10 m RTE is 6.4 %, on tunnel5 α. BIEVR-LIO has none either.
- No run is incomplete. Every run produced poses until 13–33 s after the ground truth ends. The matched fractions under one come from the bags: tunnel4 α, tunnel5 α and tunnel5 β start 2.6, 7.3 and 20.3 s after their ground truth.
- β and γ. On these four bags RKO-LIO and BIEVR-LIO differ by at most 3 mm, and FAST-LIO2 and Point-LIO stay within 0.11 m of them. Every method but COIN-LIO lands at 0.33–0.44 m.
- α. BIEVR-LIO is 6 and 17 times more accurate (0.19 and 0.17 against 1.07 and 2.90 m); FAST-LIO2 fails tunnel5 α and Point-LIO both α bags. The six-bag medians differ through these two bags: over β and over γ, RKO-LIO's and BIEVR-LIO's medians agree to 2 mm.
- α kept the tilt limit, as fixed. On tunnel3 α, now development data, the same configuration without the limit gave 0.18 instead of 0.72 m (see "On the UGV: the tilt limit"), but every road α sequence needs it.
- tunnel4–5 α were not run without the limit.
The check: the tilt limit on fresh bags. β and γ also ran their v18 UGV configurations, which keep the limit:
| bag | v18 UGV (with the limit) | v19 |
|---|---|---|
| tunnel4 β | 1.36 (4.4 %) | 0.38 (2.0 %) |
| tunnel4 γ | 1.28 (3.9 %) | 0.35 (1.9 %) |
| tunnel5 β | 13.48 (24.1 %) | 0.35 (2.2 %) |
| tunnel5 γ | 0.34 (2.1 %) | 0.33 (2.0 %) |
As on tunnel1–3, the limit costs on most bags: 0.9–13.1 m on three of the four, with tunnel5 β a failure. tunnel5 γ is unchanged.
What follows. - On the UGV. With the per-sensor configurations, β and γ reach the best rival's accuracy; α does not. The α configuration has to serve the road and the UGV, and only the road needs the limit. - No hidden tunnel data remains. Any later change to these configurations is measured on development data only. - No SOTA claim follows, as fixed before the run.
Reproduction¶
python3 scripts/prepare_geode_ground_truth.py GEODE/groundtruth/traj GEODE/gt_tum
python3 scripts/convert_geode_bag.py SEQ/SEQ.bag SEQ/ros2 [--ros1-out SEQ/SEQ_lidar_imu.bag]
python3 -c "import sys, yaml; print(yaml.safe_dump({'/**': {'ros__parameters': yaml.safe_load(open(sys.argv[1]))}}))" \
configs/geode/rko_lio_DEVICE_v18.yaml > rko_lio_DEVICE_v18.ros.yaml
ros2 run rko_lio offline_node --ros-args --params-file rko_lio_DEVICE_v18.ros.yaml \
-p bag_path:=SEQ/ros2 -p imu_topic:=IMU_TOPIC -p lidar_topic:=LIDAR_TOPIC -p base_frame:=base_link ...
python3 scripts/score_position_only_trajectory.py --reference GEODE/gt_tum/SEQ.txt \
--estimate TRAJECTORY.tum --output score.json --max-time-gap 0.11
The files in configs/geode/ are flat parameter maps, so a ROS parameter file wraps them
first. IMU_TOPIC is /imu/data on α and β and /livox/imu on γ. On the Metro Tunneling
holdout β and γ use rko_lio_DEVICE_ugv_v18.yaml, and on tunnel4–5 rko_lio_DEVICE_ugv_v19.yaml.
The ROS 1 rivals run in docker/enwide_rivals_ros1.Dockerfile. Each rival's ouster64,
velodyne/velody16 or avia configuration is replaced by the matching file in
configs/geode/rivals/.
Next¶
- The inertial window.
- What works. W1 with the γ IMU rotation matches BIEVR-LIO on the γ shield tunnels.
- What failed. Seven ways to make it robust failed (above), soft positions included. flat_surfaces_aggressive diverges with all but one of them.
- What is left. A registration that is lost for seconds needs a recovery the window cannot give.
- The gait as that recovery. Taking the gait's speed whenever the window disagrees with it by more than 30 % fails too (the eighth way).
- The walker's stops.
- v17. It removes the gait prior's losses on Shield_tunnel4 and 6 (24.4 → 4.21 m and 12.6 → 0.55 m). It still overshoots each stop by 2–4 m, because the cadence lags by half its 4 s window.
- Shield_tunnel2. At 10.3 m it is the γ shield tunnel left above 5 m; W1 tracks it at 0.42 m.
- Tried and failed. Carrying the gait speed over the lag with the IMU fails, and so does following the step events (above). The step events do find the stops 1.5–2 s earlier. Stop and restart is the best on the median, but fails the rule on two sequences.
- Validation. The stairs are in v18's rule, but v18 was developed on them, so they no longer show how a gait change does on unseen data. A further gait change keeps the v18 rule fixed before its runs.
- Not the step (see "On the handheld shield tunnels"). The γ along-track error grows mostly while walking, from the registration's own speed; on Shield_tunnel3 and 6 the stops add more.
- One configuration and the holdout. ENWIDE and GEODE need one configuration. The Metro Tunneling sequences are the hidden tunnel holdout: a UGV, all three devices.
- Fixed before any run (see "The Metro Tunneling holdout"). tunnel1–3 test this note's configurations, with vehicle configurations for β and γ. tunnel4–5 stay sealed for one configuration.
- tunnel1–3 ran. No failure, but BIEVR-LIO and FAST-LIO2 are more accurate. The gap is on γ, as on the shield tunnels (item 1).
- The UGV's γ gap is the tilt limit (see "After the holdout"). One configuration needs a criterion for it that tells a VLP-16 losing the pitch from a scan that holds it. Speed, weak tilt information and a longer gyro initialization all fail.
- The scope changed instead (2026-10-15). Configurations may depend on the sensor and the platform. tunnel4–5 test them (see "Per-sensor configurations and the sealed half").
- tunnel4–5 ran (see "The sealed half: results"). No failure; β and γ at BIEVR-LIO's level, α not. No hidden tunnel data remains.
- What is left is α on a vehicle: the road needs the tilt limit, and the UGV loses with it.
- bridge03's moving start. The registration starts from zero speed on a bridge that gives no hold along the road. Every LiDAR-inertial rival also fails there (697–1100 m).