-
Notifications
You must be signed in to change notification settings - Fork 758
evo_traj
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.
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 bag:
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
).
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
.
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. Use evo_config set plot_mode_default xy
to permanently change the default 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). If timestamps are present, velocities will be plotted too.
See also here for further information: Plotting
See here.
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.
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
.
(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.
(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
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!).