#### NOTE
This is a **Hugging Face dataset**. For large datasets, ensure `huggingface_hub>=1.1.3` to avoid rate limits. Learn more in the <a href="https://docs.voxel51.com/integrations/huggingface.html#loading-datasets-from-the-hub" target="_blank">Hugging Face integration docs</a>.

<a href="https://huggingface.co/datasets/Voxel51/RTK-SLAM-Absolute-Accuracy" target="_blank">![Hugging Face](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Dataset-yellow)</a>

# RTK-SLAM Absolute Accuracy → FiftyOne (Native Multimodal MCAP)

![preview](https://huggingface.co/datasets/Voxel51/RTK-SLAM-Absolute-Accuracy/resolve/main/preview.gif)

The
[RTK-SLAM dataset](https://rtk-slam-dataset.github.io/)
from the Institute for Photogrammetry and Geoinformatics, University of
Stuttgart, published as
[Willyzw/rtk-slam-dataset](https://huggingface.co/datasets/Willyzw/rtk-slam-dataset),
converted to native multimodal MCAP episodes.

A handheld rig carrying a Livox MID360, a global shutter camera and a GNSS
receiver is walked through a public park and a construction hall. Both block
the sky in places, including a 30 m underpass and an indoor hall spanning
more than 400 seconds of the route.

The reference is not the GNSS. A geodetic total station surveyed checkpoints
along each route independently, so absolute error can be measured without
first fitting the estimate onto the reference. The authors’ point is that the
usual SE(3)-aligned error absorbs global drift and can understate the real
figure by up to 76%.

## Installation

```bash
pip install fiftyone
```

## Usage

```python
import fiftyone as fo
import fiftyone.utils.huggingface as fouh

dataset = fouh.load_from_hub(
    "Voxel51/RTK-SLAM-Absolute-Accuracy",
    name="RTK-SLAM-Absolute-Accuracy",
    persistent=True,
)
fo.launch_app(dataset)
```

Where the sky was hardest to see:

```python
view = dataset.sort_by("gnss_fix_rate")
```

## What you get

Four sequences and 64.6 minutes of walking. Each episode carries:

- `/camera`, the handheld view at 1600x1200 and 20 Hz, as
  `foxglove.CompressedVideo`
- `/camera-calibration`, the pinhole intrinsics and radtan coefficients
- `/lidar`, the Livox MID360 sweep at 10 Hz, as `foxglove.PointCloud`
- `/imu.plot`, accelerometer and gyroscope at 200 Hz
- `/gnss`, the receiver’s fix, as `foxglove.LocationFix`
- `/gnss-quality.plot`, the reported horizontal sigma and whether a fix was
  held at all
- `/checkpoints`, the surveyed points as labelled spheres, coloured by
  whether each was taken outdoors, indoors or in the transition between
- `/pose-fast-lio-sam`, `/pose-okvis-lvig` and `/pose-okvis-vig`, the three
  published trajectories
- `/trajectories`, the same three as line strips
- `/checkpoint-error.plot`, each system’s distance to each checkpoint
- `/tf`, the rig geometry from the calibration
- `/instruction`, the route being walked

Across the whole set that comes to 76,409 camera frames, 38,175 LiDAR sweeps,
**763,673 IMU samples**, 38,202 GNSS fixes and 87 surveyed checkpoints.

Episodes carry the fields `sequence`, `site`, `environments`, `duration`,
`num_checkpoints`, `num_camera_frames`, `num_lidar_sweeps`,
`num_imu_samples`, `num_gnss_fixes`, `gnss_fix_rate`, `best_system`, and
`error_<system>_rmse_m` and `error_<system>_max_m` for each of the three.

| Sequence          | Duration   |   Checkpoints | GNSS fix   | fast_lio_sam   | okvis_lvig   | okvis_vig   |
|-------------------|------------|---------------|------------|----------------|--------------|-------------|
| stadtgarten_seq1  | 26m43s     |            36 | 54%        | **0.16 m**     | 4.11 m       | 3.28 m      |
| stadtgarten_seq2  | 15m35s     |            19 | 40%        | 0.17 m         | 3.19 m       | 2.69 m      |
| construction_seq1 | 12m21s     |            16 | 25%        | 0.26 m         | 0.75 m       | 1.44 m      |
| construction_seq2 | 9m60s      |            16 | 23%        | 0.46 m         | 0.81 m       | 3.72 m      |

Errors are RMSE over that sequence’s checkpoints, with no alignment applied.

## Notes on the conversion

The release publishes the same recordings three times, as ROS1 bags, ROS2
stores and an extended EuRoC layout. The ROS2 store is the one converted.

The surveyed checkpoints are in ETRS89 / UTM 32N with DHHN2016 heights, which
are metres above the geoid, while the recordings and the published
trajectories use ellipsoidal height. Around Stuttgart the two differ by about
48 m, so the checkpoints are transformed through the geoid model before being
placed in the episode’s local east-north-up frame. That frame is anchored on
the origin the trajectory authors used, so the estimates need no adjustment.

The GNSS is carried as recorded. It is an input to the systems under test
rather than a reference, and it is degraded on purpose: on the construction
sequences a fix is held for under a quarter of the run.

Video is re-encoded to Annex-B H.264 without B-frames. The source carries
JPEG frames, which are most of its volume.

The `/livox/lidar` topic duplicates `/livox/points` in a vendor-specific
message type and is not carried.

`stadtgarten_seq2` runs 935 s in the recording against the 14m36s its
source table gives. The other three match their published durations to the
second.

## License & attribution

The source release is distributed under
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), and this
conversion is distributed under the same license.

```bibtex
@article{zhang2025rtkslam,
  title   = {An RTK-SLAM Dataset for Absolute Accuracy Evaluation in
             GNSS-Degraded Environments},
  author  = {Zhang, Wei and Ress, Vincent and Skuddis, David and
             Soergel, Uwe and Haala, Norbert},
  journal = {ISPRS Annals of the Photogrammetry, Remote Sensing and Spatial
             Information Sciences},
  year    = {2025},
}
```

Changes from the source: conversion to the FiftyOne MCAP flavor, re-encoding
of the video to H.264, transformation of the surveyed checkpoints into the
trajectory frame, and encoding of the sensor, pose and error streams as
message streams.
