Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

slam_eval

Tools for offline evaluation of a SLAM system (GLIM) against Qualisys motion-capture ground truth, on ROS2 bags (.db3 / .mcap). It contains two independent pipelines meant to be used in sequence:

  1. slam_eval_pipeline.py — trajectory accuracy (ATE/RPE) via evo.
  2. fido_eval.py — evaluation of the FIDO dynamic object rejection module: checks whether lidar points belonging to the moving person are correctly classified as "dynamic" by the SLAM.

Dependencies

pip install rosbags evo

Versions used in this project: rosbags==0.11.2, evo==1.36.4, Python 3.12.

Both scripts read mocap_msgs/RigidBodies / mocap4r2_msgs/RigidBody messages (defined in msg/), registering them at runtime in the rosbags typestore, so the ROS2 mocap packages don't need to be installed — only the bags are needed.

Project structure

Path Content
slam_eval_pipeline.py ATE/RPE pipeline for SLAM trajectory vs Qualisys
fido_eval.py FIDO evaluation (TP/FP/FN/TN on dynamic/static points)
launcher_slam Example command for slam_eval_pipeline.py
launcher_fido (empty — to be filled with an example command for fido_eval.py)
msg/ Reference .msg definitions for the mocap4r2 types
bags/, filter_bags/ Input ROS2 bags (raw/filtered data, not versioned)
results/, results_new/ Output of slam_eval_pipeline.py (one per bag/run, not versioned)
fido_results/ Output of fido_eval.py: CSV, logs, RViz marker bags (not versioned)

Data folders (bags/, filter_bags/, results*/, fido_results/) are in .gitignore because they contain large files generated locally.

1. slam_eval_pipeline.py — Trajectory evaluation (ATE/RPE)

Extracts the SLAM and Qualisys trajectories in TUM format, aligns them (Umeyama), and computes:

  • ATE (Absolute Trajectory Error) via evo_ape
  • RPE (Relative Pose Error) via evo_rpe

The Umeyama alignment computed by evo_ape (saved in ape_result.zip) is a prerequisite for fido_eval.py.

Usage

python3 slam_eval_pipeline.py \
    --slam_bag ./filter_bags/1912_none/1912_none_0.mcap \
    --slam_topic /glim_ros/odom_corrected \
    --gt_bag /path/to/qualisys_bag/qualisys_0.db3 \
    --gt_topic /rigid_bodies \
    --rigid_body_name JO \
    --slam_ros_version jazzy \
    --gt_ros_version humble \
    --t_max_diff 0.05 \
    --output_dir ./results

Main parameters

Flag Description Default
--slam_bag Bag containing the SLAM odometry (.mcap/.db3) required
--slam_topic SLAM odometry topic (e.g. /glim_ros/odom_corrected) required
--gt_bag Qualisys bag with the rigid bodies required
--gt_topic RigidBodies topic required
--rigid_body_name Name of the rigid body to use as ground truth (e.g. the robot) None
--slam_ros_version / --gt_ros_version ROS2 version of the respective bags (humble, iron, jazzy, foxy) humble / jazzy
--t_offset Time offset (s) to add to the SLAM timestamps, if the two bags aren't synchronized 0.0
--t_max_diff Maximum time difference (s) to match SLAM/GT poses to the same instant 0.01
--t_start / --t_end Seconds to trim from the start/end of the overlapping trajectory 0.0
--skip_rpe Skip the RPE computation (ATE only) False
--output_dir Output directory ./results

If --t_offset is 0.0 and the initial timestamps of SLAM and GT differ by more than 0.5s, the script prints a warning with the suggested offset.

Output

For each run, a subfolder <output_dir>/<slam_bag_name>[_t<N>s][_e<N>s]/ is created with:

  • gt.txt, slam.txt — trajectories in TUM format
  • ape_result.zip, ape_plot_map.png — ATE results (also contains alignment_transformation_sim3.npy, used by fido_eval.py)
  • rpe_result.zip, rpe_plot_map.png — RPE results (unless --skip_rpe)

2. fido_eval.py — Dynamic object rejection evaluation (FIDO)

