Open-source project
mcarfagno/mpc_python avatar
mcarfagno/mpc_python

mpc_python: an iterative model predictive controller you can read end to end

A simple MPC controller for path tracking implemented in python

544 stars88 forksJupyter NotebookMIT

At a glance

What is it?
mpc_python is a small Python implementation of an iterative model predictive control path tracking controller built on CVXPY and paired with MuJoCo, with configuration in YAML, a headless demo that needs no physics and a set of notebooks that derive the model before the controller is introduced. It is MIT licensed and the primary language of the repository is Jupyter Notebook.
Who is it for?
Adopt mpc_python if you are moving from basic control to real-time convex optimisation and want a controller you can read line by line, with the model derivation shown before the control law. Skip it if you need production vehicle control, since this is a teaching and research codebase rather than a hardened component, and skip it if you need a non-convex formulation that a general purpose solver handles better.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 128 days ago.
What is it written in?
Mainly Jupyter Notebook, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The stated goal is a bridge from basic control to real-time convex optimisation

mpc_python is described as a hopefully easy-to-follow iterative MPC tracking controller built with CVXPY and paired with MuJoCo, and the purpose is stated as helping anyone looking to transition from basic control to real-time convex optimisation. That framing explains the size of the project, since a teaching implementation is judged by how much a reader can learn from it rather than by how fast it runs. The technical commitment is the use of CVXPY to maintain a strict quadratic programming framework rather than relying on a non-linear solver such as CasADi, and the author is explicit that the linear solver is a deliberate choice rather than a limitation of ambition. The way the gap to non-linear physics is closed is the interesting part of the design, because implementing an iterative MPC still lets you handle non-linear kinematics through iterative linearisation, so the optimisation stays convex while the model it is applied to is refined around the current operating point. The repository is MIT licensed, its primary language is recorded as Jupyter Notebook, and the last push was on 2026-06-17 with the repository not archived and no GitHub releases, so it is an actively touched project without a release stream.

Two demos, because the physics is not the point

The demonstration section shows six recordings, arranged as three pairs, and the pairing is the useful information. Each pair covers the same scenario twice, once as a MuJoCo simulation with the mushr car model and once as a headless toy demo with a dummy car. The three scenarios are with no obstacles, with static obstacle avoidance and with moving obstacle avoidance. So the project ships a full physics simulation path and a stripped down path, and the second one exists so that a reader can watch the controller behave without installing a physics engine or worrying about solver performance. That is a good instinct for a teaching project, since the interesting behaviour is the optimiser working, not the vehicle dynamics. The MuJoCo demos run against the mushr car model, which comes from the prl-mushr project, and the README notes that the repository builds on code and ideas from other open source projects with a special thanks section, listing the MPC papers and course notes from Prof. Borrelli, pythonrobotics by Atsushi Sakai, MPCC by alexliniger with the associated paper, the rocket-lander project by arex18, and the mushr project for the vehicle used. The static and moving obstacle work is described in the notebooks as halfplane constraints used to avoid track collisions.

The codebase is small and the configuration file is the entry point

The README gives a brief overview of the codebase, and the structure says a lot about the priorities. There is a config/ directory holding mpc.yaml, which the comment marks as the configuration of the MPC and the place to start, and simulation.yaml with the common configuration of the demos. Then the package itself, with a cvxpy_mpc/ subdirectory holding the main implementation and a utils module, a models/ directory containing the mushr model, and two entry points at the top level, mpc_demo_mujoco.py for the MuJoCo demo and mpc_demo_nosim.py for the demo with no physics simulation. The separation of a single implementation file from the demos is the detail that makes the project usable, since the controller can be read without the simulation in the way, and the YAML configuration means the controller's tuning is not buried in Python. The primary language being recorded as Jupyter Notebook is a further signal about intent, since the notebooks are not an afterthought here but the main teaching text for the project.

Running the demos through Nix or Conda

There are two supported ways to run the examples, and the Nix route is the shortest. A Nix flake is provided for a reproducible development shell, and the two examples are run with a pair of commands.

bash
nix run --impure .#mujoco-demo
nix run .#nosim-demo

Entering the development shell is the heavier option, and the README says so, noting that it also includes jupyter lab to experiment with the notebooks.

bash
nix develop --impure

The GUI demos need a graphics stack, and the README points at nixGL, which auto-detects Intel, AMD and NVIDIA GPUs.

bash
nixGL python mpc_python/mpc_demo_mujoco.py

The headless demo runs without it.

bash
python mpc_python/mpc_demo_nosim.py

The Conda route is the conventional alternative, creating an environment from the file and activating it under the name simulation.

bash
conda env create -f env.yml
conda activate simulation

And then the same two scripts run directly.

bash
python3 mpc_demo_mujoco.py
python3 mpc_demo_nosim.py

