1 |
|
|
/////////////////////////////////////////////////////////////////////////////// |
2 |
|
|
// BSD 3-Clause License |
3 |
|
|
// |
4 |
|
|
// Copyright (C) 2019-2022, LAAS-CNRS, University of Edinburgh, |
5 |
|
|
// Heriot-Watt University |
6 |
|
|
// Copyright note valid unless otherwise stated in individual files. |
7 |
|
|
// All rights reserved. |
8 |
|
|
/////////////////////////////////////////////////////////////////////////////// |
9 |
|
|
|
10 |
|
|
#ifndef CROCODDYL_CORE_SOLVERS_FDDP_HPP_ |
11 |
|
|
#define CROCODDYL_CORE_SOLVERS_FDDP_HPP_ |
12 |
|
|
|
13 |
|
|
#include <Eigen/Cholesky> |
14 |
|
|
#include <vector> |
15 |
|
|
|
16 |
|
|
#include "crocoddyl/core/solvers/ddp.hpp" |
17 |
|
|
|
18 |
|
|
namespace crocoddyl { |
19 |
|
|
|
20 |
|
|
/** |
21 |
|
|
* @brief Feasibility-driven Differential Dynamic Programming (FDDP) solver |
22 |
|
|
* |
23 |
|
|
* The FDDP solver computes an optimal trajectory and control commands by |
24 |
|
|
* iterates running `backwardPass()` and `forwardPass()`. The backward pass |
25 |
|
|
* accepts infeasible guess as described in the `SolverDDP::backwardPass()`. |
26 |
|
|
* Additionally, the forward pass handles infeasibility simulations that |
27 |
|
|
* resembles the numerical behaviour of a multiple-shooting formulation, i.e.: |
28 |
|
|
* \f{eqnarray} |
29 |
|
|
* \mathbf{\hat{x}}_0 &=& \mathbf{\tilde{x}}_0 - (1 - |
30 |
|
|
* \alpha)\mathbf{\bar{f}}_0,\\ |
31 |
|
|
* \mathbf{\hat{u}}_k &=& \mathbf{u}_k + \alpha\mathbf{k}_k + |
32 |
|
|
* \mathbf{K}_k(\mathbf{\hat{x}}_k-\mathbf{x}_k),\\ \mathbf{\hat{x}}_{k+1} &=& |
33 |
|
|
* \mathbf{f}_k(\mathbf{\hat{x}}_k,\mathbf{\hat{u}}_k) - (1 - |
34 |
|
|
* \alpha)\mathbf{\bar{f}}_{k+1}. |
35 |
|
|
* \f} |
36 |
|
|
* Note that the forward pass keeps the gaps \f$\mathbf{\bar{f}}_s\f$ open |
37 |
|
|
* according to the step length \f$\alpha\f$ that has been accepted. This solver |
38 |
|
|
* has shown empirically greater globalization strategy. Additionally, the |
39 |
|
|
* expected improvement computation considers the gaps in the dynamics: |
40 |
|
|
* \f{equation} |
41 |
|
|
* \Delta J(\alpha) = \Delta_1\alpha + \frac{1}{2}\Delta_2\alpha^2, |
42 |
|
|
* \f} |
43 |
|
|
* with |
44 |
|
|
* \f{eqnarray} |
45 |
|
|
* \Delta_1 = \sum_{k=0}^{N-1} \mathbf{k}_k^\top\mathbf{Q}_{\mathbf{u}_k} |
46 |
|
|
* +\mathbf{\bar{f}}_k^\top(V_{\mathbf{x}_k} - |
47 |
|
|
* V_{\mathbf{xx}_k}\mathbf{x}_k),\nonumber\\ \Delta_2 = \sum_{k=0}^{N-1} |
48 |
|
|
* \mathbf{k}_k^\top\mathbf{Q}_{\mathbf{uu}_k}\mathbf{k}_k + |
49 |
|
|
* \mathbf{\bar{f}}_k^\top(2 V_{\mathbf{xx}_k}\mathbf{x}_k |
50 |
|
|
* - V_{\mathbf{xx}_k}\mathbf{\bar{f}}_k). \f} |
51 |
|
|
* |
52 |
|
|
* For more details about the feasibility-driven differential dynamic |
53 |
|
|
* programming algorithm see: \include mastalli-icra20.bib |
54 |
|
|
* |
55 |
|
|
* \sa `SolverDDP()`, `backwardPass()`, `forwardPass()`, `expectedImprovement()` |
56 |
|
|
* and `updateExpectedImprovement()` |
57 |
|
|
*/ |
58 |
|
|
class SolverFDDP : public SolverDDP { |
59 |
|
|
public: |
60 |
|
|
EIGEN_MAKE_ALIGNED_OPERATOR_NEW |
61 |
|
|
|
62 |
|
|
/** |
63 |
|
|
* @brief Initialize the FDDP solver |
64 |
|
|
* |
65 |
|
|
* @param[in] problem shooting problem |
66 |
|
|
*/ |
67 |
|
|
explicit SolverFDDP(boost::shared_ptr<ShootingProblem> problem); |
68 |
|
|
virtual ~SolverFDDP(); |
69 |
|
|
|
70 |
|
|
virtual bool solve( |
71 |
|
|
const std::vector<Eigen::VectorXd>& init_xs = DEFAULT_VECTOR, |
72 |
|
|
const std::vector<Eigen::VectorXd>& init_us = DEFAULT_VECTOR, |
73 |
|
|
const std::size_t maxiter = 100, const bool is_feasible = false, |
74 |
|
|
const double init_reg = NAN); |
75 |
|
|
|
76 |
|
|
/** |
77 |
|
|
* @copybrief SolverAbstract::expectedImprovement |
78 |
|
|
* |
79 |
|
|
* This function requires to first run `updateExpectedImprovement()`. The |
80 |
|
|
* expected improvement computation considers the gaps in the dynamics: |
81 |
|
|
* \f{equation} \Delta J(\alpha) = \Delta_1\alpha + |
82 |
|
|
* \frac{1}{2}\Delta_2\alpha^2, \f} with \f{eqnarray} \Delta_1 = |
83 |
|
|
* \sum_{k=0}^{N-1} \mathbf{k}_k^\top\mathbf{Q}_{\mathbf{u}_k} |
84 |
|
|
* +\mathbf{\bar{f}}_k^\top(V_{\mathbf{x}_k} |
85 |
|
|
* - V_{\mathbf{xx}_k}\mathbf{x}_k),\nonumber\\ \Delta_2 = \sum_{k=0}^{N-1} |
86 |
|
|
* \mathbf{k}_k^\top\mathbf{Q}_{\mathbf{uu}_k}\mathbf{k}_k + |
87 |
|
|
* \mathbf{\bar{f}}_k^\top(2 V_{\mathbf{xx}_k}\mathbf{x}_k |
88 |
|
|
* - V_{\mathbf{xx}_k}\mathbf{\bar{f}}_k). \f} |
89 |
|
|
*/ |
90 |
|
|
virtual const Eigen::Vector2d& expectedImprovement(); |
91 |
|
|
|
92 |
|
|
/** |
93 |
|
|
* @brief Update internal values for computing the expected improvement |
94 |
|
|
*/ |
95 |
|
|
void updateExpectedImprovement(); |
96 |
|
|
virtual void forwardPass(const double stepLength); |
97 |
|
|
|
98 |
|
|
/** |
99 |
|
|
* @brief Return the threshold used for accepting step along ascent direction |
100 |
|
|
*/ |
101 |
|
|
double get_th_acceptnegstep() const; |
102 |
|
|
|
103 |
|
|
/** |
104 |
|
|
* @brief Modify the threshold used for accepting step along ascent direction |
105 |
|
|
*/ |
106 |
|
|
void set_th_acceptnegstep(const double th_acceptnegstep); |
107 |
|
|
|
108 |
|
|
protected: |
109 |
|
|
double dg_; //!< Internal data for computing the expected improvement |
110 |
|
|
double dq_; //!< Internal data for computing the expected improvement |
111 |
|
|
double dv_; //!< Internal data for computing the expected improvement |
112 |
|
|
double th_acceptnegstep_; //!< Threshold used for accepting step along ascent |
113 |
|
|
//!< direction |
114 |
|
|
}; |
115 |
|
|
|
116 |
|
|
} // namespace crocoddyl |
117 |
|
|
|
118 |
|
|
#endif // CROCODDYL_CORE_SOLVERS_FDDP_HPP_ |