From a5393014b96ae2a2c02dbbe2e2078ca0208d4a00 Mon Sep 17 00:00:00 2001 From: Easton Potokar Date: Fri, 10 Apr 2026 12:29:27 -0400 Subject: [PATCH] Update a bunch of docs --- README.md | 4 ++-- docs/examples/data_loading.md | 4 ++-- docs/examples/dataset.md | 4 ++-- docs/examples/evaluation.md | 4 ++-- docs/examples/odometry.md | 4 ++-- docs/examples/pipeline.md | 26 ++++++++++++++++---------- docs/install.md | 2 +- docs/quickstart.md | 8 ++++---- docs/ref/pipelines.md | 5 +++-- python/evalio/cli/__init__.py | 3 --- python/evalio/cli/stats.py | 2 +- python/evalio/datasets/base.py | 2 +- 12 files changed, 36 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3468fbcd..b4876076 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ evalio can be used both as a python library and as a CLI for both datasets and p Once evalio is installed, datasets can be listed and downloaded via the CLI interface. For example, to list all datasets and then download a sequence from the hilti-2022 dataset, ```bash evalio ls datasets -evalio download hilti_2022/basement_2 +evalio dl hilti_2022/basement_2 ``` Once downloaded, a trajectory can then be easily used in python, @@ -108,4 +108,4 @@ If you use evalio in your research, please cite the following paper, primaryClass={cs.RO}, url={https://arxiv.org/abs/2507.16000}, } -``` \ No newline at end of file +``` diff --git a/docs/examples/data_loading.md b/docs/examples/data_loading.md index 1930ebf0..2d526d21 100644 --- a/docs/examples/data_loading.md +++ b/docs/examples/data_loading.md @@ -81,7 +81,7 @@ from evalio.rerun import convert # Initialize rerun rr.init("evalio") -rr.connect_tcp() +rr.connect_grpc() # Stream lidar scans to rerun for scan in Hilti2022.basement_2.lidar(): @@ -89,4 +89,4 @@ for scan in Hilti2022.basement_2.lidar(): rr.log("lidar", convert(scan, color="z")) ``` -If anything is unclear, please open an issue on the evalio repository. We are always looking to improve the documentation and make it easier to use. \ No newline at end of file +If anything is unclear, please open an issue on the evalio repository. We are always looking to improve the documentation and make it easier to use. diff --git a/docs/examples/dataset.md b/docs/examples/dataset.md index 7bd4d872..afbeeca7 100644 --- a/docs/examples/dataset.md +++ b/docs/examples/dataset.md @@ -70,7 +70,7 @@ Additionally, there is a number of optional methods that you can implement to ad def vehicle(self) -> str: ... - def download(self) -> str: ... + def download(self) -> None: ... def quick_len(self) -> Optional[int]: ... ``` @@ -82,4 +82,4 @@ The next three are again self-explanatory, all of which provide information for `quick_len` returns a hardcoded number of scans in a dataset, used for `evalio ls` and for computing time estimates in `evalio run`. If not set, evalio will load the data to compute the length. -That's all there is to it! Datasets are fairly simple - mostly just parameter setting and easy-to-use iterator wrappers. If you have an dataset implementation of an open-source dataset, feel free to make a PR to add it to evalio so others can use it as well. \ No newline at end of file +That's all there is to it! Datasets are fairly simple - mostly just parameter setting and easy-to-use iterator wrappers. If you have an dataset implementation of an open-source dataset, feel free to make a PR to add it to evalio so others can use it as well. diff --git a/docs/examples/evaluation.md b/docs/examples/evaluation.md index 81096c1f..c0b5e8ba 100644 --- a/docs/examples/evaluation.md +++ b/docs/examples/evaluation.md @@ -63,6 +63,6 @@ Results will be saved to the `output_dir` specified in the config file, with nes Once trajectories have been run, statistics can be calculated, ```bash -evalio stats -d results -m mean -w 200 -s RTEt +evalio stats results --metric mean --w-meters 200 --sort RTEt_200.0m ``` -With `-m/--metric` specifying the metric to calculate with options including mean, median, and sse and `-w/--window` specifying the window size for RTE, with a default of 100 scans. Only first part of all trajectories can also be done using the `-l/--length` option. Sorting of the results can be done with the `-s/--sort` option, with any column heading being an allowed option. \ No newline at end of file +With `--metric` specifying the metric to calculate with options including mean, median, and sse, and `--w-meters` / `--w-seconds` specifying RTE windows (defaults to `--w-meters 30` and can be repeated). Only first part of all trajectories can also be done using the `-l/--length` option. Sorting of the results can be done with `-S/--sort`, with any column heading being an allowed option. diff --git a/docs/examples/odometry.md b/docs/examples/odometry.md index c0fba751..6e0d767a 100644 --- a/docs/examples/odometry.md +++ b/docs/examples/odometry.md @@ -44,7 +44,7 @@ from evalio.types import Trajectory from evalio.datasets import NewerCollege2020 from evalio import stats -traj = Trajectory.from_experiment("odometry.csv") +traj = Trajectory.from_file("odometry.csv") gt = NewerCollege2020.short_experiment.ground_truth() # Align the odometry to the ground truth @@ -52,4 +52,4 @@ traj_aligned, gt_aligned = stats.align(traj, gt) # Compute metrics as desired (will align if not already aligned) error = stats.rte(traj, gt).mean() -``` \ No newline at end of file +``` diff --git a/docs/examples/pipeline.md b/docs/examples/pipeline.md index a06b187b..12437768 100644 --- a/docs/examples/pipeline.md +++ b/docs/examples/pipeline.md @@ -33,7 +33,7 @@ To create a pipeline, simply inherit from the `Pipeline` class, # Getters def pose(self) -> SE3: ... - def map(self) -> list[Point]: ... + def map(self) -> dict[str, list[Point]]: ... # Setters def set_imu_params(self, params: ImuParams): ... @@ -44,7 +44,7 @@ To create a pipeline, simply inherit from the `Pipeline` class, # Doers def initialize(self): ... def add_imu(self, mm: ImuMeasurement): ... - def add_lidar(self, mm: LidarMeasurement) -> list[Point]: ... + def add_lidar(self, mm: LidarMeasurement) -> None: ... ``` === "C++" @@ -72,7 +72,7 @@ To create a pipeline, simply inherit from the `Pipeline` class, // Getters const SE3 pose() { ... }; - const std::vector map() { ... }; + const evalio::Map<> map() { ... }; // Setters void set_imu_params(ImuParams params) { ... }; @@ -83,7 +83,7 @@ To create a pipeline, simply inherit from the `Pipeline` class, // Doers void initialize() { ... }; void add_imu(ImuMeasurement mm) { ... }; - std::vector add_lidar(LidarMeasurement mm) { ... }; + void add_lidar(LidarMeasurement mm) { ... }; } ``` @@ -93,6 +93,8 @@ We'll cover each section of methods in turn. The first four methods are all static methods that provide information about the pipeline. `version`, `url`, and `name` are all self-explanatory. `default_params` is a static method that returns a dictionary of the default parameters for the pipeline. This is used to verify parameters before they are passed in, as well as ensure a consistent output for each run. +In C++ there is additionally a number of helper type conversion functions that can make converting between iterators, point types, and geometry types simpler. A good example of this can be found in the `lio_sam.h` binding where it is used to convert pose and point types. These converters can additionally be leveraged by the `save` methods described below. + ## Getters The next two methods are getters for the pose and map. The pose is the most up-to-date estimate for the IMU and is polled after each lidar measurement is passed in. @@ -112,7 +114,11 @@ Arguably the most important part. `add_imu` is called for each IMU measurement. This is where the IMU data is processed and used to update the pose. -`add_lidar` is called for each lidar measurement. This is where the lidar data is processed and used to update the map. It returns a list of features were extracted from the scan and are used for visualization. +`add_lidar` is called for each lidar measurement. This is where the lidar data is processed and used to update the map. + +Saving poses can be done asynchronously, using `save(stamp, pose)`. In C++, the type of `pose` can be anything that has the method `evalio::convert(const MyPose& pose)` implemented. + +For visualization, features can be save similarly with either `save(stamp, {"key": features})` in python, or `save(stamp, "key1", feat1, "key2", feat2)` in C++. Again, `feat1` and `feat2` can be any type that are iterators with their internal point types convertible to `evalio::Point`. ## C++ Building @@ -125,11 +131,11 @@ NB_MODULE(_core, m) { // Only have to override the static methods here // All the others will be automatically inherited from the base class - nb::class_(m, "MyCppPipeline") + nb::class_(m, "MyPipeline") .def(nb::init<>()) - .def_static("name", &MyCppPipeline::name) - .def_static("url", &MyCppPipeline::url) - .def_static("default_params", &MyCppPipeline::default_params); + .def_static("name", &MyPipeline::name) + .def_static("url", &MyPipeline::url) + .def_static("default_params", &MyPipeline::default_params); } ``` @@ -145,4 +151,4 @@ We recommend then setting everything up to be built with [`scikit-build-core`](h m.def("abi_tag", []() { return nb::detail::abi_tag(); }); ``` -That's all there is to it! Pipelines should be fairly easy to implement and are usually just a simple wrapper around your existing code to provide a common interface. Once your pipeline is open-source/published/etc, feel free to make a PR to add it to evalio. This both improves the visibility of your work and of evalio. \ No newline at end of file +That's all there is to it! Pipelines should be fairly easy to implement and are usually just a simple wrapper around your existing code to provide a common interface. Once your pipeline is open-source/published/etc, feel free to make a PR to add it to evalio. This both improves the visibility of your work and of evalio. diff --git a/docs/install.md b/docs/install.md index 567db137..7ce80d02 100644 --- a/docs/install.md +++ b/docs/install.md @@ -23,7 +23,7 @@ make ``` ### Pipelines -By default, pipelines are not included due to their large dependencies. We use vpckg to handle a reliable build of these dependencies and pipelines. vcpkg and the pipelines can be setup via running +By default, pipelines are not included due to their large dependencies. We use vcpkg to handle a reliable build of these dependencies and pipelines. vcpkg and the pipelines can be setup via running ```bash ./cpp/setup_pipelines.sh ``` diff --git a/docs/quickstart.md b/docs/quickstart.md index c40c58bf..8f3f4c45 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -12,7 +12,7 @@ evalio can be used both as a python library and as a [CLI](ref/cli.md) for both Once evalio is installed, datasets can be listed and downloaded via the [CLI](ref/cli.md) interface. For example, to list all datasets and then download a sequence from the hilti-2022 dataset, ```bash evalio ls datasets -evalio download hilti_2022/basement_2 +evalio dl hilti_2022/basement_2 ``` evalio downloads data to the path given by `-D`, `EVALIO_DATA` environment variable, or if both are unset to the local folder `./evalio_data`. All the trajectories in a dataset can also be downloaded by using the wildcard `hilti_2022/*`, making sure to escape the asterisk as needed. @@ -67,10 +67,10 @@ import rerun as rr from evalio.rerun import convert rr.init("evalio") -rr.connect_tcp() +rr.connect_grpc() for scan in ds.Hilti2022.basement_2.lidar(): rr.set_time("timeline", timestamp=scan.stamp.to_sec()) - rr.log("lidar", convert(scan, color=[255, 0, 255])) + rr.log("lidar", convert(scan, color=(255, 0, 255))) ``` !!! note @@ -143,4 +143,4 @@ where m -> map, s -> scan, i -> intensity image, and f -> extracted features can That's about the gist of it! Try playing around the [CLI](ref/cli.md) interface to see what else is possible. Feel free to open an issue if you have any questions, suggestions, or problems. -Additionally, we recommend checking out the examples section for specific use cases for evalio. \ No newline at end of file +Additionally, we recommend checking out the examples section for specific use cases for evalio. diff --git a/docs/ref/pipelines.md b/docs/ref/pipelines.md index 0238cb69..5398eb09 100644 --- a/docs/ref/pipelines.md +++ b/docs/ref/pipelines.md @@ -5,12 +5,13 @@ For more information about the pipelines included in evalio, see the [included p members: - Pipeline - CTICP - - KissICP + - DLIO + - FORM - GenZICP + - KissICP - LOAM - LioSAM - MadICP - - FORM - PipelineNotFound - UnusedPipelineParam - InvalidPipelineParamType diff --git a/python/evalio/cli/__init__.py b/python/evalio/cli/__init__.py index 1189397a..59d33c36 100644 --- a/python/evalio/cli/__init__.py +++ b/python/evalio/cli/__init__.py @@ -55,9 +55,6 @@ def module_callback(value: Optional[list[str]]) -> list[Any]: @app.callback() def global_options( - # Marking this as a str for now to get autocomplete to work, - # Once this fix is released (hasn't been as of 0.15.2), we can change it to a Path - # https://github.com/fastapi/typer/pull/1138 data_dir: Annotated[ Optional[Path], typer.Option( diff --git a/python/evalio/cli/stats.py b/python/evalio/cli/stats.py index ae7f7560..3509b71e 100644 --- a/python/evalio/cli/stats.py +++ b/python/evalio/cli/stats.py @@ -286,7 +286,7 @@ def evaluate_typer( # Parse some of the options if only_complete and only_failed: raise typer.BadParameter( - "Can only use one of --only-complete, --only-incomplete, or --only-failed." + "Can only use one of --only-complete or --only-failed." ) # Parse the filtering options diff --git a/python/evalio/datasets/base.py b/python/evalio/datasets/base.py index 24d0628d..adc72491 100644 --- a/python/evalio/datasets/base.py +++ b/python/evalio/datasets/base.py @@ -233,7 +233,7 @@ def _fail_not_downloaded(self): if not self.is_downloaded(): # TODO: Make this print with rich? raise ValueError( - f"Data for {self} not found, please use `evalio download {self}` to download" + f"Data for {self} not found, please use `evalio dl {self}` to download" ) @classmethod