The notebooks derive the model before the controller

The notebooks section is organised into three groups, and the ordering is the pedagogical argument. The first is model derivation, with analytical and numerical derivation across four notebooks covering the linearised system modelling, parametrised path curves, a differential model and a motion model. The second is the MPC itself, implementation and testing of various tweaks, with four notebooks covering the base controller, the version with iterative linearisation, a variant that works in a car reference frame, and a simplified one. The third is obstacle avoidance, with halfplane constraints to avoid track collisions, spread over a base notebook and a better track one, and this group is still marked as work in progress. The sequence matters for anyone planning to learn from it, because the linearised model that the convex program optimises over is derived in the first group and the iterative refinement that handles non-linear kinematics is introduced in the second. The repository also keeps the original notebooks on model predictive control for path-following problems for historical context, and the README flags those as a bit outdated, which is a small but useful warning.

The dependency set is where the solver choice shows

The package metadata is short and readable. The project is mpc-python at version 0.1.0, requires Python 3.11 or newer, and depends on numpy below version 2, matplotlib, mujoco, cvxpy, scipy, osqp, sympy and pyyaml. Two of those carry most of the meaning. The numpy ceiling of less than 2 is the kind of pin that tells you the code was written against a specific array API, and it is the sort of constraint that a reader will hit if they try to install into a modern environment without reading the pin. OSQP is the actual solver, an operator splitting method for quadratic programs, which is what makes the convex optimisation cheap enough to run inside a control loop, and sympy is there for the symbolic derivation in the notebooks. The optional extras are the notebook group, with jupyterlab, ipython, ipywidgets and nbformat and nbconvert, and a dev group with black and ruff. The build backend is setuptools, and the packages are found from the project root. The whole stack is a well known one, and the constraint is that the pieces are pinned to a configuration that was validated together.

Where mpc_python is the wrong choice

The first limit is that this is a teaching implementation. The phrase hopefully easy-to-follow is a signal about what the project optimises for, and a controller that is easy to read is not the same as a controller that holds up when the distribution shifts, a sensor fault or a solver that fails to converge inside your control period. The iterative linearisation scheme has a known failure mode, since the refinement is only valid near the linearisation point, and a vehicle far from the operating point the model was linearised around can produce a plan that is optimal for the wrong model. The second is the obstacle avoidance, which is the newest part and the one the README still marks as work in progress, so a reader who needs collision avoidance is building on the least settled code. The third is the scope of the vehicle, since the model is the mushr car and the toy demo is a dummy car, so the parameters and the kinematic assumptions are specific and the configuration file is where the transferability lives. The fourth is the solver, and sticking to CVXPY and a convex formulation is a deliberate choice with a cost, since problems that need a genuinely non-convex formulation are out of reach here even though the author notes the appeal of a non-linear solver. And the fifth is the absence of a release stream, with a version of 0.1.0, no GitHub releases and a primary language recorded as Jupyter Notebook, so the code is a set of notebooks and scripts you read and copy rather than a package you depend on.

Editorial conclusion

Adopt mpc_python if you are moving from basic control to real-time convex optimisation and want a controller you can read line by line, with the model derivation shown before the control law. Skip it if you need production vehicle control, since this is a teaching and research codebase rather than a hardened component, and skip it if you need a non-convex formulation that a general purpose solver handles better. Verify first that your Python is 3.11 or newer, that the linearised model and its iterative refinement suit your vehicle, and that you read the obstacle avoidance notebooks, which the README still marks as work in progress.

Frequently asked questions

What is mpc_python and what is it for?

It is a simple model predictive control path tracking controller implemented in Python, using CVXPY to keep the optimisation in a strict quadratic programming framework and paired with MuJoCo for simulation. The stated purpose is to help anyone transitioning from basic control to real-time convex optimisation, with non-linear kinematics handled through iterative linearisation.

How do I run the mpc_python demos?

Through the Nix flake you can run nix run --impure .#mujoco-demo and nix run .#nosim-demo, and nix develop --impure gives a shell that also includes jupyter lab. The Conda route is conda env create -f env.yml followed by conda activate simulation. The GUI demo needs nixGL, while the headless demo runs with plain python.

What do the mpc_python notebooks cover?

They are grouped as model derivation, with analytical and numerical derivation of the linearised system, parametrised path curves, a differential model and a motion model, then the MPC implementation and testing across the base controller, iterative linearisation, a car reference frame variant and a simplified version, and finally obstacle avoidance using halfplane constraints, which the README still marks as work in progress.

Official sources

  1. Issues
  2. License: MIT
  3. mcarfagno/mpc_python on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mcarfagno-mpc-python.svg)](https://hysenlabs.com/projects/mcarfagno-mpc-python)

Was this useful?