PyGRAMPC is a Python interface for the GRAMPC solver build by pybind11. It features the same functionality as the Matlab interface. For questions regarding GRAMPC please refer to the grampc repository.
First you need the Eigen 3.4 Library installed on your computer. Download the library at https://eigen.tuxfamily.org/index.php?title=Main_Page and follow the installation commands in their INSTALL
file.
Clone this repository and install the package via pip. You need a suitable C++ compiler installed listed at the pybind11 project.
pip install "path to interface"
Alternatively you can install directly from git via
pip install git+https://github.com/grampc/pygrampc
This version adds compatibility for a future python interface for GRAMPC-S
. Due to these changes, existing problem definitions must be recompiled.
ProblemBase
to ProblemDescription
.grampc
namespace in C++
.Eigen::Ref<const Vector> cVectorRef
to const Eigen::Ref<const Vector>& VectorConstRef
.Please refer to the two examples inside the examples
folder.
The problem description can either be stated in C++ or Python.
In Python you can inherit from the C++ ProblemBase
class supplied by the pygrampc package.
This class redirects the C function calls to Python, so native Python code can be executed.
Please note that the Python problem description is intended for rapid prototyping.
If the full speed of GRAMPC is desired, one must write the problem description in C++
The attributes Nx, Nu, Np, Ng, Nh, NgT and NhT must be initialized during __init__()
to circumvent undefined behaviour.
Setting these values during __init__()
is equivalent to the void ocp_dim(...)
function from the C interface.
An example would be
class MyProblem(ProblemBase):
def __init__(self):
ProblemBase.__init__(self, *args)
self.Nx = 2
self.Nu = 1
self.Np = 0
self.Ng = 0
self.Nh = 0
self.NgT = 2
self.NhT = 0
...
When writing your problem description in Python, only __init__()
, ffct()
and dfdx_vec()
are mandatory to implement.
If you are unsure about the function arguments, please refer to MyProblem.py
.
All function arguments are numpy arrays. The output of the functions need to be written at the allocated memory of out
.
To set the output data of your function do write to the preallocated memory inside the out array with
out[0] = ...
out[:] = ...
statements like
out = out * 2
do not work because Python creates a new variable out
which doesn't points to the allocated memory from GRAMPC
Because the arguments are numpy arrays, one should use numpy methods for calculation. Here is an example for computing the integral cost term:
def lfct(self, out, t, x, u, p, xdes, udes):
out[0] = np.dot(self.Q, np.power(x - xdes, 2)) + np.dot(self.R, np.power(u - udes, 2))
Debugging the Python problem description is very simple, just put in a breakpoint inside the function of interest and start the Python debugger.
If extra speed is desired, the Python interface can be used with a compiled problem description. Inside the template folder there is a C++ template with a CMakeLists.txt file for compilation. As in the Python interface, you only have to override the functions you need.
Using the C++ problem description can result in a 100 times speedup per time step.
For an example, please refer to the Crane2D
example.
To invoke the compilation process please install scikit-build-core
and pybind11
via pip.
Then run build_problem.py
inside the Crane2D
folder.
There exists both a Python and C++ problem description, which showcases the achieved speedup.
Debugging the C++ is more complicated than Python debugging. First, the toolbox needs to be compiled with Debug symbols. This can be achieved with
pip install "path to interface" --config-settings=cmake.build-type="DEBUG"
Then compile your C++ problem description in debug mode and use a suitable debugger.
Using the Python C++ Debugger
extensions for VS Code is a reliable way to debug Python and C++ code.
If you are using GRAMPC in your work, please cite
@Article{,
author = {Englert, Tobias and Völz, Andreas and Mesmer, Felix and Rhein, Sönke and Graichen, Knut},
title = {A software framework for embedded nonlinear model predictive control using a gradient-based augmented Lagrangian approach (GRAMPC)},
doi = {10.1007/s11081-018-9417-2},
issn = {1573-2924},
number = {3},
pages = {769--809},
url = {https://doi.org/10.1007/s11081-018-9417-2},
volume = {20},
journal = {Optimization and Engineering},
refid = {Englert2019},
year = {2019},
}