{"id":22441441,"url":"https://github.com/decargroup/navlie","last_synced_at":"2025-04-12T18:41:04.170Z","repository":{"id":50368183,"uuid":"516410936","full_name":"decargroup/navlie","owner":"decargroup","description":"A state estimation package for Lie groups! ","archived":false,"fork":false,"pushed_at":"2025-03-04T20:03:38.000Z","size":11108,"stargazers_count":167,"open_issues_count":4,"forks_count":15,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-03T22:07:10.955Z","etag":null,"topics":["kalman-filter","lie-groups","navigation","python","robotics","state-estimation"],"latest_commit_sha":null,"homepage":"https://decargroup.github.io/navlie/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/decargroup.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-21T14:45:53.000Z","updated_at":"2025-03-30T14:29:34.000Z","dependencies_parsed_at":"2024-01-07T20:28:28.139Z","dependency_job_id":"90725438-102d-4194-8c2d-fd360802f6f9","html_url":"https://github.com/decargroup/navlie","commit_stats":null,"previous_names":["decargroup/pynav"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decargroup%2Fnavlie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decargroup%2Fnavlie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decargroup%2Fnavlie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decargroup%2Fnavlie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/decargroup","download_url":"https://codeload.github.com/decargroup/navlie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248616452,"owners_count":21134084,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kalman-filter","lie-groups","navigation","python","robotics","state-estimation"],"created_at":"2024-12-06T02:14:32.622Z","updated_at":"2025-04-12T18:41:04.150Z","avatar_url":"https://github.com/decargroup.png","language":"Python","readme":"navlie\n======\n.. image:: https://github.com/decargroup/navlie/actions/workflows/test_package.yml/badge.svg\n    :target: https://github.com/decargroup/navlie/actions/workflows/test_package.yml\n    :alt: Tests\n\n\n.. image:: https://github.com/decargroup/navlie/actions/workflows/publish_docs.yml/badge.svg\n    :target: https://github.com/decargroup/navlie/actions/workflows/publish_docs.yml\n    :alt: Docs\n\n.. image:: https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10-blue\n    :target: https://www.python.org/downloads/\n    :alt: Python Version\n    \n.. image:: ./docs/source/fun_figs.png \n    :alt: Demo Figures\n    :align: center\n    :width: 100%\n\n\nAn on-manifold state estimation library for robotics.\n\nThe core idea behind this project is to abstract-away the state definition such that a single estimator implementation can operate on a variety of state manifolds, such as the usual vector space, and any Lie group. At the moment, algorithms and features of this package include:\n\n- Extended Kalman Filter\n- Iterated Extended Kalman Filter\n- Sigmapoint Kalman Filters (Unscented, Spherical Cubature, Gauss-Hermite)\n- Interacting Multiple Model Filter\n- Batch MAP Estimation\n- A large collection of common process and measurement models\n- Out-of-the-box on-manifold numerical jacobian using finite differencing\n- Various utils for plotting, error, and consistency evaluation\n- Monte Carlo experiment executor with result aggregation\n- A preintegration module for linear, wheel odometry, and IMU process models\n\nBy implementing a few classes, the user can model almost any problem. Documentation can be found at https://decargroup.github.io/navlie\n\nDisclaimer\n----------\nWhile navlie is starting to get some maturity, its still definitely not perfect. The code is probably still simple enough that you can check out the  source directly to get a better understanding. If (when) you find a bug, please feel free to open an Github issue. Contributions/thoughts are welcome, and if anything regarding documentation is still grossly unclear, just let us know :). \n\nSetup\n-----\n\nInstallation\n^^^^^^^^^^^^\n\nClone this repo, change to its directory, and execute \n\n.. code-block:: bash\n\n    pip install -e .\n\nThis command should automatically install all dependencies, including our package `pymlg` (found at https://github.com/decargroup/pymlg) for back-end Lie group mathematical operations.\n\nExamples\n^^^^^^^^\nSome starting examples running EKFs can be found in the `examples/` folder. Simply run these as python3 scripts \n\nTests\n^^^^^\nTo run integration tests, \n\n.. code-block:: bash\n\n    pytest tests\n\nor, to run tests on a specific test file, \n\n.. code-block:: bash\n\n    pytest -ra tests/integration/filename.py\n    \nThe Core Concept - Defining a `State` Implementation\n----------------------------------------------------\n\nThe algorithms and models in this repo are centered around the abstract `State` class. An instance of `State` is an object containing, at a minimum, the following attributes:\n\n- `value`: a value of some sort;\n- `dof`: the degrees of freedom associated with the state.\n\nIt will also contain the following mandatory methods that must be implemented by the user.\n\n- `plus()`:  A generic \"addition\" operation given a `dx` vector with as many elements as the `dof` of this state.\n- `minus()`:  A generic \"subtraction\" operation given another State object of the same type, which returns a numpy array of error values.\n- `copy()`: A method that returns a new object of the same type, and with the same attibute values.\n\nOptionally, it is often useful to assign a timestamp (`stamp`) and a label (`state_id`) to differentiate state instances from others. The snippet below shows how to define a simple vector-space state:  \n\n\n.. code-block:: python\n\n    from navlie.types import State \n    import numpy as np\n\n    class VectorState(State):\n        \"\"\"\n        A standard vector-based state, with value represented by a 1D numpy array.\n        \"\"\"\n\n        def __init__(self, value: np.ndarray, stamp: float = None, state_id=None):\n            super(VectorState, self).__init__(\n                value=value,\n                dof=value.size,\n                stamp=stamp,\n                state_id=state_id,\n            )\n\n        def plus(self, dx: np.ndarray):\n            new = self.copy()\n            new.value = new.value + dx\n            return new\n\n        def minus(self, x: \"VectorState\") -\u003e np.ndarray:\n            return self.value - x.value\n\n        def copy(self) -\u003e \"VectorState\":\n            return VectorState(self.value.copy(), self.stamp, self.state_id)\n\n\nAs another more complicated example, a state object belonging to the SE(3) Lie group can be implemented as \n\n.. code-block:: python\n\n    from navlie.types import State \n    from pymlg import SE3 \n    import numpy as np \n\n    class SE3State(State):\n        def __init__(self, value: np.ndarray, stamp: float = None, state_id=None):\n            super(SE3State, self).__init__(\n                value=value,\n                dof=6,\n                stamp=stamp,\n                state_id=state_id,\n            )\n        \n        def plus(self, dx: np.ndarray):\n            new = self.copy()\n            new.value = new.value @ SE3.Exp(dx)\n            return new\n\n        def minus(self, x: \"SE3State\") -\u003e np.ndarray:\n            return SE3.Log(SE3.inverse(x.value) @ self.value)\n\n        def copy(self) -\u003e \"SE3State\":\n            return SE3State(self.value.copy(), self.stamp, self.state_id)\n\n\nProcess and Measurement Models\n------------------------------\n.. image:: ./docs/source/system_diagram.png\n    :alt: System Diagram\n\nThere are a few more core types in this package. The main ones are the `ProcessModel` and `MeasurementModel` classes. Both of these are abstract classes requiring the user to implement\n\n- an `evaluate()` method, \n- a `covariance()` method,\n- and optionally a `jacobian()` method.\n\nFor example, a simple \"single integrator\" (velocity input) model can be implemented as follows:\n\n.. code-block:: python\n\n    class SingleIntegrator(ProcessModel):\n        \"\"\"\n        The single-integrator process model is a process model of the form\n\n            x_k = x_{k-1} + dt * u_{k-1}\n        \"\"\"\n\n        def __init__(self, Q: np.ndarray):\n            self._Q = Q\n\n        def evaluate(self, x: VectorState, u: VectorInput, dt: float) -\u003e np.ndarray:\n            \"\"\"\n            Returns a state with an updated value according to a process model.\n            \"\"\"\n            x.value = x.value + dt * u.value\n            return x\n\n        def jacobian(self, x: VectorState, u: VectorInput, dt: float) -\u003e np.ndarray:\n            \"\"\"\n            (optional) Jacobian of the process model with respect to the state.\n            \"\"\"\n            return np.identity(x.dof)\n\n        def covariance(self, x: VectorState, u: VectorInput, dt: float) -\u003e np.ndarray:\n            \"\"\"\n            Returns the covariance of the process model errors.\n            \"\"\"\n            return dt**2 * self._Q\n\n\nSimilarly, a single distance-to-landmark measurement model can be implemented as \n\n.. code-block:: python \n\n    class RangePointToAnchor(MeasurementModel):\n        \"\"\"\n        Range measurement from a point state to an anchor (which is also another\n        point).\n        \"\"\"\n\n        def __init__(self, anchor_position: List[float], R: float):\n            self._r_cw_a = np.array(anchor_position)\n            self._R = np.array(R)\n\n        def evaluate(self, x: VectorState) -\u003e np.ndarray:\n            r_zw_a = x.value\n            y = np.linalg.norm(self._r_cw_a - r_zw_a)\n            return y\n\n        def jacobian(self, x: VectorState) -\u003e np.ndarray:\n            r_zw_a = x.value\n            r_zc_a = r_zw_a - self._r_cw_a\n            y = np.linalg.norm(r_zc_a)\n            return r_zc_a.reshape((1, -1)) / y\n\n        def covariance(self, x: VectorState) -\u003e np.ndarray:\n            return self._R\n\n\nIn fact, for both `ProcessModel` and `MeasurementModel`, subclasses will inherit a finite-difference numerical differentiation method `jacobian_fd()`, which also serves as the default implementation if `jacobian` is not overriden. Nevertheless, it allows for an easy way to check your `jacobian()` implementation! (`evaluate()` method must be implemented for this to work, see some of the files in `tests/` for an example of this.)\n\nBuilt-in Library\n----------------\nMany state, process, and measurement models are already written and part of the built-in library and, as an example, can be accessed with \n\n.. code-block:: python \n\n    from navlie.lib.states import VectorState, SE3State\n    from navlie.lib.models import RangePoseToAnchor, Altitude\n\nThe following state types are currently part of the lib:\n\n- `VectorState`\n- `SO2State`\n- `SO3State`\n- `SE2State`\n- `SE3State`\n- `SE23State`\n- 'SL3State'\n- `IMUState` (contains IMU biases as part of the state)\n- `CompositeState` (for holding many sub-states as a single state)\n\nThe following process models are currently part of the lib:\n\n- `SingleIntegrator`\n- `BodyFrameVelocity`\n- `RelativeBodyFrameVelocity`\n- `CompositeProcessModel`\n- `IMUKinematics`\n\nThe following measurement models are currently part of the lib:\n\n- `RangePointToAnchor`\n- `RangePoseToAnchor`\n- `RangePoseToPose`\n- `RangeRelativePose`\n- `GlobalPosition`\n- `Altitude` \n- `Gravitometer`\n- and many more\n\nFinally, this repo has the following state estimation algorithms implemented:\n\n- `ExtendedKalmanFilter`\n- `IteratedKalmanFilter`\n- `UnscentedKalmanFilter`\n- `InteractingModelFilter`\n- and more\n\n\nContributing\n------------\nIf you wish to make some changes, fork this repo, make your changes, and then make a pull request. Here are some conventions that should be followed:\n\n- Code style should follow the PEP8 style guide. https://peps.python.org/pep-0008. We recommend using `black --line-length 80 .` to format the code.\n- Everything should be type hinted as much as possible. Essentially, in the VS Code dark theme, you should not have any white text. \n\nThe goal of this project is to write general algorithms that work for any implementation of the abstract `State`, `ProcessModel` and `MeasurementModel`. As such, please give thought to how this could be done to any algorithm you implement. As a rule of thumb, code outside of the `navlie/lib` folder should not depend on any of the classes in `navlie/lib`, although sometimes this rule is broken. \n\nIf you want to discuss anything regarding this repo, feel free to email `charles.c.cossette@gmail.com`.\n\n\nContributing to the Documentation\n---------------------------------\nYou must first install the dependencies for the documentation. This can be done by running\n\n.. code-block:: bash\n\n    pip install -r docs/requirements.txt\n\nAfter this is done, change to the `./docs/` directory and run \n\n.. code-block:: bash\n\n    make html\n\nafter which the documentation will be updated, and viewable by opening the ``docs/index.html`` file in your browser.  In terms of actually writing documentation, we use the numpy format, which can be seen in some of the existing docstrings in the code, and used as a template. \n\nAlternatively and prefereably, install the `autoDocstring extension for VSCode. \u003chttps://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring\u003e` and change the docstring format in the settings to `numpy`.\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecargroup%2Fnavlie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdecargroup%2Fnavlie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecargroup%2Fnavlie/lists"}