evo
evo is a Python package for the evaluation of odometry and SLAM (Simultaneous Localization and Mapping) algorithms. It provides a robust command-line interface and a modular Python library for handling, evaluating, and comparing trajectory outputs from various formats like TUM, KITTI, EuRoC MAV, and ROS bagfiles. It includes tools for association, alignment, scale adjustment (for monocular SLAM), flexible output, plotting, and visualization. The library is actively maintained, with the current version being 1.35.2, and supports Python 3.10+.
Common errors
-
evo_ape: command not found (or similar for evo_traj, evo_rpe)
cause The executables provided by the 'evo' package are not in your system's PATH, or argcomplete (for tab completion) was not installed correctly.fixEnsure pip's script directory is in your system's PATH. If installing with `--no-binary evo` (recommended for CLI usage), make sure `argcomplete` is installed and activated. Sometimes, restarting the terminal or system can resolve this. For programmatic use, you can always import and call functions directly (e.g., `python -c 'from evo.main_ape import ape; ...'`). -
ModuleNotFoundError: No module named 'evo.core'
cause The 'evo' package is not installed in the currently active Python environment, or there's a typo in the import statement.fixVerify that 'evo' is installed in your active virtual environment using `pip show evo`. If not, run `pip install evo`. Check for typos in your import statements (e.g., `from evo.core.trajectory import PoseTrajectory3D`).
Warnings
- breaking Python 2.7 support was dropped after evo version 1.12.0. The current version requires Python 3.10+.
- gotcha Jupyter Notebook or IPython environments may encounter issues if the kernel's Python version does not match the version where evo was installed, leading to import errors or unexpected behavior.
- gotcha Plotting operations, especially with Matplotlib, can sometimes be slow due to the overhead of loading the plotting library and rendering complex figures. This is particularly noticeable for large datasets or multiple plots.
Install
-
pip install evo -
pip install evo --upgrade --no-binary evo
Imports
- PoseTrajectory3D
from evo.core.trajectory import PoseTrajectory3D
- metrics
from evo.core import metrics
- file_interface
from evo.tools import file_interface
- sync
from evo.core import sync
- plot
from evo.tools import plot
Quickstart
import os
import numpy as np
from evo.core import metrics, sync
from evo.core.trajectory import PoseTrajectory3D
from evo.tools import file_interface, plot
from evo.tools.settings import SETTINGS
import matplotlib.pyplot as plt
# Create dummy trajectory files for demonstration
# In a real scenario, these would be actual ground truth and estimated trajectories
ref_file_content = """
1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
2.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0
3.0 2.0 0.0 0.0 0.0 0.0 0.0 1.0
4.0 3.0 0.0 0.0 0.0 0.0 0.0 1.0
"""
est_file_content = """
1.0 0.1 0.0 0.0 0.0 0.0 0.0 1.0
2.0 1.1 0.0 0.0 0.0 0.0 0.0 1.0
3.0 2.1 0.0 0.0 0.0 0.0 0.0 1.0
4.0 3.1 0.0 0.0 0.0 0.0 0.0 1.0
"""
# Save dummy files
dummy_dir = "./evo_quickstart_data"
os.makedirs(dummy_dir, exist_ok=True)
ref_path = os.path.join(dummy_dir, "ref.tum")
est_path = os.path.join(dummy_dir, "est.tum")
with open(ref_path, "w") as f: f.write(ref_file_content)
with open(est_path, "w") as f: f.write(est_file_content)
# 1. Load trajectories (TUM format in this example)
traj_ref = file_interface.read_tum_trajectory_file(ref_path)
traj_est = file_interface.read_tum_trajectory_file(est_path)
# 2. Associate trajectories by timestamps
traj_ref, traj_est = sync.associate_trajectories(traj_ref, traj_est, max_diff=0.1)
# 3. Align trajectories (e.g., SE(3) Umeyama alignment)
traj_est_aligned = traj_est.copy()
traj_est_aligned.align(traj_ref)
# 4. Calculate Absolute Pose Error (APE)
ape_metric = metrics.APE(metrics.PoseRelation.translation_part)
ape_stats = ape_metric.process_trajectory(traj_ref, traj_est_aligned)
print("\n--- APE Statistics (Translation Part) ---")
print(f"RMSE: {ape_stats.rmse:.4f}")
print(f"Mean: {ape_stats.mean:.4f}")
print(f"Max: {ape_stats.max:.4f}")
# 5. Plotting (optional)
SETTINGS.plot_usetex = False # Disable LaTeX for simpler plotting
fig = plt.figure(figsize=(10, 8))
plot.trajectories(fig, {"reference": traj_ref, "estimate_aligned": traj_est_aligned}, plot.PlotMode.xyz)
plt.title("Trajectories (Aligned)")
plt.show()
# Clean up dummy files and directory
os.remove(ref_path)
os.remove(est_path)
os.rmdir(dummy_dir)