Skip to content

evo_traj

Michael Grupp edited this page Mar 18, 2024 · 25 revisions

evo_traj is the main tool to do house-keeping stuff with multiple trajectories, such as:

  • displaying some infos
  • plotting
  • verifying that the data is valid
  • exporting to other formats
  • applying transformations

etc.

Basics

evo_traj can open as many trajectories as you want. In case of a text based trajectory format (tum, euroc, kitti - see also the formats chapter) you give the trajectory files as arguments, for example:

evo_traj tum traj_1.txt traj_2.txt traj_3.txt

(here, you could also use glob notation on a UNIX-like system: evo_traj tum traj_*)

In case of a ROS bagfile, you give the file path followed by the names of the topics you want to use:

evo_traj bag data.bag /groundtruth /odom /tf:map.base_link

or, with a ROS2 bags:

evo_traj bag2 data /groundtruth /odom /tf:map.base_link

You can also use the --all_topics option to load all trajectories inside the bagfile. TF topics can be used with a special syntax described here

A reference trajectory can be marked with --ref:

evo_traj bag data.bag /odom /tf:map.base_link --ref /groundtruth

You have to give the --ref argument if you want to use the alignment features with evo_traj (-a / --align, -s / --correct_scale or --n_to_align).

Check trajectory data

By default, evo_traj prints out only a few important infos about the trajectories that you feed into it in this format:

name:	groundtruth
infos:	12765 poses, 304.207m path length, 889.019s duration

In verbose mode (-v/--verbose) the output changes to this format:

name:   groundtruth
infos
        duration (s)    889.01894474
        nr. of poses    12765
        path length (m) 304.206897009
        pos_end (m)     [ -3.32159757  -4.64051651  32.7839329 ]
        pos_start (m)   [-0.00489994 -0.01775981 -0.01375532]
        t_end (s)       1502793459.3
        t_start (s)     1502792570.28

You can get the most detailed output with the --full_check flag. This performs some math and logic checks - e.g. if the quaternions have unit norm or if the timestamps are ascending. Some speed values are shown as well (except for kitti where we don't have timestamps).

name:   groundtruth
infos
        duration (s)    889.01894474
        nr. of poses    12765
        path length (m) 304.206897009
        pos_end (m)     [ -3.32159757  -4.64051651  32.7839329 ]
        pos_start (m)   [-0.00489994 -0.01775981 -0.01375532]
        t_end (s)       1502793459.3
        t_start (s)     1502792570.28
checks
        SE(3) conform   yes
        array shapes    ok
        nr. of stamps   ok
        quaternions     ok
        timestamps      ok
stats
        v_avg (km/h)    1.411572
        v_avg (m/s)     0.392103
        v_max (km/h)    3.038775
        v_max (m/s)     0.844104
        v_min (km/h)    0.001567
        v_min (m/s)     0.000435

Tip: On UNIX-like systems, pipe the output to less to get a more comfortable view when loading multiple trajectories. If you don't want any output except warnings and errors, use --silent.

Plotting

Append -p or --plot to your command to plot the trajectories. You can specify the view with --plot_mode - e.g. --plot_mode xz for a 2D view at the x and z axes or --plot_mode xyz for a 3D view. In any case, there's also a second tab in the plot window with the x, y and z values plotted individually and a third one with roll, pitch and yaw angles (xyz-convention).

See also here for further information: Plotting

Exporting

See here.

Alignment and transformation

Geometric alignment

If you give a reference trajectory with --ref, you can align the other trajectories to the reference with Umeyama's method:

  • --align or -a = SE(3) Umeyama alignment (rotation, translation)
  • --align --correct_scale or -as = Sim(3) Umeyama alignment (rotation, translation, scale)
  • --correct_scale or -s = scale correction only

The alignment_demo.py script shows the different types of alignment with an example trajectory. It's also possible to align only the first n poses of the trajectories with --n_to_align, for example --n_to_align 100.

New since v1.5.0: A simple origin alignment that can be useful for drift/loop closure evaluation is available with --align_origin. This is not based on the Umeyama algorithm.

Temporal alignment

This is done by searching the best matching timestamps between the reference and the other trajectories. All trajectories are then reduced to the best matching timestamps. If no matches are found, an error is thrown. The options for this step are:

  • --t_offset: add a constant timestamp offset (not adding to --ref trajectory) - default: 0.0s
  • --t_max_diff: maximum timestamp difference for data association - default: 0.01s

All geometric alignment methods (--align, --correct_scale) do this automatically to do point registration. You can also just synchronize the timestamps of the trajectories without any geometric alignment with --sync.

Projection

(since v1.26.0)

You can project the poses into a plane with --project_to_plane and the desired plane (xy, xz or yz). For example, --project_to_plane xy:

Note: Projection is done before any potential geometric alignment.

Downsampling and Filtering

(since v1.26.0)

Trajectories can be downsampled to a fixed maximum number of poses. This can be useful for example if you have very large data and want to improve plotting performance.

evo_traj tum data.txt -v --downsample 1000

A smarter type of filtering is a motion filter. This filters out poses that didn't move enough compared to a previous pose. This can be useful for example to remove parts of your data in which nothing interesting happened, keeping only motions that are above the translation or angle threshold.

Example that filters with a threshold of 0.5m and 5 degrees:

evo_traj tum data.txt -v --motion_filter 0.5 5

Transformations

You can also transform the poses of the trajectories with a custom 3D transformation. For this, you need a .json file with the translation vector and the rotation quaternion in this format:

{
  "x": 0.0,
  "y": 0.0,
  "z": 0.0,
  "qx": 0.0,
  "qy": 0.0,
  "qz": 0.0,
  "qw": 1.0
}

You can alternatively also save 4x4 SE(3) matrices in either a text (np.savetxt) or binary format (np.save) using numpy and load them with the same command line argument as the JSON format.

To apply such a transformation from the global frame, use --transform_left <json file>. To transform each pose from its own local frame, use --transform_right <json file> (this changes the shape of the trajectory if it includes a translation!).