Composable building blocks for creating trajectory planners for autonomous systems, with NumPy and JAX implementations of the MPPI algorithm.
Project description
The GitHub mirror of Faran exists for discoverability. The primary repo is on GitLab.
Faran: A Composable Trajectory Planning Library
Faran provides composable building blocks for trajectory planning in Python, intended for researchers who want a working planner quickly and the flexibility to customize components as needed.
The library includes implementations of MPPI, dynamics models, samplers, state estimation algorithms, cost functions, and other useful components, with support for both NumPy and JAX backends. The API is flexible, type-safe, and designed to minimize boilerplate.
Faran also provides an optional visualization package, faran-visualizer, which can generate standalone HTML files for interactive visualizations of simulation results.
Faran is being actively developed. That means some features may be missing, there are some gotchas, and some of the API might change. See the roadmap for what's available and what's coming. You can help by reporting issues or contributing fixes and features.
Why Faran?
The Python ecosystem has plenty of individual MPPI implementations 1, 2, 3, state estimation libraries 4, 5, and distance computation tools 6, but getting them to work together still requires a lot of glue code, plus reimplementing smaller components like cost functions, obstacle tracking, and motion prediction. Faran provides all of these under one roof, with a consistent API across backends.
Installation
Python 3.13+ is required.
pip install faran # NumPy + JAX (CPU only)
pip install faran[cuda] # JAX with GPU support
The visualizer CLI can be installed separately:
pip install faran-visualizer
Quick Start
Here's how you can configure an MPPI planner for the MPCC formulation, assuming a kinematic bicycle model:
from faran.numpy import mppi, model, sampler, trajectory, types, extract
import numpy as np
reference = trajectory.waypoints(
points=[(0, 0), (10, 0), (20, 5), (30, 0), (40, -5), (50, 0)],
path_length=35.0,
)
planner, augmented_model, contouring_cost, lag_cost = mppi.mpcc(
model=model.bicycle.dynamical(
time_step_size=0.1, wheelbase=2.5,
speed_limits=(0.0, 15.0), steering_limits=(-0.5, 0.5),
acceleration_limits=(-3.0, 3.0),
),
sampler=sampler.gaussian(
standard_deviation=[0.5, 0.05], rollout_count=256, seed=42,
to_batch=types.bicycle.control_input_batch.create
),
reference=reference,
# Components do not implicitly assume any semantic meaning for state dimensions.
position_extractor=extract.from_physical(lambda states: states.positions),
# Configs are typically typed dicts, so you get IDE support without many imports.
config={
"weights": {"contouring": 100.0, "lag": 100.0, "progress": 1000.0},
"virtual": {"velocity_limits": (0.0, 15.0)},
},
)
Switching from faran.numpy to from faran.jax uses the JAX backend. Since both backends have a compatible API, you don't need to make any other changes.
Full example: simulation loop + visualization
To see how the planner works, we can collect runtime data as follows:
from faran import access, collectors, metrics
planner = collectors.states.decorating(
planner,
# A tradeoff of the flexibility is that you need to tell the library
# how things are wired a bit more explicitly. This aspect of the API
# is still being iterated on, so expect some changes.
transformer=types.augmented.state_sequence.of_states(
physical=types.bicycle.state_sequence.of_states,
virtual=types.simple.state_sequence.of_states,
),
)
registry = metrics.registry(
error_metric := metrics.mpcc_error(contouring=contouring_cost, lag=lag_cost),
collectors=collectors.registry(planner),
)
Now we set up a dummy simulation loop.
state = types.augmented.state.of(
physical=types.bicycle.state.create(x=0.0, y=0.0, heading=0.0, speed=0.0),
virtual=types.simple.state.zeroes(dimension=1),
)
nominal = types.augmented.control_input_sequence.of(
physical=types.bicycle.control_input_sequence.zeroes(horizon=30),
virtual=types.simple.control_input_sequence.zeroes(horizon=30, dimension=1),
)
for _ in range(100):
control = planner.step(temperature=50.0, nominal_input=nominal, initial_state=state)
state = augmented_model.step(inputs=control.optimal, state=state)
nominal = control.nominal
Finally, we can visualize the results:
import asyncio
from faran_visualizer import MpccSimulationResult, configure, visualizer
errors = registry.get(error_metric)
result = MpccSimulationResult(
reference=reference,
states=registry.data(access.states.require()),
contouring_errors=errors.contouring,
lag_errors=errors.lag,
time_step_size=0.1,
wheelbase=2.5,
)
configure(output_directory=".")
asyncio.run(visualizer.mpcc()(result, key="quickstart"))
For a step-by-step walkthrough, see the Getting Started guide.
Features
See the feature overview for the full list of supported components, backend coverage, and roadmap.
Documentation
| Getting Started | Installation, first planner, simulation loop |
| User Guide | See the math behind the algorithms and understand how components work together |
| Examples | End-to-end scenarios with interactive visualizations |
| API Reference | Detailed usage instructions for every component |
Contributing
See CONTRIBUTING.md and DESIGN.md.
Code of Conduct
See CODE_OF_CONDUCT.md.
License
MIT, see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file faran-0.3.1.tar.gz.
File metadata
- Download URL: faran-0.3.1.tar.gz
- Upload date:
- Size: 190.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be77aaa7ec1990464e3698098a8793cbdd7b42a9e306bdbd5835f3bbb278f2aa
|
|
| MD5 |
85b22cc5c61707d3b10b111b98efa698
|
|
| BLAKE2b-256 |
60472feb392a04b37330bd4ec0346af9ff205c732fb90a90ba771b0090dd94c0
|
File details
Details for the file faran-0.3.1-py3-none-any.whl.
File metadata
- Download URL: faran-0.3.1-py3-none-any.whl
- Upload date:
- Size: 222.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
404d064baa2a0a8cc3b8a6aac1b9a5a0ba41ac4b77f0169cd6311232a3fb202e
|
|
| MD5 |
bf1589b815c0bc926db5b450630cf292
|
|
| BLAKE2b-256 |
aec4e9279aeb19a56e5528d29182aba425d092319260aeffd666f2a69aa8f679
|