Ground truth for robots#

This guide gives a robot a ground truth from the mocap system and measures the error of its localization. Read Frames and conventions first: the ground truth lives in a TF tree parallel to the robot’s.

1. Define the rigid body#

Put at least three markers on the robot (asymmetric, not on a line, visible from above) and create a rigid body in the mocap software, for example robot. Check it:

$ ros2 mocap4r2 bodies optitrack_driver

2. Run robot_gt#

robot_gt:
  ros__parameters:
    rigid_body: robot
    robot_frame: base_link        # gt_frame defaults to base_link_gt
    body_to_robot: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]   # calibrated in step 3
$ ros2 launch mocap4r2_robot_gt robot_gt.launch.yaml params_file:=robot_gt.yaml

It publishes TF mocap -> gt_origin -> base_link_gt, ~/pose and ~/odom (nav_msgs/Odometry with velocities in the robot frame, filtered with velocity_alpha). Untracked or missing bodies produce nothing: a ground truth is never extrapolated.

3. Calibrate the body on the robot#

body_calibrator finds body_to_robot: the base of the robot is the centre of the circle the body traces when the robot turns in place, and the direction of a straight drive gives the yaw between the body and the robot.

$ ros2 run mocap4r2_gt_tools body_calibrator --ros-args -p rigid_body:=robot \
    -r rigid_bodies:=/rigid_bodies -p base_height:=0.0
$ ros2 service call /body_calibrator/reset std_srvs/srv/Trigger
# turn the robot in place at least 90 degrees
$ ros2 service call /body_calibrator/turn_done std_srvs/srv/Trigger
# drive straight forward at least 0.3 m
$ ros2 service call /body_calibrator/compute std_srvs/srv/Trigger

It answers (and saves to body_to_robot.yaml) the value for robot_gt. base_height is the height of the robot frame origin over the mocap floor (0 for base_footprint).

4. Align the map with the mocap room#

To compare the localization (map -> base_link) with the ground truth, find map -> mocap while the robot drives around with its localization running:

$ ros2 run mocap4r2_gt_tools frame_aligner
# drive around the room
$ ros2 service call /frame_aligner/compute std_srvs/srv/Trigger

It publishes map -> mocap as a static transform and saves it (map_to_mocap.yaml) to publish it in later runs with static_transform_publisher. planar: true (default) fits a yaw and a translation, which suits robots on a floor.

5. Measure the error#

$ ros2 launch mocap4r2_gt_tools gt_evaluation.launch.yaml output_dir:=run1

gt_evaluator samples both trajectories at the same instants (TF interpolation) and publishes on ~/error (TrajectoryError) the ATE (after alignment, unless align: false) and the RPE over rpe_delta samples. When it ends it writes run1/estimate.tum and run1/groundtruth.tum, ready for evo:

$ evo_ape tum run1/groundtruth.tum run1/estimate.tum -a --plot

Time synchronization#

Mocap stamps come from the computer running the driver. If the robot has another clock, synchronize both (chrony/PTP). ros2 mocap4r2 doctor warns when the stamps of a system are far from the ROS clock. mocap4r2_gt_tools.trajectory.time_offset estimates the offset between two signals (for example the yaw rate of the ground truth and of the robot IMU) by cross-correlation.