Cross-solver NMPC benchmark harness.
This repository is intentionally solver-neutral. It keeps:
- canonical benchmark case specs
- native targets for embedded solvers and adapters for external solver stacks
- git submodules under
third_party/for external solver code - result directories
- plotting utilities
- CI for validating the harness itself
It does not vendor solver source trees or generated benchmark outputs. External solvers are pulled in as git submodules instead.
Fairness rules in this repository:
- headline solver comparisons use same asset, model family,
dt, horizon, and requested closed-loop steps; seeresults/asset_benchmark_report.md - official
acadosexamples define the benchmark problems acadostimings measure compiled C closed-loop runners, not Python export/codegenMiniSolverruns as a native embedded C++ target linked directly into the benchmark appCasADitimings measure repeated solve calls on a pre-built CasADi SQP graph; one-time graph construction is excluded- case-specific termination follows the official closed-loop logic for that case
- official
race_carsandquadrotor_navrequire piecewise track functions. MiniSolver handles them through dcol-style model-update callbacks: the runner samples the official spline/ppoly geometry and refreshes smooth local polynomial jets as stage parameters before each solve iteration.
cases/: benchmark case definitionstargets/minisolver/: MiniSolver native benchmark target and local runner sourcebackends/acados/: acados export/build/run adapterbackends/casadi/: CasADi SQP adapterbackends/altro/: ALTRO C++ adapter for robotics asset candidatesassets/: canonical external reference assets imported from public MPC repositoriesthird_party/: solver checkouts managed as git submodulesresults/raw/: ignored raw benchmark outputresults/figures/: ignored generated plotsplots/: result aggregation and plotting helpersrun.py: unified entry point
Use results/asset_benchmark_report.md for the current same-condition,
end-to-end solver comparison. It is the report intended for ranking solvers.
Asset-derived headline candidates:
data_driven_mpc_loop_trackingdata_driven_mpc_lemniscate_trackingnonlinear_mpcc_porto_followingnonlinear_mpcc_fssim_following
Asset-derived stress candidate:
mpcc_track_following
Official compatibility/reference cases:
pendulum_on_cartrace_carsquadrotor_navchain_mass
race_cars and quadrotor_nav are kept as official acados compatibility cases.
Their MiniSolver models use generated C++ plus callback-refreshed local spline
jets, so the benchmark can compare the same official track geometry without
requiring Python MiniModel ppoly support.
minisolveracadoscasadiclarabelfor convex asset cases onlyaltrofor convex robotics asset cases only
Besides the official acados solver cases, this repository now keeps a small
asset library for future benchmark expansion across different model families.
Current imported sources:
- autonomous driving:
alexliniger/MPCCnirajbasnet/Nonlinear_MPCC_for_autonomous_racingargoverse-apisample trajectories
- robotics:
uzh-rpg/data_driven_mpcloop and lemniscate references
Import or refresh them with:
python3 scripts/import_reference_assets.pyThe importer writes canonical CSVs under assets/reference/ plus provenance
metadata in assets/catalog.json.
Initialize external solvers:
git submodule update --init --recursive
./scripts/bootstrap_acados.shRun MiniSolver on the official pendulum case:
python3 run.py --backend minisolver --case pendulum_on_cartRun MiniSolver against a local development checkout instead of the pinned submodule:
python3 run.py --backend minisolver --case pendulum_on_cart --minisolver-source-dir /path/to/MiniSolverRun acados on the same case:
python3 run.py --backend acados --case pendulum_on_cartRun CasADi SQP on the same case:
python3 run.py --backend casadi --case pendulum_on_cartAggregate the latest raw data:
./scripts/summarize_results.py
./scripts/write_report.pyRun all four official MiniSolver compatibility cases from a local development checkout:
python3 targets/minisolver/run_all.py \
--minisolver-source-dir /path/to/MiniSolver \
--solver-backend cpu \
--refresh-assetsRun all public-asset-derived MiniSolver benchmark candidates:
python3 targets/minisolver/run_case_candidates.py \
--minisolver-source-dir /path/to/MiniSolverRun all public-asset-derived acados benchmark candidates:
python3 backends/acados/run_candidates.py \
--acados-repo third_party/acadosRun the stricter acados full-SQP asset profile:
python3 backends/acados/run_candidates.py \
--acados-repo third_party/acados \
--profile sqpRun all public-asset-derived CasADi benchmark candidates:
python3 backends/casadi/run_candidates.pyRun all convex Clarabel asset candidates:
python3 backends/clarabel/run_candidates.pyRun all ALTRO robotics asset candidates:
python3 backends/altro/run_candidates.pyRefresh the same-case end-to-end solver comparison report:
python3 scripts/summarize_results.py
python3 scripts/write_asset_benchmark_report.pyRun a single asset-derived candidate:
python3 targets/minisolver/run_case_candidate.py \
--candidate case_candidates/nonlinear_mpcc_porto_following.json \
--minisolver-source-dir /path/to/MiniSolverRefresh the official compatibility report and the asset comparison report after benchmark runs:
python3 scripts/summarize_results.py
python3 scripts/write_report.py
python3 scripts/write_asset_benchmark_report.pyRun all four acados cases:
python3 backends/acados/run_all.py \
--acados-repo third_party/acadosRun all four CasADi cases:
python3 backends/casadi/run_all.py \
--acados-repo third_party/acadosThis repo also includes a tiny set of dataset-driven NMPC scenarios under scenarios/.
They use public datasets as sources of reference trajectories, while dynamics/constraints remain solver-defined.
Design notes live under docs/ (see docs/DESIGN.md).
Build the C++ runner:
cmake -S . -B build -DMINISOLVER_SOURCE_DIR=/path/to/MiniSolver
cmake --build build -j
./build/minisolver_real_scenarios --list
./build/minisolver_real_scenarios --scenario scenarios/ngsim_i80_v36/scenario.json --check-gtImport datasets (offline):
python3 tools/import_ngsim.py --vehicle-id 36 --location i-80 --start-time-ms 1113433135300 --duration-s 5.0 --N 50 --dt 0.1 --name ngsim_i80_v36 --output-root scenarios
python3 tools/import_tum_rgbd.py --url https://cvg.cit.tum.de/rgbd/dataset/freiburg1/rgbd_dataset_freiburg1_xyz-groundtruth.txt --start-time 1305031098.6659 --duration-s 6.0 --N 50 --dt 0.1 --name tum_freiburg1_xyz --output-root scenariosRegenerate ground-truth (offline):
python3 -m pip install -r tools/requirements.txt
python3 tools/generate_gt.py --scenario-root scenarios