blob: 37442cf4cc8c8a1be3f4c13e2028b84688235b0f [file] [log] [blame]
#include <ct/optcon/optcon.h>
#include "exampleDir.h"
#include "plotResultsOscillator.h"
/*!
* This example shows how to use classical Direct Multiple Shooting with an oscillator system,
* using IPOPT as NLP solver.
*
* \example DMS.cpp
*/
int main(int argc, char **argv)
{
using namespace ct::optcon;
using namespace ct::core;
const size_t state_dim = SecondOrderSystem::STATE_DIM;
const size_t control_dim = SecondOrderSystem::CONTROL_DIM;
/**
* STEP 1 : set up the optimal control problem
* */
StateVector<state_dim> x_0;
StateVector<state_dim> x_final;
x_0 << 0.0, 0.0;
x_final << 2.0, -1.0;
double w_n = 0.5; // oscillator frequency
double zeta = 0.01; // oscillator damping
// create oscillator system
std::shared_ptr<SecondOrderSystem> oscillator(new SecondOrderSystem(w_n, zeta));
// load the cost weighting matrices from file and store them in terms. Note that we only use intermediate cost
std::shared_ptr<ct::optcon::TermQuadratic<state_dim, control_dim>> intermediateCost(
new ct::optcon::TermQuadratic<state_dim, control_dim>());
intermediateCost->loadConfigFile(ct::optcon::exampleDir + "/dmsCost.info", "intermediateCost", true);
// create a cost function and add the terms to it.
std::shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction(
new CostFunctionAnalytical<state_dim, control_dim>());
costFunction->addIntermediateTerm(intermediateCost);
// we include the desired terminal state as a hard constraint
std::shared_ptr<ct::optcon::ConstraintContainerAnalytical<state_dim, control_dim>> finalConstraints(
new ct::optcon::ConstraintContainerAnalytical<2, 1>());
std::shared_ptr<TerminalConstraint<state_dim, control_dim>> terminalConstraint(
new TerminalConstraint<2, 1>(x_final));
terminalConstraint->setName("TerminalConstraint");
finalConstraints->addTerminalConstraint(terminalConstraint, true);
finalConstraints->initialize();
// define optcon problem and add constraint
OptConProblem<state_dim, control_dim> optConProblem(oscillator, costFunction);
optConProblem.setInitialState(x_0);
optConProblem.setGeneralConstraints(finalConstraints);
/**
* STEP 2 : determine solver settings
*/
DmsSettings settings;
settings.N_ = 25; // number of nodes
settings.T_ = 5.0; // final time horizon
settings.nThreads_ = 4; // number of threads for multi-threading
settings.splineType_ = DmsSettings::PIECEWISE_LINEAR;
settings.costEvaluationType_ = DmsSettings::FULL; // we evaluate the full cost and use no trapezoidal approximation
settings.objectiveType_ = DmsSettings::KEEP_TIME_AND_GRID; // don't optimize the time spacing between the nodes
settings.h_min_ = 0.1; // minimum admissible distance between two nodes in [sec]
settings.integrationType_ = DmsSettings::RK4; // type of the shot integrator
settings.dt_sim_ = 0.01; // forward simulation dt
settings.solverSettings_.solverType_ = NlpSolverSettings::SolverType::IPOPT; // use IPOPT
settings.absErrTol_ = 1e-8;
settings.relErrTol_ = 1e-8;
settings.print();
/**
* STEP 3 : Calculate an appropriate initial guess
*/
StateVectorArray<state_dim> x_initguess;
ControlVectorArray<control_dim> u_initguess;
DmsPolicy<state_dim, control_dim> initialPolicy;
x_initguess.resize(settings.N_ + 1, StateVector<state_dim>::Zero());
u_initguess.resize(settings.N_ + 1, ControlVector<control_dim>::Zero());
for (size_t i = 0; i < settings.N_ + 1; ++i)
{
x_initguess[i] = x_0 + (x_final - x_0) * (i / settings.N_);
}
initialPolicy.xSolution_ = x_initguess;
initialPolicy.uSolution_ = u_initguess;
/**
* STEP 4: solve DMS with IPOPT
*/
optConProblem.setTimeHorizon(settings.T_);
std::shared_ptr<DmsSolver<state_dim, control_dim>> dmsSolver(
new DmsSolver<state_dim, control_dim>(optConProblem, settings));
dmsSolver->setInitialGuess(initialPolicy);
dmsSolver->solve();
// retrieve the solution
DmsPolicy<state_dim, control_dim> solution = dmsSolver->getSolution();
// let's plot the output
plotResultsOscillator<state_dim, control_dim>(solution.xSolution_, solution.uSolution_, solution.tSolution_);
}