Hilti 2022

Hilti SLAM Challenge 2022 / Hilti-Oxford (a hand-held survey pole walked through construction sites and Oxford’s Sheldonian Theatre).

Named for the year on purpose: the Hilti challenge datasets are NOT one family with one sensor suite. 2021 is a different rig entirely (Ouster OS0-64 + Livox MID70, IMUs on /imu, /imu_adis and /os_imu). 2023 ships two platforms: its hand-held one reuses these topic and frame names but runs the IMU at 200 Hz rather than ~400 Hz and carries its own calibration, while its robot platform is a RoboSense BPearl + Xsens MTi-670. The 2026 Hilti-Trimble challenge has no LiDAR in its bags at all. Anything other than 2022 wants its own profile, not a re-use of this one.

One monolithic ROS 1 bag per sequence: a Hesai PandarXT-32 lidar, a Sevensense Alphasense IMU, and five cameras. There is no /tf or /tf_static in the bags at all, so every sensor pose has to be fixed here.

base_link is the IMU, and that is not an arbitrary choice: the dataset’s own calibration/calibration_files/lidar_calibration.yaml declares the IMU as base_link at identity, and every ground-truth file is expressed in the IMU frame. Reporting in the IMU frame therefore lands the estimate in the reference’s own frame, with no offset to compose afterwards. The lidar sits at T_imu_pandar below, taken from that same file (translation [-0.001, -0.00855, 0.055], quaternion x,y,z,w [0.7071068, -0.7071068, 0, 0], i.e. a 5.6 cm lever arm).

Ground truth is worth reading before picking a sequence: only exp14_basement_2, exp16_attic_to_upper_gallery_2 and exp18_corridor_lower_gallery_2 ship a dense 6-DoF trajectory (~10 Hz). The other thirteen sequences ship surveyed control points – a handful of positions with a placeholder identity quaternion, not poses.

Running it

Online replay with the 3D GUI:

mola-lo-gui-hilti2022 /path/to/expNN_name.bag [additional flags]

Offline batch run, writing a trajectory file:

mola-lo-cli-hilti2022 /path/to/expNN_name.bag [additional flags]

What this profile sets, and why

These are defaults, not overrides: exporting any of these variables before running the wrapper takes precedence.

MOLA_LIDAR_TOPIC

Default: /hesai/pandar

MOLA_IMU_TOPIC

Default: /alphasense/imu

MOLA_CAMERA_TOPIC

Default: /alphasense/cam0/image_raw

MOLA_USE_FIXED_CAMERA_POSE

Default: 1

MOLA_USE_FIXED_IMU_POSE

Default: 1

MOLA_USE_FIXED_LIDAR_POSE

Default: 1

HILTI2022_BASE_FRAME

Default: imu

LIDAR_POSE_X

Default: -0.001

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

LIDAR_POSE_Y

Default: -0.00855

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

LIDAR_POSE_Z

Default: 0.055

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

LIDAR_POSE_YAW

Default: -90

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

LIDAR_POSE_PITCH

Default: 0

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

LIDAR_POSE_ROLL

Default: 180

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

IMU_POSE_X

Default: 0}" ; : "${IMU_POSE_Y:=0}" ; : "${IMU_POSE_Z:=0

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

IMU_POSE_YAW

Default: 0}" ; : "${IMU_POSE_PITCH:=0}" ; : "${IMU_POSE_ROLL:=0

T_imu_pandar, from the dataset’s lidar_calibration.yaml.

MOLA_TF_BASE_LINK

Default: lidar

T_pandar_imu, the inverse of the above.

LIDAR_POSE_X

Default: 0}" ; : "${LIDAR_POSE_Y:=0}" ; : "${LIDAR_POSE_Z:=0

T_pandar_imu, the inverse of the above.

LIDAR_POSE_YAW

Default: 0}" ; : "${LIDAR_POSE_PITCH:=0}" ; : "${LIDAR_POSE_ROLL:=0

T_pandar_imu, the inverse of the above.

IMU_POSE_X

Default: -0.00855

T_pandar_imu, the inverse of the above.

IMU_POSE_Y

Default: -0.001

T_pandar_imu, the inverse of the above.

IMU_POSE_Z

Default: 0.055

T_pandar_imu, the inverse of the above.

IMU_POSE_YAW

Default: -90

This rotation is its own inverse (R^T == R), hence the same angles as the imu branch above; only the translation changes.

IMU_POSE_PITCH

Default: 0

This rotation is its own inverse (R^T == R), hence the same angles as the imu branch above; only the translation changes.

IMU_POSE_ROLL

Default: 180

This rotation is its own inverse (R^T == R), hence the same angles as the imu branch above; only the translation changes.

MOLA_LO_INITIAL_LOCALIZATION_METHOD

Default: InitLocalization::PitchAndRollFromIMU

Hand-held rig, like conslam: larger and faster rotations than a vehicle, so lean on the IMU both for deskewing and for the initial pitch/roll. The clouds do carry genuine per-point timestamps (an f64 ‘timestamp’ field plus ‘ring’), so deskewing has real data to work with here.

MOLA_DESKEW_METHOD

Default: MotionCompensationMethod::IMU

Hand-held rig, like conslam: larger and faster rotations than a vehicle, so lean on the IMU both for deskewing and for the initial pitch/roll. The clouds do carry genuine per-point timestamps (an f64 ‘timestamp’ field plus ‘ring’), so deskewing has real data to work with here.

Under the hood

Online launch file

lidar_odometry_from_rosbag1.yaml

Offline CLI input

--input-rosbag1 <MOLA_LO_BAGS_JOINED>

Profile source

scripts/lib/profiles/hilti2022.sh