MPCC from ETH Zurich: path following as an optimization problem, not a tracking error
Model Predictive Contouring Controller (MPCC) for Autonomous Racing
At a glance
- What is it?
- MPCC is a C++ and Matlab implementation of the Model Predictive Contouring Controller for autonomous racing, where the vehicle is forced to follow a reference path by optimising progress along it. It ships the full control stack from a nonlinear bicycle model to a real-time QP, but the C++ side has no obstacle avoidance.
- Who is it for?
- Take MPCC if you want a readable, citable reference implementation of nonlinear contouring control and are willing to write your own solver wiring, track files and build steps from the C++ and Matlab instruction files in those folders. Leave it alone if you need out of the box obstacle avoidance in C++, or a package you can install from a registry, since neither exists here.
- Can I use it commercially?
- Yes. Apache-2.0 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?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Star history
- alexliniger/MPCC1,882 ★ · +1
| Repository | 2026-10-17 | 2026-10-24 |
|---|---|---|
| alexliniger/MPCC | 1.9k | 1.9k |
1 Stars in the last 7 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Why contouring beats tracking for a racing line
The usual path following setup penalises the distance between the vehicle and a reference line, and that framing quietly punishes the thing a racing car is trying to do. MPCC restates the objective as progress along the path.
The trick is an augmented state, theta, that approximates how far along the reference path the car has travelled. It is not a physical measurement; it is a virtual integrator added to the state vector, and it is coupled to the real dynamics through a lag error e^l that also appears in the cost. So the optimiser is free to run theta forward, but only by physically moving, and it pays a price for any mismatch between the two.
The cost then has three parts that pull in different directions. Contouring error, the lateral distance to the reference path, is penalised so the car stays on the line. The lag error is penalised so theta does not drift away from reality. And progress along the path is maximised, so the controller pushes speed rather than settling for a slow but accurate tracking solution. Rates of the inputs are penalised too, which keeps the duty cycle and steering from chattering between adjacent solutions.
That combination is what separates this from a plain model predictive controller aimed at holding a lane.
Nonlinear bicycle model with magic formula tires
The prediction model is a bicycle model with nonlinear magic formula tire models, plus a drive train model. The state is the global position X and Y, the heading phi, the longitudinal velocity v_x, the lateral velocity v_y, the yaw rate omega, and the augmented progress state theta.
The inputs are three: the duty cycle d to the drive train, the steering angle delta, and the velocity along the reference path v_theta, which the README describes as an approximation of the velocities projected onto the path.
Using a nonlinear tire model rather than a linear bicycle model is a deliberate choice for a racing application. Grip limits are the whole game on a track, and a controller that plans around a linear approximation of cornering will push past the limit in exactly the corners where the lap time is decided. The cost is that the optimisation problem is no longer a quadratic program, which the next section deals with.
The equations themselves are given as images in the README rather than as text, so a reader wanting the exact formulation goes to the linked papers.
Linearising until the problem fits inside a real-time QP
The nonlinear problem is approximated as a time-varying quadratic program through a sequence of steps: the dynamics are linearised and discretised, the lag and contouring errors are approximated with a first order Taylor expansion, and the track constraints are replaced by two linear half spaces aligned with the track boundaries.
That last approximation is the one with real consequences. A curved track boundary is not a straight line, so over a long horizon the two half spaces drift away from the true edge. It works because the horizon is re-solved every control step with fresh linearization points, but it means the constraint is only locally accurate and the tracking quality depends on how tight the iteration is.
The resulting QP is solved with hpipm in the C++ implementation. The Matlab implementation is broader: it also offers Yalmip, CVX and direct QuadProg interfaces, which is convenient for exploring the formulation but is not what you want in a control loop.
Obstacle avoidance runs ahead of the QP solve. A grid search one dimensional dynamic programming approach finds the best route around obstacles, that path is converted into a corridor, and the corridor modifies the track constraint. The optimisation itself never sees the other cars directly.
The C++ and Matlab split is not symmetric
The README is direct about one asymmetry: the C++ implementation has additional features proposed in the AMZ Driverless paper, but obstacle avoidance is currently supported only in the Matlab implementation.
That is the single most important fact for anyone choosing between the two folders. The C++ side is the one aimed at the real-time platform and it is the one missing the corridor generation step, so a C++ user chasing obstacles has to build that grid search themselves.
The repository layout is minimal: a C++ folder, a Matlab folder, an Images folder for the figures used in the README, a LICENSE and the README itself. There is no CI configuration, no package manifest at the root and no documentation site. Instructions for running either side live in the respective folders, and the README points there rather than repeating them, which means the build steps are not visible from the top level at all.
No releases, no package registry, and a licence you can build on
The repository has no GitHub releases, so there is no version to pin and no changelog to diff. You are working with whatever is on the default branch, master.
The last push was on 2026-04-25, and the repository is not archived. Treat that as the maintenance signal rather than the paper list, since several of the cited papers date from the 2015 to 2019 period while the code has continued to move.
The licence is Apache-2.0, which is the permissive choice and carries the standard patent grant and NOTICE obligations if you redistribute. Anyone embedding the controller in a larger stack, commercial or otherwise, can work with it under those terms without seeking permission. This is a note on the licence text, not legal advice.
Citations matter here more than in most code repositories. The README asks that users of either implementation cite Optimization-based autonomous racing of 1:43 scale RC cars, and that users of the C++ version additionally cite AMZ Driverless: The Full Autonomous Racing System.
Where MPCC is the wrong tool
It is a research implementation of a path following controller for a racing line, not a general purpose autonomous driving stack. There is no perception, no local planning beyond the corridor, no behaviour for traffic lights or pedestrians, and no fault handling. If your problem is following a highway lane, this is an oversized and awkward fit.
The offline comparison is randomized and stochastic MPC. The related papers listed in the README take the same MPCC problem and change the treatment of uncertainty: reformulating track constraints as chance constraints, optimizing over feedback policies with disturbance feedback, and learning model mismatch with Gaussian processes. A paper on cautious NMPC with GP dynamics reports gains when the simulation model had severe mismatch, and a later one reports a lap time reduction of 10 percent on a real Formula Student car once the GP dictionary had converged. Those are extensions, not code in this repository.
If you want a solution rather than a formulation to study, expect to supply the track representation, the solver build, the state estimation and the hardware loop yourself.
Editorial conclusion
Take MPCC if you want a readable, citable reference implementation of nonlinear contouring control and are willing to write your own solver wiring, track files and build steps from the C++ and Matlab instruction files in those folders. Leave it alone if you need out of the box obstacle avoidance in C++, or a package you can install from a registry, since neither exists here. Before adopting, read the instruction file in the folder you plan to build and confirm your linear solver can satisfy the hpipm interface, because the C++ path depends on it.
Frequently asked questions
Does the MPCC repository support obstacle avoidance in C++?
No. The README states that obstacle avoidance is currently only supported in the Matlab implementation, even though the C++ version carries other features from the AMZ Driverless paper.
Which solver does MPCC use for the C++ implementation?
The quadratic program is solved with hpipm. The Matlab version additionally offers Yalmip, CVX and direct QuadProg interfaces.
What is the theta state in the MPCC controller?
Theta is an augmented state that approximates the progress of the car along the reference path. It is coupled to the real dynamics through the lag error e^l, which is penalised in the cost function.
How do I run the MPCC code?
The README does not give run commands at the top level and instead directs readers to the individual instruction files in the C++ and Matlab folders.
Official sources
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.
[](https://hysenlabs.com/projects/alexliniger-mpcc)Star history chart for your README
[](https://hysenlabs.com/projects/alexliniger-mpcc)Was this useful?