For each synchronized lidar frame:

  1. Reads the person's head position from Qualisys.
  2. Transforms it into the lidar frame using the GLIM odometry and the Umeyama alignment computed in step 1 (or, if --robot_body_name is given, using the robot's per-frame pose instead of the static alignment — more robust to drift).
  3. Builds a vertical cylinder (head → feet) around the person in the lidar frame.
  4. Classifies the points from the "dynamic" and "static" topics against the cylinder → TP/FP/FN/TN.
  5. Computes precision, recall, F1 per frame and aggregated over the whole sequence.

Requires the output of slam_eval_pipeline.py (ape_result.zip) as input, from which it reads the Umeyama alignment matrix.

Usage

python3 fido_eval.py \
    --slam_bag ./filter_bags/1912_none/1912_none_0.mcap \
    --gt_bag /path/to/qualisys_bag/qualisys_0.db3 \
    --output_bag ./filter_bags/1912_none/1912_none_0.mcap \
    --evo_result ./results/1912_none_0/ape_result.zip \
    --rigid_body_name JO \
    --slam_ros_version jazzy \
    --gt_ros_version humble \
    --output_ros_version jazzy \
    --person_height 1.75 \
    --cylinder_radius 0.4 \
    --output_csv ./fido_results/fido_eval_1912.csv

--output_bag can be the same as --slam_bag if the dynamic/static topics, the odometry, and the ground truth are all in the same bag.

Main parameters

Flag Description Default
--slam_bag Bag containing /glim_ros/odom_corrected (SLAM odometry) required
--gt_bag Qualisys bag with the rigid bodies required
--output_bag GLIM bag with the dynamic/static pointclouds (can = --slam_bag) required
--evo_result ape_result.zip generated by slam_eval_pipeline.py, contains the Umeyama matrix required
--rigid_body_name Qualisys rigid body name of the person JO
--robot_body_name Qualisys rigid body name of the robot; if given, uses per-frame transformation instead of the static Umeyama None
--slam_topic / --gt_topic Odometry / ground-truth topics /glim_ros/odom_corrected / /rigid_bodies
--dynamic_topic / --static_topic Pointcloud topics classified as dynamic/static /glim_ros/velodyne_points_dynamic / /glim_ros/velodyne_points_static
--slam_ros_version / --gt_ros_version / --output_ros_version ROS2 versions of the respective bags jazzy / humble / jazzy
--person_height Approximate person height (m), defines the cylinder from feet to head 1.75
--cylinder_radius Cylinder radius (m) 0.4
--t_max_diff Maximum time difference (s) to synchronize odom/GT/pointcloud 0.05
--t_offset_gt Offset (s) to add to the Qualisys timestamps, if the cylinder appears lagging/leading the points 0.0
--T_lidar_imu Lidar↔IMU extrinsic as 16 floats (row-major 4×4 matrix); omit if the odometry is already in the lidar frame None (identity)
--output_csv Output CSV path ./fido_eval.csv
--rviz_bag If given, generates an .mcap bag with the cylinder marker + pointclouds for visual inspection in RViz2 None
--marker_frame frame_id of the RViz marker (map = GLIM world, or velodyne/lidar/base_link) map
--marker_topic Topic on which to publish the marker in the rviz_bag /fido_eval/cylinder

Output

  • CSV (--output_csv) with one row per frame: t, TP, FP, FN, TN, precision, recall, f1, n_dyn, n_sta, head_x/y/z_lidar.
  • Aggregated summary printed to screen (total TP/FP/FN/TN, global precision/recall/F1, and per-frame mean±σ).
  • (optional) --rviz_bag: .mcap bag with the cylinder marker and the dynamic/static pointclouds remapped to /fido_eval/points_dynamic and /fido_eval/points_static, useful for visually validating the alignment in RViz2.

Typical workflow

  1. Record a SLAM (GLIM) bag and a Qualisys bag for the same experiment (see [[project_experiment_setup]] for the setup: one person walking around the room for the whole duration of the bag).
  2. Run slam_eval_pipeline.py to get ATE/RPE and the Umeyama alignment matrix (ape_result.zip).
  3. Run fido_eval.py, passing the ape_result.zip from step 2, to evaluate the dynamic/static classification on the person.
  4. (Optional) Generate the --rviz_bag and inspect it in RViz2 to visually verify that the cylinder correctly follows the person.

Notes

  • ROS2 topics used in this project: Qualisys → /rigid_bodies (RigidBodies), SLAM → /glim_ros/odom_corrected (Odometry).
  • If the SLAM and Qualisys bags come from different ROS2 versions (e.g. Jazzy vs Humble), set --slam_ros_version/--gt_ros_version (and --output_ros_version for fido_eval.py) correctly: CDR typestores differ between versions.
  • If the script reports many frames skipped due to failed synchronization (skipped_odom/skipped_gt), increase --t_max_diff or check that the bags were recorded in the same time window (see the time-offset warning).

About

Python toolkit for offline evaluation of a SLAM system (GLIM) against Qualisys mocap ground truth on ROS2 bags: trajectory accuracy (ATE/RPE via evo) and dynamic object rejection (FIDO, TP/FP/FN/TN).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages