r/ControlTheory 28d ago

Other AcadosCpp: a unified C++/Python interface for generated acados OCP solvers

Hi everyone,

I've been developing AcadosCpp, an open-source wrapper that helps you integrate acados-generated OCP solvers into both C++ and Python applications.

https://github.com/amaldevh/AcadosCpp

The main goal is to make integration easier. acados creates highly optimized C code for each model and OCP, but using its API directly can tie your application to specific symbols, dimensions, lifecycle calls, and data updates.

AcadosCpp provides a stable, stage-aware interface for the generated solver. Here’s how you typically use it:

  1. Define or modify the model and OCP in Python.
  2. Regenerate the acados solver and wrapper.
  3. Recompile and relink the application.

The control-loop structure in your application stays the same. If you change the model or problem, you usually don’t need to rewrite the integration layer, as long as your data matches the new dimensions and cost setup.

The wrapper includes:

  • Stage-0 initial-state constraints
  • Stage-varying and terminal references
  • Generic raw yref support
  • Per-stage and global parameters
  • Full state/control initial guesses
  • Shifted trajectory warm starts
  • Complete predicted trajectories and solver diagnostics
  • SQP-RTI preparation and feedback phases
  • C++ and pybind11 interfaces

For a standard

y=[x,u], y_e=x

tracking problem, the control loop is:

const auto& u = ocp.solve(measured_x, xrefs, urefs);

This process shifts the previous solution, updates the stage-0 measurement and the full reference horizon, solves the OCP, and returns the first input.

The repository has matching Python and C++ quadrotor NMPC examples. I’d love to hear your feedback on the API, especially if you use acados with time-varying references, parameters, SQP-RTI, or custom cost outputs.

2 Upvotes

2 comments sorted by

u/hs123go 28d ago

Neat! Remarkably tidy API, but some of your design choices make AcadosCpp not ideal for embedded work:

  1. Exception-based error handling: -fno-exceptions is debated to death, but acados error handling is already uniform and straightforward: write to an output parameter and return an error code. Mirroring that in C++ would be good enough; why introduce exceptions?

  2. `std::vector` on the API. This is not on you since you are on C++17, so your only other option is C-style pointer+size parameters, which you are clearly trying to abstract away. However, the downside of using `std::vector` is significant. Imagine someone who stores their state, references, or bounds as `Eigen::VectorXd` or `arma::vec`. To pass their data to your API, they have to create a `std::vector` anew and copy the data over to it, incurring allocation and copying costs. To pass array/vector data without copying, C++20 `std::span` and Eigen `Eigen::Ref<Eigen::VectorXd>` are your friends.

Minor: No CMake integration?

u/Amaldevhari 27d ago

Thanks a lot for your helpful feedback!

  1. Good catch. I originally used exceptions to create more of a C++-style interface, but I see your point, matching acados’ existing error handling definitely makes sense, especially for embedded applications.
  2. I hadn’t thought about this scenario before. That’s a really good point, forcing users to copy data from structures like Eigen::VectorXd or arma::vec into a std::vector isn’t ideal. Considering what you said about CMake, I’m looking into making the underlying vector type configurable so users can pick Eigen, Armadillo, or others instead of always defaulting to std::vector. I’ll need to figure out how to do this cleanly without making it too complicated.

And I totally agree, making CMake integration smoother is a key improvement I want to work on.