- 3.0.2 optimal control module.
NLOC_MPCTest.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4  **********************************************************************************************************************/
5 
6 //#define DEBUG_PRINT_MPC
7 //#define MATLAB_LOG_MPC
8 
9 #pragma once
10 
11 #include <chrono>
12 #include <gtest/gtest.h>
13 
14 #include "mpcTestSettings.h"
15 #include "../testSystems/LinearOscillator.h"
16 
17 namespace ct {
18 namespace optcon {
19 namespace example {
20 
21 using namespace ct::core;
22 using namespace ct::optcon;
23 
24 using std::shared_ptr;
25 
26 
30 TEST(MPCTestA, ForwardIntegratorTest)
31 {
34 
35  try
36  {
37  // desired final state
38  Eigen::Matrix<double, state_dim, 1> x_final;
39  x_final << 20, 0;
40 
42  x0.setRandom(); // initial state
43  double timeHorizon = 3.0; // final time
44 
45  // set up the Optimal Control Problem
46  shared_ptr<ControlledSystem<state_dim, control_dim>> system(new LinearOscillator);
47  shared_ptr<LinearSystem<state_dim, control_dim>> analyticLinearSystem(new LinearOscillatorLinear);
48  shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction =
49  tpl::createCostFunctionLinearOscillator<double>(x_final);
50 
51  ContinuousOptConProblem<state_dim, control_dim> optConProblem(system, costFunction, analyticLinearSystem);
52  optConProblem.setInitialState(x0);
53  optConProblem.setTimeHorizon(timeHorizon);
54 
55  // FIRST ILQR INSTANCE FOR CALCULATING THE 'PERFECT' INITIAL GUESS
56  NLOptConSettings nloc_settings;
57  nloc_settings.dt = 0.001;
58  nloc_settings.K_sim = 1;
59  nloc_settings.max_iterations = 100;
60  nloc_settings.integrator = ct::core::IntegrationType::EULER;
61  nloc_settings.discretization = NLOptConSettings::APPROXIMATION::FORWARD_EULER;
62  nloc_settings.nlocp_algorithm = NLOptConSettings::NLOCP_ALGORITHM::ILQR;
63  nloc_settings.lqocp_solver = NLOptConSettings::LQOCP_SOLVER::GNRICCATI_SOLVER;
64  nloc_settings.printSummary = false;
65 
66  // number of steps
67  size_t K = nloc_settings.computeK(timeHorizon);
68 
69  // initial controller
72  StateVectorArray<state_dim> x_ref(K + 1, x0);
73  ct::core::StateFeedbackController<state_dim, control_dim> initController(x_ref, u0_ff, u0_fb, nloc_settings.dt);
74 
75  NLOptConSolver<state_dim, control_dim> initSolver(optConProblem, nloc_settings);
76  initSolver.configure(nloc_settings);
77  initSolver.setInitialGuess(initController);
78  initSolver.solve();
79 
80  // obtain the 'perfect' init controller from first iLQR solver
82  auto perfectStateTrajectory = initSolver.getStateTrajectory();
83 
84  // mpc settings
85  ct::optcon::mpc_settings settings_mpc;
86  settings_mpc.stateForwardIntegration_ = true;
87  settings_mpc.stateForwardIntegratorType_ = nloc_settings.integrator;
88  settings_mpc.stateForwardIntegration_dt_ = nloc_settings.dt;
89  settings_mpc.postTruncation_ = false;
90 
91  // MPC instance
92  MPC<NLOptConSolver<state_dim, control_dim>> mpcSolver(optConProblem, nloc_settings, settings_mpc);
93 
94  // initialize it with perfect initial guess
95  mpcSolver.setInitialGuess(perfectInitController);
96 
97  ct::core::Time t = 0.0; // init time
98 
99 
101  ct::core::Time ts_newPolicy;
102 
103 
108  mpcSolver.prepareIteration(t);
109  mpcSolver.finishIteration(x0, t, newPolicy, ts_newPolicy);
110  auto mpcStateTrajectory = newPolicy.getReferenceStateTrajectory();
111 
112  ASSERT_EQ(newPolicy.uff().size(), perfectInitController.uff().size());
113  ASSERT_EQ(newPolicy.getFeedforwardTrajectory().duration(),
114  perfectInitController.getFeedforwardTrajectory().duration());
115 
116  for (size_t i = 0; i < mpcStateTrajectory.size(); i++)
117  {
118  ASSERT_NEAR(mpcStateTrajectory[i](0), perfectStateTrajectory[i](0), 1e-6); // positions
119  ASSERT_NEAR(mpcStateTrajectory[i](1), perfectStateTrajectory[i](1), 1e-6); // velocities
120  }
121 
122 
133  std::shared_ptr<ct::core::StateFeedbackController<state_dim, control_dim>> prevController(
135  double time_window = 0.2;
136  for (size_t i = 0; i < mpcStateTrajectory.size() - static_cast<size_t>(nloc_settings.computeK(time_window));
137  i++)
138  {
139  double t_forward_start = i * nloc_settings.dt;
140  double t_forward_stop = t_forward_start + time_window;
141 
142  mpcStateTrajectory.setInterpolationType(ct::core::InterpolationType::LIN);
143  ct::core::StateVector<state_dim> start_state = mpcStateTrajectory.eval(t_forward_start);
144  ct::core::StateVector<state_dim> ref_end_state = mpcStateTrajectory.eval(t_forward_stop);
145  mpcSolver.doForwardIntegration(t_forward_start, t_forward_stop, start_state, prevController);
146 
147  // temporarily commented out, as hard to guarantee this condition is met
148  // ASSERT_LT((start_state-ref_end_state).array().abs().maxCoeff(), 1e-1);
149  }
150 
151  } catch (std::exception& e)
152  {
153  std::cout << "caught exception: " << e.what() << std::endl;
154  FAIL();
155  }
156 }
157 
158 
159 TEST(MPCTestB, NLOC_MPC_DoublePrecision)
160 {
163 
164  for (int solverType = 0; solverType <= 0; solverType++)
165 
166  try
167  {
168  Eigen::Vector2d x_final;
169  x_final << 20, 0;
170 
172  x0.setRandom();
173 
175 
176  // set up the Optimal Control Problem
177  shared_ptr<ControlledSystem<state_dim, control_dim>> system(new LinearOscillator);
178  shared_ptr<LinearSystem<state_dim, control_dim>> analyticLinearSystem(new LinearOscillatorLinear);
179  shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction =
180  tpl::createCostFunctionLinearOscillator<double>(x_final);
181 
182  ContinuousOptConProblem<state_dim, control_dim> optConProblem(system, costFunction, analyticLinearSystem);
183  optConProblem.setTimeHorizon(timeHorizon);
184  optConProblem.setInitialState(x0);
185 
186 
187  // FIRST ILQR INSTANCE FOR CALCULATING THE 'PERFECT' INITIAL GUESS
188 
189  NLOptConSettings nloc_settings;
190  nloc_settings.dt = 0.01;
191  nloc_settings.K_sim = 1;
192  nloc_settings.K_shot = 1;
193  nloc_settings.max_iterations = 10;
194  nloc_settings.min_cost_improvement = 1e-10; // strict bounds to reach a solution very close to optimality
195  nloc_settings.discretization = NLOptConSettings::APPROXIMATION::FORWARD_EULER;
196  nloc_settings.lqocp_solver = NLOptConSettings::LQOCP_SOLVER::GNRICCATI_SOLVER;
197  nloc_settings.integrator = ct::core::IntegrationType::EULER;
198  nloc_settings.lineSearchSettings.type = LineSearchSettings::TYPE::SIMPLE;
199  nloc_settings.nThreads = 1;
200  nloc_settings.nThreadsEigen = 1;
201  nloc_settings.printSummary = false;
202  nloc_settings.debugPrint = false;
203 
204 
205  if (solverType == 0)
206  nloc_settings.nlocp_algorithm = NLOptConSettings::NLOCP_ALGORITHM::ILQR;
207  else
208  nloc_settings.nlocp_algorithm = NLOptConSettings::NLOCP_ALGORITHM::GNMS;
209 
210 
211  int K = nloc_settings.computeK(timeHorizon); // number of steps
212 
213 
214  // provide initial controller
217  StateVectorArray<state_dim> x_ref(K + 1, x0);
219  x_ref, u0_ff, u0_fb, nloc_settings.dt);
220 
221 
222  // solve iLQR and obtain perfect init guess
223  NLOptConSolver<state_dim, control_dim> initSolver(optConProblem, nloc_settings);
224  initSolver.configure(nloc_settings);
225  initSolver.setInitialGuess(initController);
226  initSolver.solve();
227 
228  ct::core::StateFeedbackController<state_dim, control_dim> perfectInitController = initSolver.getSolution();
229  ct::core::StateTrajectory<state_dim> perfectStateTrajectory =
230  perfectInitController.getReferenceStateTrajectory();
231 
232  // settings for the ilqr instance used in MPC
233  NLOptConSettings nloc_settings_mpc = nloc_settings;
234  nloc_settings_mpc.max_iterations = 1;
235 
236  // mpc specific settings
237  ct::optcon::mpc_settings settings;
238  settings.stateForwardIntegration_ = true;
239  settings.stateForwardIntegratorType_ = nloc_settings.integrator;
240  settings.stateForwardIntegration_dt_ = nloc_settings.dt;
241  settings.postTruncation_ = false;
242  settings.measureDelay_ = false;
243  settings.fixedDelayUs_ = 100000; //
244  settings.delayMeasurementMultiplier_ = 1.0;
246  settings.coldStart_ = false;
247  settings.additionalDelayUs_ = 0;
248  settings.useExternalTiming_ = true;
249 
250 
251  // Create MPC object
252  MPC<NLOptConSolver<state_dim, control_dim>> mpcSolver(optConProblem, nloc_settings_mpc, settings);
253 
254  mpcSolver.setInitialGuess(perfectInitController);
255 
256  // outputs
257  std::vector<ct::core::StateTrajectory<state_dim>>
258  stateTrajContainer; // collection of all state trajectories
260  std::vector<double> timeStamps; // collection of all policy-start timestamps
261  std::vector<ct::core::StateVector<state_dim>> initStates; // collection of all initial tests
262 
263  int maxNumRuns = 2000;
264  int numRuns = 0;
265 
266 
267  // timestamp of the new optimal policy
268  ct::core::Time ts_newPolicy = 0.0;
269 
270  mpcSolver.prepareIteration(0.0);
271 
272 
273  for (int i = 0; i < maxNumRuns; i++)
274  {
275  // we assume to have a perfect initial state (perfect state evolution)
276  if (i == 1)
277  x0 = tempStateTraj.eval(1e-6 * settings.fixedDelayUs_);
278  else if (i > 0)
279  x0 = tempStateTraj.front();
280 
281  // (fake) time which has passed since start of MPC
282  double t = i * 1e-6 * settings.fixedDelayUs_;
283 
284  // new optimal policy
286 
287  // run one mpc cycle
288  bool success = mpcSolver.finishIteration(x0, t, newPolicy, ts_newPolicy);
289  mpcSolver.prepareIteration(t);
290 
291  tempStateTraj = newPolicy.getReferenceStateTrajectory();
292 
293  // save trajectories
294  stateTrajContainer.push_back(tempStateTraj);
295  timeStamps.push_back(ts_newPolicy);
296  initStates.push_back(x0);
297 
298 
299  ct::core::Time relTime = ts_newPolicy;
300  ct::core::StateVector<state_dim> mpcTrajFirstState = tempStateTraj.front();
301  ct::core::StateVector<state_dim> refState = perfectStateTrajectory.eval(relTime);
302 
303  // Intuition of this test:
304  // The start of every mpc state trajectory has to be close to the initial "perfect" state trajectory.
305  // we allow for some tolerance, as the optimal trajectories might slightly change with shrinking time horizon
306  ASSERT_LT(std::fabs((refState - mpcTrajFirstState)(0)), 1.0); // max pos deviation
307  ASSERT_LT(std::fabs((refState - mpcTrajFirstState)(1)), 2.0); // max vel deviation
308 
309  if (mpcSolver.timeHorizonReached() || !success)
310  break;
311 
312  numRuns++;
313  }
314 
315 
316  mpcSolver.printMpcSummary();
317 
318  ASSERT_GT(numRuns, 10); // make sure that MPC runs more than 10 times
319 
320 
321 // The resulting trajectories can be visualized in MATLAB using the script mpc_unittest_plotting.m
322 #ifdef MATLAB_LOG_MPC
323 #ifdef MATLAB
324  std::cout << "Saving MPC trajectories to Matlab" << std::endl;
325 
326  matlab::MatFile matFile;
327  std::string dir = std::string(DATA_DIR_MPC) + "/solution.mat";
328  matFile.open(dir);
329 
330  for (size_t i = 0; i < timeStamps.size(); i++)
331  {
332  std::string x_varName = "x_" + std::to_string(i); // state traj
333  std::string t_varName = "t_" + std::to_string(i); // time traj
334  std::string ts_varName = "ts_" + std::to_string(i); // time stamp
335  std::string x0_varName = "x0_" + std::to_string(i); // initial states
336  matFile.put(x_varName, stateTrajContainer[i].getDataArray().toImplementation());
337  matFile.put(t_varName, stateTrajContainer[i].getTimeArray().toEigenTrajectory());
338  matFile.put(ts_varName, timeStamps[i]);
339  }
340 
341  matFile.close();
342 #endif
343 #endif
344 
345  } catch (std::exception& e)
346  {
347  std::cout << "caught exception: " << e.what() << std::endl;
348  FAIL();
349  }
350 }
351 
352 
353 } // namespace example
354 } // namespace optcon
355 } // namespace ct
LineSearchSettings lineSearchSettings
number of threads for eigen parallelization (applies both to MP and ST) Note. in order to activate Ei...
Definition: NLOptConSettings.hpp:275
virtual const core::StateTrajectory< STATE_DIM, SCALAR > getStateTrajectory() const override
Definition: NLOptConSolver-impl.hpp:152
void printMpcSummary()
printout simple statistical data
Definition: MPC-impl.h:300
LQOCP_SOLVER lqocp_solver
which nonlinear optimal control algorithm is to be used
Definition: NLOptConSettings.hpp:259
bool measureDelay_
Definition: MpcSettings.h:71
bool printSummary
Definition: NLOptConSettings.hpp:278
size_t nThreadsEigen
number of threads, for MP version
Definition: NLOptConSettings.hpp:274
double dt
Eigenvalue correction factor for Hessian regularization.
Definition: NLOptConSettings.hpp:262
TYPE type
Definition: NLOptConSettings.hpp:58
StateTrajectory< STATE_DIM, SCALAR > & getReferenceStateTrajectory()
bool finishIteration(const core::StateVector< STATE_DIM, Scalar_t > &x, const Scalar_t x_ts, Policy_t &newPolicy, Scalar_t &newPolicy_ts, const std::shared_ptr< core::Controller< STATE_DIM, CONTROL_DIM, Scalar_t >> forwardIntegrationController=nullptr)
finish MPC iteration
Definition: MPC-impl.h:177
bool timeHorizonReached()
Check if final time horizon for this task was reached.
Definition: MPC-impl.h:101
void prepareIteration(const Scalar_t &ext_ts)
Definition: MPC-impl.h:138
MPC_MODE mpc_mode
Definition: MpcSettings.h:99
bool debugPrint
Definition: NLOptConSettings.hpp:277
double stateForwardIntegration_dt_
Definition: MpcSettings.h:63
double delayMeasurementMultiplier_
Definition: MpcSettings.h:79
bool coldStart_
Definition: MpcSettings.h:111
void configure(const Settings_t &settings) override
Definition: NLOptConSolver-impl.hpp:62
double min_cost_improvement
duration of a shot as an integer multiple of dt
Definition: NLOptConSettings.hpp:265
clear all close all load ct GNMSLog0 mat reformat t
Definition: gnmsPlot.m:6
void setInitialGuess(const Policy_t &initialGuess) override
Definition: NLOptConSolver-impl.hpp:118
NLOCP_ALGORITHM nlocp_algorithm
Definition: NLOptConSettings.hpp:258
bool postTruncation_
Definition: MpcSettings.h:94
Definition: LinearOscillator.h:45
Settings for the NLOptCon algorithm.
Definition: NLOptConSettings.hpp:198
virtual bool solve() override
Definition: NLOptConSolver-impl.hpp:126
int additionalDelayUs_
Definition: MpcSettings.h:89
ct::core::Time timeHorizon
Definition: ConstrainedNLOCTest.cpp:15
void doForwardIntegration(const Scalar_t &t_forward_start, const Scalar_t &t_forward_stop, core::StateVector< STATE_DIM, Scalar_t > &x_start, const std::shared_ptr< core::Controller< STATE_DIM, CONTROL_DIM, Scalar_t >> forwardIntegrationController=nullptr)
perform forward integration of the measured system state, to compensate for expected or already occur...
Definition: MPC-impl.h:115
TEST(ConstraintComparison, comparisonAnalyticAD)
Definition: ConstraintComparison.h:158
const DiscreteArray< control_vector_t > & uff() const
Definition: LinearOscillator.h:27
MPC Settings struct.
Definition: MpcSettings.h:45
Main MPC class.
Definition: MPC.h:55
for i
Definition: mpc_unittest_plotting.m:14
APPROXIMATION discretization
which integrator to use during the NLOptCon forward rollout
Definition: NLOptConSettings.hpp:256
int K_sim
sampling time for the control input (seconds)
Definition: NLOptConSettings.hpp:263
virtual const Policy_t & getSolution() override
Definition: NLOptConSolver-impl.hpp:144
virtual T eval(const SCALAR &evalTime) override
int computeK(double timeHorizon) const
log to matlab (true/false)
Definition: NLOptConSettings.hpp:290
tpl::LinearOscillator< double > LinearOscillator
Definition: LinearOscillator.h:105
int max_iterations
trade off between external (general and path) constraint violation and cost
Definition: NLOptConSettings.hpp:269
a dummy class which is created for compatibility reasons if the MATLAB flag is not set...
Definition: matlab.hpp:17
bool useExternalTiming_
Definition: MpcSettings.h:118
StateVector< state_dim > x0
Definition: ConstrainedNLOCTest.cpp:14
FIXED_FINAL_TIME.
Definition: MpcSettings.h:34
tpl::LinearOscillatorLinear< double > LinearOscillatorLinear
Definition: LinearOscillator.h:106
bool stateForwardIntegration_
Definition: MpcSettings.h:53
ct::core::IntegrationType integrator
Definition: NLOptConSettings.hpp:255
ct::core::IntegrationType stateForwardIntegratorType_
Definition: MpcSettings.h:58
int nThreads
save the smallest eigenvalue of the Hessian
Definition: NLOptConSettings.hpp:272
int K_shot
number of sub-integration-steps
Definition: NLOptConSettings.hpp:264
Definition: NLOptConSolver.hpp:29
int fixedDelayUs_
Definition: MpcSettings.h:84
void setInitialGuess(const Policy_t &initGuess)
set a new initial guess for the policy
Definition: MPC-impl.h:92
ControlTrajectory< CONTROL_DIM, SCALAR > & getFeedforwardTrajectory()
Definition: OptConProblemBase.h:40
Definition: exampleDir.h:9
double Time