Releases: Tim-HW/glass-lio
Release list
V1.1 - Tight coupling on by default
V1.1 — Tight coupling on by default
The 18-DoF tightly-coupled path went from documented-but-disabled to the default,
and glasslio got measured against real ground truth and two established systems for the
first time.
Tight coupling works
imu_prior_weight: 1.0 is now the default in config/livox_mid_360.yaml. The IMU is a
residual in the same normal equations as the LiDAR — where the geometry is degenerate,
the LiDAR term has a null space and the IMU is the only thing there, so it takes over
exactly where it is needed, with no mode switch.
Getting there took two one-line fixes and zero new architecture, against a documented
diagnosis ("it needs a whole sliding window") that turned out to be wrong:
- Gravity was the runaway. Promoted to a state but anchored to its own moving
estimate, it had no restoring force — it wandered to|g| ≈ 25in 200 scans and threw
the pose ~500 km. Anchoring the prior to the fixed init value and stiffening it
(gravity_sigma0.5 → 0.05) dropped divergence ~400x. lidar_sigmawas miscalibrated. At 0.05 the solver under-trusted the LiDAR and let
the IMU over-integrate velocity on bland stretches (|v| ramping to ~40 m/s). At 0.02 —
the Livox's real point-to-plane noise — the remaining drift collapsed and tight reached
parity with loose.
Full accounting, including why the structural diagnosis was itself the trap:
doc/7-tight-coupling.md.
Two new degeneracy gates
- Translation degeneracy (
min_translation_eigenvalue_ratio, default 0.05) — a scan
whose plane normals cluster into one or two directions leaves a translation axis with
near-zero constraint. RMSE and correspondence count both look healthy while the solve
slides freely along it. The gate checks the smallest-eigenvalue/trace ratio ofH's
translation block instead. Calibrated empirically: the indoor bag's floor is 0.117, the
failure window's ceiling 0.034 — no overlap.
(§3.6.1) - Deskew gyro-bias resync (
min_rotation_eigenvalue_ratio, default 0.05) — deskew was
running on the bias measured once at init, forever, while the tight solve refined one
every scan. It now resyncs, but only on scans where the LiDAR itself constrains
rotation — an ungated resync through a long corridor compounds, since each scan's
slightly-off bias distorts the geometry the next one is built from.
(§7.8d)
First benchmark against real ground truth
glasslio vs FAST-LIO2 vs KISS-ICP on M3DGR,
RTK/ArUco ground truth, all three on ROS 2 Jazzy with real-time playback. Full
methodology: doc/benchmark.md.
Outdoor01 (345.85 m true path) — FAST-LIO2 is the most accurate of the three;
glasslio and KISS-ICP hold good local consistency but accumulate more global drift:
| System | APE rmse | RPE rmse | Path length | Ratio vs GT |
|---|---|---|---|---|
| glasslio | 6.00 m | 0.394 m | 362.2 m | 1.05x |
| FAST-LIO2 | 0.216 m | 0.247 m | 347.3 m | 1.004x |
| KISS-ICP | 3.147 m | 0.392 m | 388.7 m | 1.12x |
Corridor02 (M3DGR's designated LiDAR-degeneracy sequence) — the ordering flips:
| System | Tracking health | Translation error |
|---|---|---|
| glasslio | Tracked the full 293 s, zero rejected scans | 9.66 m |
| FAST-LIO2 | Ran the full 293 s but diverged | 14,810.8 m |
| KISS-ICP | Tracked the full 293 s | 5.31 m |
Single run per system per sequence, with run-to-run variance under CPU load — treat these
as ±30-50%, not exact.
⚠️ Upgrade note: glass_core is now a submodule
The estimation engine (SE(3) Gauss-Newton, preintegration, marginalization, SO(3)
Jacobians) moved to its own repo, Tim-HW/glass-core,
shared with glass-vio. Clone with --recurse-submodules, or run
git submodule update --init in an existing checkout — an uninitialized submodule shows
up as an empty glass_core/ and CMake will stop with a message pointing at this step.
git clone --recurse-submodules https://github.com/Tim-HW/glass-lio.gitAlso
- New doc:
benchmark.md(11 write-ups now) - Status table updated — tight coupling is ✅, not
⚠️
Full changelog: V1.0...V1.1