Skip to content

Commit

Permalink
Merge branch 'pybind' into 'master'
Browse files Browse the repository at this point in the history
Pybind11 and minor fixes (version 0.5.0)

See merge request altairLab/optcontrol/libmpc!43
  • Loading branch information
nicolapiccinelli committed May 17, 2024
2 parents 64b3fda + 36c8da5 commit cb1c33b
Show file tree
Hide file tree
Showing 41 changed files with 752 additions and 230 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ build/
bin/
lib/
web/
examples/build/
python/build/
docs/source/_build
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "python/deps/pybind11"]
path = python/deps/pybind11
url = https://github.com/pybind/pybind11
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## [0.5.0] - 2024-05-17
### Added
- Python bindings for the library using pybind11 (pympcxx)
- The result struct now contains a string to describe the status of the optimization problem
- Added new parameters for the nonlinear mpc (time_limit, absolute_ftol, absolute_xtol)

### Changed
- Breaking change: some of the APIs have been refactored. New APIs: setDiscretizationSamplingTime, setExogenousInputs, optimize
substitute setContinuosTimeModel, setExogenuosInputs, step
- Improved error handling in the NLopt interface

### Fixed
- The set of the discretization sampling time was not working properly in the non-linear mpc

## [0.4.2] - 2024-01-14
### Added
- Added examples to show how to use the library
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 20)
set(LIBMPCC_VERSION 0.4.2)
set(LIBMPCC_VERSION 0.5.0)

## Specify a project name
project(mpc++ VERSION ${LIBMPCC_VERSION} LANGUAGES CXX)
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ is tested to work on Linux, macOS and Windows.

The libmpc++ website can be found at the following link: https://altairlab.gitlab.io/optcontrol/libmpc/

