Austin Schuh | 7400da0 | 2018-01-28 19:54:58 -0800 | [diff] [blame^] | 1 | |
| 2 | #include <ct/optcon/optcon.h> |
| 3 | #include "exampleDir.h" |
| 4 | #include "plotResultsOscillator.h" |
| 5 | |
| 6 | /*! |
| 7 | * This example shows how to use classical Direct Multiple Shooting with an oscillator system, |
| 8 | * using IPOPT as NLP solver. |
| 9 | * |
| 10 | * \example DMS.cpp |
| 11 | */ |
| 12 | int main(int argc, char **argv) |
| 13 | { |
| 14 | using namespace ct::optcon; |
| 15 | using namespace ct::core; |
| 16 | |
| 17 | const size_t state_dim = SecondOrderSystem::STATE_DIM; |
| 18 | const size_t control_dim = SecondOrderSystem::CONTROL_DIM; |
| 19 | |
| 20 | |
| 21 | /** |
| 22 | * STEP 1 : set up the optimal control problem |
| 23 | * */ |
| 24 | |
| 25 | StateVector<state_dim> x_0; |
| 26 | StateVector<state_dim> x_final; |
| 27 | |
| 28 | x_0 << 0.0, 0.0; |
| 29 | x_final << 2.0, -1.0; |
| 30 | |
| 31 | double w_n = 0.5; // oscillator frequency |
| 32 | double zeta = 0.01; // oscillator damping |
| 33 | |
| 34 | // create oscillator system |
| 35 | std::shared_ptr<SecondOrderSystem> oscillator(new SecondOrderSystem(w_n, zeta)); |
| 36 | |
| 37 | |
| 38 | // load the cost weighting matrices from file and store them in terms. Note that we only use intermediate cost |
| 39 | std::shared_ptr<ct::optcon::TermQuadratic<state_dim, control_dim>> intermediateCost( |
| 40 | new ct::optcon::TermQuadratic<state_dim, control_dim>()); |
| 41 | intermediateCost->loadConfigFile(ct::optcon::exampleDir + "/dmsCost.info", "intermediateCost", true); |
| 42 | |
| 43 | // create a cost function and add the terms to it. |
| 44 | std::shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction( |
| 45 | new CostFunctionAnalytical<state_dim, control_dim>()); |
| 46 | costFunction->addIntermediateTerm(intermediateCost); |
| 47 | |
| 48 | |
| 49 | // we include the desired terminal state as a hard constraint |
| 50 | std::shared_ptr<ct::optcon::ConstraintContainerAnalytical<state_dim, control_dim>> finalConstraints( |
| 51 | new ct::optcon::ConstraintContainerAnalytical<2, 1>()); |
| 52 | |
| 53 | std::shared_ptr<TerminalConstraint<state_dim, control_dim>> terminalConstraint( |
| 54 | new TerminalConstraint<2, 1>(x_final)); |
| 55 | terminalConstraint->setName("TerminalConstraint"); |
| 56 | finalConstraints->addTerminalConstraint(terminalConstraint, true); |
| 57 | finalConstraints->initialize(); |
| 58 | |
| 59 | |
| 60 | // define optcon problem and add constraint |
| 61 | OptConProblem<state_dim, control_dim> optConProblem(oscillator, costFunction); |
| 62 | optConProblem.setInitialState(x_0); |
| 63 | optConProblem.setGeneralConstraints(finalConstraints); |
| 64 | |
| 65 | |
| 66 | /** |
| 67 | * STEP 2 : determine solver settings |
| 68 | */ |
| 69 | DmsSettings settings; |
| 70 | settings.N_ = 25; // number of nodes |
| 71 | settings.T_ = 5.0; // final time horizon |
| 72 | settings.nThreads_ = 4; // number of threads for multi-threading |
| 73 | settings.splineType_ = DmsSettings::PIECEWISE_LINEAR; |
| 74 | settings.costEvaluationType_ = DmsSettings::FULL; // we evaluate the full cost and use no trapezoidal approximation |
| 75 | settings.objectiveType_ = DmsSettings::KEEP_TIME_AND_GRID; // don't optimize the time spacing between the nodes |
| 76 | settings.h_min_ = 0.1; // minimum admissible distance between two nodes in [sec] |
| 77 | settings.integrationType_ = DmsSettings::RK4; // type of the shot integrator |
| 78 | settings.dt_sim_ = 0.01; // forward simulation dt |
| 79 | settings.solverSettings_.solverType_ = NlpSolverSettings::SolverType::IPOPT; // use IPOPT |
| 80 | settings.absErrTol_ = 1e-8; |
| 81 | settings.relErrTol_ = 1e-8; |
| 82 | |
| 83 | settings.print(); |
| 84 | |
| 85 | |
| 86 | /** |
| 87 | * STEP 3 : Calculate an appropriate initial guess |
| 88 | */ |
| 89 | StateVectorArray<state_dim> x_initguess; |
| 90 | ControlVectorArray<control_dim> u_initguess; |
| 91 | DmsPolicy<state_dim, control_dim> initialPolicy; |
| 92 | |
| 93 | |
| 94 | x_initguess.resize(settings.N_ + 1, StateVector<state_dim>::Zero()); |
| 95 | u_initguess.resize(settings.N_ + 1, ControlVector<control_dim>::Zero()); |
| 96 | for (size_t i = 0; i < settings.N_ + 1; ++i) |
| 97 | { |
| 98 | x_initguess[i] = x_0 + (x_final - x_0) * (i / settings.N_); |
| 99 | } |
| 100 | |
| 101 | initialPolicy.xSolution_ = x_initguess; |
| 102 | initialPolicy.uSolution_ = u_initguess; |
| 103 | |
| 104 | |
| 105 | /** |
| 106 | * STEP 4: solve DMS with IPOPT |
| 107 | */ |
| 108 | |
| 109 | optConProblem.setTimeHorizon(settings.T_); |
| 110 | |
| 111 | std::shared_ptr<DmsSolver<state_dim, control_dim>> dmsSolver( |
| 112 | new DmsSolver<state_dim, control_dim>(optConProblem, settings)); |
| 113 | |
| 114 | dmsSolver->setInitialGuess(initialPolicy); |
| 115 | dmsSolver->solve(); |
| 116 | |
| 117 | // retrieve the solution |
| 118 | DmsPolicy<state_dim, control_dim> solution = dmsSolver->getSolution(); |
| 119 | |
| 120 | // let's plot the output |
| 121 | plotResultsOscillator<state_dim, control_dim>(solution.xSolution_, solution.uSolution_, solution.tSolution_); |
| 122 | } |