GCC Code Coverage Report


Directory: ./
File: include/crocoddyl/multibody/actions/contact-fwddyn.hpp
Date: 2025-03-26 19:23:43
Exec Total Coverage
Lines: 32 33 97.0%
Branches: 58 116 50.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh, CTU, INRIA,
5 // University of Oxford, Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifndef CROCODDYL_MULTIBODY_ACTIONS_CONTACT_FWDDYN_HPP_
11 #define CROCODDYL_MULTIBODY_ACTIONS_CONTACT_FWDDYN_HPP_
12
13 #include <stdexcept>
14
15 #include "crocoddyl/core/actuation-base.hpp"
16 #include "crocoddyl/core/constraints/constraint-manager.hpp"
17 #include "crocoddyl/core/costs/cost-sum.hpp"
18 #include "crocoddyl/core/diff-action-base.hpp"
19 #include "crocoddyl/multibody/contacts/multiple-contacts.hpp"
20 #include "crocoddyl/multibody/data/contacts.hpp"
21 #include "crocoddyl/multibody/fwd.hpp"
22 #include "crocoddyl/multibody/states/multibody.hpp"
23
24 namespace crocoddyl {
25
26 /**
27 * @brief Differential action model for contact forward dynamics in multibody
28 * systems.
29 *
30 * This class implements contact forward dynamics given a stack of
31 * rigid-contacts described in `ContactModelMultipleTpl`, i.e., \f[
32 * \left[\begin{matrix}\dot{\mathbf{v}}
33 * \\ -\boldsymbol{\lambda}\end{matrix}\right] = \left[\begin{matrix}\mathbf{M}
34 * & \mathbf{J}^{\top}_c \\ {\mathbf{J}_{c}} & \mathbf{0}
35 * \end{matrix}\right]^{-1} \left[\begin{matrix}\boldsymbol{\tau}_b
36 * \\ -\mathbf{a}_0 \\\end{matrix}\right], \f] where \f$\mathbf{q}\in Q\f$,
37 * \f$\mathbf{v}\in\mathbb{R}^{nv}\f$ are the configuration point and
38 * generalized velocity (its tangent vector), respectively;
39 * \f$\boldsymbol{\tau}_b=\boldsymbol{\tau} -
40 * \mathbf{h}(\mathbf{q},\mathbf{v})\f$ is the bias forces that depends on the
41 * torque inputs \f$\boldsymbol{\tau}\f$ and the Coriolis effect and gravity
42 * field \f$\mathbf{h}(\mathbf{q},\mathbf{v})\f$;
43 * \f$\mathbf{J}_c\in\mathbb{R}^{nc\times nv}\f$ is the contact Jacobian
44 * expressed in the local frame; and \f$\mathbf{a}_0\in\mathbb{R}^{nc}\f$ is the
45 * desired acceleration in the constraint space. To improve stability in the
46 * numerical integration, we define PD gains that are similar in spirit to
47 * Baumgarte stabilization: \f[ \mathbf{a}_0 = \mathbf{a}_{\lambda(c)} - \alpha
48 * \,^oM^{ref}_{\lambda(c)}\ominus\,^oM_{\lambda(c)}
49 * - \beta\mathbf{v}_{\lambda(c)}, \f] where \f$\mathbf{v}_{\lambda(c)}\f$,
50 * \f$\mathbf{a}_{\lambda(c)}\f$ are the spatial velocity and acceleration at
51 * the parent body of the contact \f$\lambda(c)\f$, respectively; \f$\alpha\f$
52 * and \f$\beta\f$ are the stabilization gains;
53 * \f$\,^oM^{ref}_{\lambda(c)}\ominus\,^oM_{\lambda(c)}\f$ is the
54 * \f$\mathbb{SE}(3)\f$ inverse composition between the reference contact
55 * placement and the current one.
56 *
57 * The derivatives of the system acceleration and contact forces are computed
58 * efficiently based on the analytical derivatives of Recursive Newton Euler
59 * Algorithm (RNEA) as described in \cite mastalli-icra20. Note that the
60 * algorithm for computing the RNEA derivatives is described in \cite
61 * carpentier-rss18.
62 *
63 * The stack of cost and constraint functions are implemented in
64 * `CostModelSumTpl` and `ConstraintModelAbstractTpl`, respectively. The
65 * computation of the contact dynamics and its derivatives are carrying out
66 * inside `calc()` and `calcDiff()` functions, respectively. It is also
67 * important to remark that `calcDiff()` computes the derivatives using the
68 * latest stored values by `calc()`. Thus, we need to run `calc()` first.
69 *
70 * \sa `DifferentialActionModelAbstractTpl`, `calc()`, `calcDiff()`,
71 * `createData()`
72 */
73 template <typename _Scalar>
74 class DifferentialActionModelContactFwdDynamicsTpl
75 : public DifferentialActionModelAbstractTpl<_Scalar> {
76 public:
77 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
78 CROCODDYL_DERIVED_CAST(DifferentialActionModelBase,
79 DifferentialActionModelContactFwdDynamicsTpl)
80
81 typedef _Scalar Scalar;
82 typedef DifferentialActionModelAbstractTpl<Scalar> Base;
83 typedef DifferentialActionDataContactFwdDynamicsTpl<Scalar> Data;
84 typedef MathBaseTpl<Scalar> MathBase;
85 typedef StateMultibodyTpl<Scalar> StateMultibody;
86 typedef CostModelSumTpl<Scalar> CostModelSum;
87 typedef ConstraintModelManagerTpl<Scalar> ConstraintModelManager;
88 typedef ContactModelMultipleTpl<Scalar> ContactModelMultiple;
89 typedef ActuationModelAbstractTpl<Scalar> ActuationModelAbstract;
90 typedef DifferentialActionDataAbstractTpl<Scalar>
91 DifferentialActionDataAbstract;
92 typedef typename MathBase::VectorXs VectorXs;
93 typedef typename MathBase::MatrixXs MatrixXs;
94
95 /**
96 * @brief Initialize the contact forward-dynamics action model
97 *
98 * It describes the dynamics evolution of a multibody system under
99 * rigid-contact constraints defined by `ContactModelMultipleTpl`. It computes
100 * the cost described in `CostModelSumTpl`.
101 *
102 * @param[in] state State of the multibody system
103 * @param[in] actuation Actuation model
104 * @param[in] contacts Stack of rigid contact
105 * @param[in] costs Stack of cost functions
106 * @param[in] JMinvJt_damping Damping term used in operational space inertia
107 * matrix (default 0.)
108 * @param[in] enable_force Enable the computation of the contact force
109 * derivatives (default false)
110 */
111 DifferentialActionModelContactFwdDynamicsTpl(
112 std::shared_ptr<StateMultibody> state,
113 std::shared_ptr<ActuationModelAbstract> actuation,
114 std::shared_ptr<ContactModelMultiple> contacts,
115 std::shared_ptr<CostModelSum> costs,
116 const Scalar JMinvJt_damping = Scalar(0.),
117 const bool enable_force = false);
118
119 /**
120 * @brief Initialize the contact forward-dynamics action model
121 *
122 * It describes the dynamics evolution of a multibody system under
123 * rigid-contact constraints defined by `ContactModelMultipleTpl`. It computes
124 * the cost described in `CostModelSumTpl`.
125 *
126 * @param[in] state State of the multibody system
127 * @param[in] actuation Actuation model
128 * @param[in] contacts Stack of rigid contact
129 * @param[in] costs Stack of cost functions
130 * @param[in] constraints Stack of constraints
131 * @param[in] JMinvJt_damping Damping term used in operational space inertia
132 * matrix (default 0.)
133 * @param[in] enable_force Enable the computation of the contact force
134 * derivatives (default false)
135 */
136 DifferentialActionModelContactFwdDynamicsTpl(
137 std::shared_ptr<StateMultibody> state,
138 std::shared_ptr<ActuationModelAbstract> actuation,
139 std::shared_ptr<ContactModelMultiple> contacts,
140 std::shared_ptr<CostModelSum> costs,
141 std::shared_ptr<ConstraintModelManager> constraints,
142 const Scalar JMinvJt_damping = Scalar(0.),
143 const bool enable_force = false);
144 928 virtual ~DifferentialActionModelContactFwdDynamicsTpl() = default;
145
146 /**
147 * @brief Compute the system acceleration, and cost value
148 *
149 * It computes the system acceleration using the contact dynamics.
150 *
151 * @param[in] data Contact forward-dynamics data
152 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
153 * @param[in] u Control input \f$\mathbf{u}\in\mathbb{R}^{nu}\f$
154 */
155 virtual void calc(const std::shared_ptr<DifferentialActionDataAbstract>& data,
156 const Eigen::Ref<const VectorXs>& x,
157 const Eigen::Ref<const VectorXs>& u) override;
158
159 /**
160 * @brief Compute the total cost value for nodes that depends only on the
161 * state
162 *
163 * It updates the total cost and the system acceleration is not updated as it
164 * is expected to be zero. Additionally, it does not update the contact
165 * forces. This function is used in the terminal nodes of an optimal control
166 * problem.
167 *
168 * @param[in] data Contact forward-dynamics data
169 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
170 */
171 virtual void calc(const std::shared_ptr<DifferentialActionDataAbstract>& data,
172 const Eigen::Ref<const VectorXs>& x) override;
173
174 /**
175 * @brief Compute the derivatives of the contact dynamics, and cost function
176 *
177 * @param[in] data Contact forward-dynamics data
178 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
179 * @param[in] u Control input \f$\mathbf{u}\in\mathbb{R}^{nu}\f$
180 */
181 virtual void calcDiff(
182 const std::shared_ptr<DifferentialActionDataAbstract>& data,
183 const Eigen::Ref<const VectorXs>& x,
184 const Eigen::Ref<const VectorXs>& u) override;
185
186 /**
187 * @brief Compute the derivatives of the cost functions with respect to the
188 * state only
189 *
190 * It updates the derivatives of the cost function with respect to the state
191 * only. Additionally, it does not update the contact forces derivatives. This
192 * function is used in the terminal nodes of an optimal control problem.
193 *
194 * @param[in] data Contact forward-dynamics data
195 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
196 */
197 virtual void calcDiff(
198 const std::shared_ptr<DifferentialActionDataAbstract>& data,
199 const Eigen::Ref<const VectorXs>& x) override;
200
201 /**
202 * @brief Create the contact forward-dynamics data
203 *
204 * @return contact forward-dynamics data
205 */
206 virtual std::shared_ptr<DifferentialActionDataAbstract> createData() override;
207
208 /**
209 * @brief Cast the contact-fwddyn model to a different scalar type.
210 *
211 * It is useful for operations requiring different precision or scalar types.
212 *
213 * @tparam NewScalar The new scalar type to cast to.
214 * @return DifferentialActionModelContactFwdDynamicsTpl<NewScalar> A
215 * differential-action model with the new scalar type.
216 */
217 template <typename NewScalar>
218 DifferentialActionModelContactFwdDynamicsTpl<NewScalar> cast() const;
219
220 /**
221 * @brief Check that the given data belongs to the contact forward-dynamics
222 * data
223 */
224 virtual bool checkData(
225 const std::shared_ptr<DifferentialActionDataAbstract>& data) override;
226
227 /**
228 * @brief @copydoc Base::quasiStatic()
229 */
230 virtual void quasiStatic(
231 const std::shared_ptr<DifferentialActionDataAbstract>& data,
232 Eigen::Ref<VectorXs> u, const Eigen::Ref<const VectorXs>& x,
233 const std::size_t maxiter = 100,
234 const Scalar tol = Scalar(1e-9)) override;
235
236 /**
237 * @brief Return the number of inequality constraints
238 */
239 virtual std::size_t get_ng() const override;
240
241 /**
242 * @brief Return the number of equality constraints
243 */
244 virtual std::size_t get_nh() const override;
245
246 /**
247 * @brief Return the number of equality terminal constraints
248 */
249 virtual std::size_t get_ng_T() const override;
250
251 /**
252 * @brief Return the number of equality terminal constraints
253 */
254 virtual std::size_t get_nh_T() const override;
255
256 /**
257 * @brief Return the lower bound of the inequality constraints
258 */
259 virtual const VectorXs& get_g_lb() const override;
260
261 /**
262 * @brief Return the upper bound of the inequality constraints
263 */
264 virtual const VectorXs& get_g_ub() const override;
265
266 /**
267 * @brief Return the actuation model
268 */
269 const std::shared_ptr<ActuationModelAbstract>& get_actuation() const;
270
271 /**
272 * @brief Return the contact model
273 */
274 const std::shared_ptr<ContactModelMultiple>& get_contacts() const;
275
276 /**
277 * @brief Return the cost model
278 */
279 const std::shared_ptr<CostModelSum>& get_costs() const;
280
281 /**
282 * @brief Return the constraint model manager
283 */
284 const std::shared_ptr<ConstraintModelManager>& get_constraints() const;
285
286 /**
287 * @brief Return the Pinocchio model
288 */
289 pinocchio::ModelTpl<Scalar>& get_pinocchio() const;
290
291 /**
292 * @brief Return the armature vector
293 */
294 const VectorXs& get_armature() const;
295
296 /**
297 * @brief Return the damping factor used in operational space inertia matrix
298 */
299 const Scalar get_damping_factor() const;
300
301 /**
302 * @brief Modify the armature vector
303 */
304 void set_armature(const VectorXs& armature);
305
306 /**
307 * @brief Modify the damping factor used in operational space inertia matrix
308 */
309 void set_damping_factor(const Scalar damping);
310
311 /**
312 * @brief Print relevant information of the contact forward-dynamics model
313 *
314 * @param[out] os Output stream object
315 */
316 virtual void print(std::ostream& os) const override;
317
318 protected:
319 using Base::g_lb_; //!< Lower bound of the inequality constraints
320 using Base::g_ub_; //!< Upper bound of the inequality constraints
321 using Base::nu_; //!< Control dimension
322 using Base::state_; //!< Model of the state
323
324 private:
325 void init();
326 std::shared_ptr<ActuationModelAbstract> actuation_; //!< Actuation model
327 std::shared_ptr<ContactModelMultiple> contacts_; //!< Contact model
328 std::shared_ptr<CostModelSum> costs_; //!< Cost model
329 std::shared_ptr<ConstraintModelManager> constraints_; //!< Constraint model
330 pinocchio::ModelTpl<Scalar>* pinocchio_; //!< Pinocchio model
331 bool with_armature_; //!< Indicate if we have defined an armature
332 VectorXs armature_; //!< Armature vector
333 Scalar JMinvJt_damping_; //!< Damping factor used in operational space
334 //!< inertia matrix
335 bool enable_force_; //!< Indicate if we have enabled the computation of the
336 //!< contact-forces derivatives
337 };
338
339 template <typename _Scalar>
340 struct DifferentialActionDataContactFwdDynamicsTpl
341 : public DifferentialActionDataAbstractTpl<_Scalar> {
342 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
343 typedef _Scalar Scalar;
344 typedef MathBaseTpl<Scalar> MathBase;
345 typedef DifferentialActionDataAbstractTpl<Scalar> Base;
346 typedef JointDataAbstractTpl<Scalar> JointDataAbstract;
347 typedef DataCollectorJointActMultibodyInContactTpl<Scalar>
348 DataCollectorJointActMultibodyInContact;
349 typedef typename MathBase::VectorXs VectorXs;
350 typedef typename MathBase::MatrixXs MatrixXs;
351
352 template <template <typename Scalar> class Model>
353 39556 explicit DifferentialActionDataContactFwdDynamicsTpl(
354 Model<Scalar>* const model)
355 : Base(model),
356
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 pinocchio(pinocchio::DataTpl<Scalar>(model->get_pinocchio())),
357
4/8
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39554 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39554 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 39554 times.
✗ Branch 11 not taken.
118668 multibody(
358
2/4
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 &pinocchio, model->get_actuation()->createData(),
359 std::make_shared<JointDataAbstract>(
360
2/4
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39554 times.
✗ Branch 5 not taken.
79112 model->get_state(), model->get_actuation(), model->get_nu()),
361
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 model->get_contacts()->createData(&pinocchio)),
362
2/4
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 costs(model->get_costs()->createData(&multibody)),
363
1/2
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
39556 Kinv(model->get_state()->get_nv() +
364
3/6
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
39556 model->get_contacts()->get_nc_total(),
365
2/4
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 model->get_state()->get_nv() +
366
3/6
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
39556 model->get_contacts()->get_nc_total()),
367
2/4
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 df_dx(model->get_contacts()->get_nc_total(),
368
3/6
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
39556 model->get_state()->get_ndx()),
369
4/8
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39554 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 39554 times.
✗ Branch 12 not taken.
39556 df_du(model->get_contacts()->get_nc_total(), model->get_nu()),
370
3/6
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
39556 tmp_xstatic(model->get_state()->get_nx()),
371
2/4
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 tmp_Jstatic(model->get_state()->get_nv(),
372
5/10
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 39554 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 39554 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 39554 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 39554 times.
✗ Branch 17 not taken.
118668 model->get_nu() + model->get_contacts()->get_nc_total()) {
373
2/4
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
39556 multibody.joint->dtau_du.diagonal().setOnes();
374
1/2
✓ Branch 2 taken 39554 times.
✗ Branch 3 not taken.
39556 costs->shareMemory(this);
375
3/4
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1160 times.
✓ Branch 5 taken 38394 times.
39556 if (model->get_constraints() != nullptr) {
376
2/4
✓ Branch 1 taken 1160 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1160 times.
✗ Branch 6 not taken.
1160 constraints = model->get_constraints()->createData(&multibody);
377
1/2
✓ Branch 2 taken 1160 times.
✗ Branch 3 not taken.
1160 constraints->shareMemory(this);
378 }
379
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 Kinv.setZero();
380
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 df_dx.setZero();
381
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 df_du.setZero();
382
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 tmp_xstatic.setZero();
383
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 tmp_Jstatic.setZero();
384
3/6
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 39554 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 39554 times.
✗ Branch 9 not taken.
39556 pinocchio.lambda_c.resize(model->get_contacts()->get_nc_total());
385
1/2
✓ Branch 1 taken 39554 times.
✗ Branch 2 not taken.
39556 pinocchio.lambda_c.setZero();
386 39556 }
387 79108 virtual ~DifferentialActionDataContactFwdDynamicsTpl() = default;
388
389 pinocchio::DataTpl<Scalar> pinocchio;
390 DataCollectorJointActMultibodyInContact multibody;
391 std::shared_ptr<CostDataSumTpl<Scalar> > costs;
392 std::shared_ptr<ConstraintDataManagerTpl<Scalar> > constraints;
393 MatrixXs Kinv;
394 MatrixXs df_dx;
395 MatrixXs df_du;
396 VectorXs tmp_xstatic;
397 MatrixXs tmp_Jstatic;
398
399 using Base::cost;
400 using Base::Fu;
401 using Base::Fx;
402 using Base::Lu;
403 using Base::Luu;
404 using Base::Lx;
405 using Base::Lxu;
406 using Base::Lxx;
407 using Base::r;
408 using Base::xout;
409 };
410
411 } // namespace crocoddyl
412
413 /* --- Details -------------------------------------------------------------- */
414 /* --- Details -------------------------------------------------------------- */
415 /* --- Details -------------------------------------------------------------- */
416 #include <crocoddyl/multibody/actions/contact-fwddyn.hxx>
417
418 CROCODDYL_DECLARE_EXTERN_TEMPLATE_CLASS(
419 crocoddyl::DifferentialActionModelContactFwdDynamicsTpl)
420 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(
421 crocoddyl::DifferentialActionDataContactFwdDynamicsTpl)
422
423 #endif // CROCODDYL_MULTIBODY_ACTIONS_CONTACT_FWDDYN_HPP_
424