Starting from the version **0.5.0** the library is also available as a Python package (https://pypi.org/project/pympcxx/). The Python package is available on PyPI and can be installed using pip:
```
pip install pympcxx
```

## Dependecies
The library depends on the following external libraries which must be installed on the machine before using libmpc++

Expand Down
2 changes: 1 addition & 1 deletion docs/source/introduction/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ written in standard C++20 and provides static and dynamic memory allocation via
Linux, MacOs and Windows and comes with a limited set of dependecies. It provides:

* Support for linear and non-linear MPC optimal control problem formulation
* Handles discrete-time and continuos-time (for the non-linear MPC only) system's dynamics definition
* Handles discrete-time and continuous-time (for the non-linear MPC only) system's dynamics definition
* Different length for the prediction and control horizon
* Automatic Jacobian approximation for non-linear MPC
* Header-only implementation
Expand Down
8 changes: 6 additions & 2 deletions docs/source/manual/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The underlying non-linear system used within the MPC is defined as
y_k &= g(x_k, u_k)
\end{align}
in case of continuos time system the function :math:`\dot x = f(x, u)` should be interpreted as the vector field of the desired dynamical system.
in case of continuous time system the function :math:`\dot x = f(x, u)` should be interpreted as the vector field of the desired dynamical system.
The dynamical system is transformed into discrete-time using the zero-order hold (ZOH) approximation method internally.

Tutorial
Expand Down Expand Up @@ -108,6 +108,10 @@ Non-linear MPC solver (nlopt)

params.relative_ftol = 1e-10;
params.relative_xtol = 1e-10;
params.absolute_ftol = 1e-10;
params.absolute_xtol = 1e-10;
params.time_limit = 0;

params.hard_constraints = true;

nlmpc.setOptimizerParameters(params);
Expand Down Expand Up @@ -230,7 +234,7 @@ This example shows how to drives the states of a Van der Pol oscillator to zero
double ts = 0.1;

nlmpc.setLoggerLevel(mpc::Logger::log_level::NORMAL);
nlmpc.setContinuosTimeModel(ts);
nlmpc.setDiscretizationSamplingTime(ts);

auto stateEq = [&](mpc::cvec<Tnx>& dx,
const mpc::cvec<Tnx>& x,
Expand Down
4 changes: 2 additions & 2 deletions examples/quadrotor_ex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ int main()
params.maximum_iteration = 250;
controller.setOptimizerParameters(params);

controller.setExogenuosInputs(mpc::mat<Tndu, Tph>::Zero());
controller.setExogenuosInputs(mpc::cvec<Tndu>::Zero(), {0, Tph});
controller.setExogenousInputs(mpc::mat<Tndu, Tph>::Zero());
controller.setExogenousInputs(mpc::cvec<Tndu>::Zero(), {0, Tph});

auto res = controller.step(mpc::cvec<Tnx>::Zero(), mpc::cvec<Tnu>::Zero());
auto seq = controller.getOptimalSequence();
Expand Down
4 changes: 2 additions & 2 deletions examples/ugv_ex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ int main()
double Ts = 0.01;

mpc::NLMPC<Tnx, Tnu, Tny, Tph, Tch, Tineq, Teq> controller;
controller.setContinuosTimeModel(Ts);
controller.setDiscretizationSamplingTime(Ts);
controller.setLoggerLevel(mpc::Logger::log_level::NORMAL);

mpc::mat<Tnx, Tnx> A(Tnx, Tnx);
Expand Down Expand Up @@ -136,7 +136,7 @@ int main()
while(true)
{
// solve
res = controller.step(m_x, res.cmd);
res = controller.optimize(m_x, res.cmd);

// apply vector field
stateEq(m_dx, m_x, res.cmd, -1);
Expand Down
4 changes: 2 additions & 2 deletions examples/vanderpol_ex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ int main()
controller;

controller.setLoggerLevel(mpc::Logger::log_level::NORMAL);
controller.setContinuosTimeModel(ts);
controller.setDiscretizationSamplingTime(ts);

auto stateEq = [&](
mpc::cvec<num_states> &dx,
Expand Down Expand Up @@ -70,7 +70,7 @@ int main()

for (;;)
{
r = controller.step(modelX, r.cmd);
r = controller.optimize(modelX, r.cmd);
stateEq(modeldX, modelX, r.cmd);
modelX += modeldX * ts;
if (std::fabs(modelX[0]) <= 1e-2 && std::fabs(modelX[1]) <= 1e-1)
Expand Down
2 changes: 1 addition & 1 deletion include/mpc/IComponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace mpc
* method ensures the correct problem dimensions assigment has been
* already performed
*/
virtual void onInit() = 0;
virtual void onInit() override = 0;

/**
* @brief Check if the object has been correctly initialized. In case
Expand Down
27 changes: 14 additions & 13 deletions include/mpc/IMPC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace mpc
* @return true
* @return false
*/
virtual bool setContinuosTimeModel(const double) = 0;
virtual bool setDiscretizationSamplingTime(const double) = 0;
/**
* @brief Set the scaling factor for the control input. This can be used to normalize
* the control input with respect to the different measurment units
Expand All @@ -60,17 +60,6 @@ namespace mpc
*/
virtual void setOptimizerParameters(const Parameters &) = 0;

/**
* @brief Implements the initilization hook to provide shared initilization logic
* and forwards the hook through the setup hook for linear and non-linear interface
* specific initilization
*/
void onInit()
{
profiler.reset();
onSetup();
};

/**
* @brief Set the logger level
*
Expand Down Expand Up @@ -104,7 +93,7 @@ namespace mpc
* @param lastU last optimal control action
* @return Result<Tnu> optimization result
*/
Result<sizer.nu> step(const cvec<sizer.nx> x0, const cvec<sizer.nu> lastU)
Result<sizer.nu> optimize(const cvec<sizer.nx> x0, const cvec<sizer.nu> lastU)
{
onModelUpdate(x0);

Expand Down Expand Up @@ -173,10 +162,22 @@ namespace mpc
}

protected:
/**
* @brief Implements the initilization hook to provide shared initilization logic
* and forwards the hook through the setup hook for linear and non-linear interface
* specific initilization
*/
void onInit() override
{
profiler.reset();
onSetup();
};

/**
* @brief Initilization hook for the linear and non-linear interfaces
*/
virtual void onSetup() = 0;

/**
* @brief Dynamical system initial condition update hook
*/
Expand Down
2 changes: 1 addition & 1 deletion include/mpc/IOptimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace mpc
* method ensures the correct problem dimensions assigment has been
* already performed
*/
virtual void onInit() = 0;
virtual void onInit() override = 0;
/**
* @brief Abstract setter for the optimizer parameters
*
Expand Down
34 changes: 17 additions & 17 deletions include/mpc/LMPC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace mpc
using IDimensionable<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::eq;

public:
using IMPC<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::step;
using IMPC<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::optimize;
using IMPC<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::setLoggerLevel;
using IMPC<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::setLoggerPrefix;
using IMPC<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>::getLastResult;
Expand All @@ -62,7 +62,7 @@ namespace mpc
/**
* @brief (NOT AVAILABLE) Set the discretization time step to use for numerical integration
*/
bool setContinuosTimeModel(const double /*ts*/)
bool setDiscretizationSamplingTime(const double /*ts*/) override
{
throw std::runtime_error("Linear MPC supports only discrete time systems");
return false;
Expand All @@ -73,7 +73,7 @@ namespace mpc
*
* @param param desired parameters (the structure must be of type LParameters)
*/
void setOptimizerParameters(const Parameters &param)
void setOptimizerParameters(const Parameters &param) override
{
((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setParameters(param);
}
Expand All @@ -82,7 +82,7 @@ namespace mpc
* @brief (NOT AVAILABLE) Set the scaling factor for the control input
*
*/
void setInputScale(const cvec<Tnu> /*scaling*/)
void setInputScale(const cvec<Tnu> /*scaling*/) override
{
throw std::runtime_error("Linear MPC does not support input scaling");
}
Expand All @@ -91,7 +91,7 @@ namespace mpc
* @brief (NOT AVAILABLE) Set the scaling factor for the dynamical system's states variables
*
*/
void setStateScale(const cvec<Tnx> /*scaling*/)
void setStateScale(const cvec<Tnx> /*scaling*/) override
{
throw std::runtime_error("Linear MPC does not support state scaling");
}
Expand Down Expand Up @@ -438,33 +438,33 @@ namespace mpc
{

Logger::instance().log(Logger::log_type::DETAIL) << "Setting disturbances matrices" << std::endl;
return builder.setExogenuosInput(Bd, Dd);
return builder.setExogenousInput(Bd, Dd);
}

/**
* @brief Set the exogenuos inputs vector
* @brief Set the exogenous inputs vector
*
* @param uMeas measured exogenuos input
* @param uMeas measured exogenous input
* @return true
* @return false
*/
bool setExogenuosInputs(
bool setExogenousInputs(
const mat<Tndu, Tph> &uMeasMat)
{
return ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenuosInputs(uMeasMat);
return ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenousInputs(uMeasMat);
}

/**
* @brief Set the exogenuos inputs vector, the exogenuos inputs are assumed to be constant
* @brief Set the exogenous inputs vector, the exogenous inputs are assumed to be constant
* along the specified prediction horizon segment
*
* @param uMeas measured exogenuos input
* @param uMeas measured exogenous input
* @param slice slice of the prediction horizon [start end]
* (if both ends re set to -1 the whole prediction horizon is used)
* @return true
* @return false
*/
bool setExogenuosInputs(
bool setExogenousInputs(
const cvec<Tndu> &uMeas,
const std::array<int, 2> slice)
{
Expand All @@ -480,7 +480,7 @@ namespace mpc
uMeasMat.col(i) = uMeas;
}

return ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenuosInputs(uMeasMat);
return ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenousInputs(uMeasMat);
}

// Replicate on segment of the prediction horizon
Expand All @@ -498,7 +498,7 @@ namespace mpc

for (size_t i = start; i < end; i++)
{
ret = ret && ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenuosInputs(i, uMeas);
ret = ret && ((LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)> *)optPtr)->setExogenousInputs(i, uMeas);
}

return ret;
Expand Down Expand Up @@ -650,7 +650,7 @@ namespace mpc
/**
* @brief Initilization hook for the linear interface
*/
void onSetup()
void onSetup() override
{
builder.initialize(nx(), nu(), ndu(), ny(), ph(), ch());
optPtr = new LOptimizer<MPCSize(Tnx, Tnu, Tndu, Tny, Tph, Tch, 0, 0)>();
Expand All @@ -668,7 +668,7 @@ namespace mpc
*
* @warning This function is not available for use.
*/
void onModelUpdate(const cvec<Tnx> /*x0*/)
void onModelUpdate(const cvec<Tnx> /*x0*/) override
{
}

Expand Down
18 changes: 9 additions & 9 deletions include/mpc/LMPC/LOptimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace mpc
* method ensures the correct problem dimensions assigment has been
* already performed
*/
void onInit()
void onInit() override
{
result.cmd.resize(nu());
result.cmd.setZero();
Expand Down Expand Up @@ -97,7 +97,7 @@ namespace mpc
*
* @param param parameters desired
*/
void setParameters(const Parameters &param)
void setParameters(const Parameters &param) override
{
checkOrQuit();
lin_params = *dynamic_cast<LParameters *>(const_cast<Parameters *>(&param));
Expand Down Expand Up @@ -152,27 +152,27 @@ namespace mpc
}

/**
* @brief Set the exogenuos inputs matrix
* @brief Set the exogenous inputs matrix
*
* @param uMeas measured exogenuos input
* @param uMeas measured exogenous input
* @return true
* @return false
*/
bool setExogenuosInputs(const mat<sizer.ndu, sizer.ph> &uMeas)
bool setExogenousInputs(const mat<sizer.ndu, sizer.ph> &uMeas)
{
extInputMeas = uMeas;
return true;
}

/**
* @brief Set the exogenuos inputs vector for a specific horizon step
* @brief Set the exogenous inputs vector for a specific horizon step
*
* @param index index of the horizon step
* @param uMeas measured exogenuos input
* @param uMeas measured exogenous input
* @return true
* @return false
*/
bool setExogenuosInputs(
bool setExogenousInputs(
const unsigned int index,
const cvec<sizer.ndu> &uMeas)
{
Expand All @@ -188,7 +188,7 @@ namespace mpc
*/
void run(
const cvec<sizer.nx> &x0,
const cvec<sizer.nu> &u0)
const cvec<sizer.nu> &u0) override
{
checkOrQuit();
Result<sizer.nu> r;
Expand Down
Loading

0 comments on commit cb1c33b

Please sign in to comment.