GrandTour
GrandTour (https://grand-tour.leggedrobotics.com): an ANYbotics ANYmal-D quadruped carrying the open-source “Boxi” sensor payload.
Each mission is published as a set of per-topic ROS 1 bags, so the LiDAR, the IMU, /tf and the front camera live in SEPARATE files. They are replayed jointly through the generic rosbag1 launch file / a comma-joined –input-rosbag1, so no dataset-specific launch file is needed.
Bags used (the rest of each mission's bags are ignored):
<mission>_hesai_undist.bag /boxi/hesai/points_undistorted 10 Hz (required)
<mission>_tf_minimal.bag /tf, /tf_static (optional)
<mission>_tf_model.bag /tf, /tf_static (only for the STIM320, see below)
<mission>_adis.bag /boxi/adis/imu 200 Hz (optional, default IMU)
<mission>_stim320_imu.bag /boxi/stim320/imu 500 Hz (opt-in alternative IMU)
<mission>_hdr_<tag>.bag /boxi/hdr/<tag>/image_raw/... 10 Hz (optional, GUI only)
<mission>_alphasense.bag /boxi/alphasense/<tag>/image_... 10 Hz (optional, GUI only)
<mission>_anymal_state.bag /anymal/state_estimator/odometry (opt-in, see below)
Sensor extrinsics come from the dataset’s own /tf_static (base -> box_base -> hesai_lidar / adis16475_imu / hdr_base -> hdr_front), so no fixed sensor poses are needed as long as the tf bag is present. Without it, the LiDAR falls back to a fixed pose at the origin (the payload extrinsics are then simply unknown).
Scoring against this dataset’s ground truth needs a body-frame correction: every GT source is anchored to a physical sensor mount (cpt7_imu, 0.293 m from base; or the total-station prism, 0.395 m), not to base, which is what the odometry reports. See the dataset’s own COMFORT benchmark rules.
Running it
Online replay with the 3D GUI:
mola-lo-gui-grandtour /path/to/<mission-dir>/ [additional flags]
Offline batch run, writing a trajectory file:
mola-lo-cli-grandtour /path/to/<mission-dir>/ [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_GRANDTOUR_IMU
Default: adis
Which IMU: the ADIS16475 by default, or the higher-grade STIM320.
The two are not interchangeable as far as /tf goes. `tf_minimal.bag` publishes the ADIS’s frame but NOT the STIM320’s, so selecting the STIM320 also selects the full `tf_model.bag`, which carries every sensor frame (verified: it has base, hesai_lidar, prism, adis16475_imu and stim320_imu, and the same /tf and /tf_static message counts).
MOLA_GRANDTOUR_CAMERA
Default: hdr_front
Which camera to preview. The three HDR cameras each ship in their own bag, while the five Alphasense cameras share a single one, so the bag and the topic have to be resolved together rather than derived from the tag alone.
MOLA_LIDAR_TOPIC
Default: /boxi/hesai/points_undistorted
GrandTour topic names and /tf frames:
MOLA_USE_FIXED_LIDAR_POSE
Default: 1
MOLA_IMU_TOPIC
Default: $imu_topic
MOLA_LO_INITIAL_LOCALIZATION_METHOD
Default: InitLocalization::PitchAndRollFromIMU
A legged robot pitches and rolls constantly from the very first scan, so level the initial pose from the IMU instead of assuming a flat start:
MOLA_IMU_TOPIC
Default: empty, so this is off unless you set it.
MOLA_CAMERA_TOPIC
Default: $camera_topic
MOLA_DESKEW_METHOD
Default: MotionCompensationMethod::None
The LiDAR stream used here is the dataset’s already-undistorted one, so deskewing it a second time would over-compensate the motion:
MOLA_MINIMUM_RANGE_FILTER
Default: 1.5
Use a shorter minimum range since the robot body is small in this dataset:
This one is on a cliff edge, so re-tune it only with measurements in hand: dropping to 1.0 m costs little, but raising it to 2.0 m degrades odometry by more than an order of magnitude, and 3.0 m is *better* than 2.0 m. A legged platform depends on the near-field ground returns this filter removes.
MOLA_LOCALMAP_CLASS
Default: mola::IncrementalPointCloud
A single incremental k-d tree in one global frame, rather than the default keyframe-based local map. Measured across every mission of this dataset that has a reference trajectory, it lowers absolute trajectory error on all of them, by ~46% on average, at ~44% more CPU (still comfortably faster than real time). A constantly pitching platform benefits from a stable, denser local map instead of one rebuilt from a small rotating keyframe set.
ODOMETRY ONLY: this map cannot be re-mapped by a global SE(3) correction, so
override it when running loop-closure SLAM on this dataset:
MOLA_LOCALMAP_CLASS=mola::KeyframePointCloudMap
MOLA_LO_SHOW_TF_TREE
Default: true
This is a legged robot with a full joint tree in /tf, which is the whole
point of showing it here, so turn the tf tree view on by default.
The four frames skipped below are the ones that are NOT physically part
of the robot, and would otherwise be drawn as if they were:
odom the world-fixed odometry frame (published
inverted, as a child of 'base')
enu_origin the geodetic reference frame (child of 'cpt7_imu')
dlio_odom, dlio_map the onboard SLAM's own frames (children of
'hesai_lidar')
Everything else in the tree is real hardware on the body: the four legs,
the IMUs, the LiDARs, the cameras, and the total-station 'prism'.
MOLA_LO_TF_TREE_EXCLUDE
Default: odom,enu_origin,dlio_odom,dlio_map
This is a legged robot with a full joint tree in /tf, which is the whole
point of showing it here, so turn the tf tree view on by default.
The four frames skipped below are the ones that are NOT physically part
of the robot, and would otherwise be drawn as if they were:
odom the world-fixed odometry frame (published
inverted, as a child of 'base')
enu_origin the geodetic reference frame (child of 'cpt7_imu')
dlio_odom, dlio_map the onboard SLAM's own frames (children of
'hesai_lidar')
Everything else in the tree is real hardware on the body: the four legs,
the IMUs, the LiDARs, the cameras, and the total-station 'prism'.
Under the hood
Online launch file |
|
Offline CLI input |
|
Profile source |