GCC Code Coverage Report


Directory: ./
File: include/crocoddyl/multibody/impulses/multiple-impulses.hpp
Date: 2025-03-26 19:23:43
Exec Total Coverage
Lines: 20 27 74.1%
Branches: 29 58 50.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, 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_MULTIBODY_IMPULSES_MULTIPLE_IMPULSES_HPP_
11 #define CROCODDYL_MULTIBODY_IMPULSES_MULTIPLE_IMPULSES_HPP_
12
13 #include <map>
14 #include <set>
15 #include <string>
16 #include <utility>
17
18 #include "crocoddyl/multibody/fwd.hpp"
19 #include "crocoddyl/multibody/impulse-base.hpp"
20
21 namespace crocoddyl {
22
23 template <typename _Scalar>
24 struct ImpulseItemTpl {
25 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
26
27 typedef _Scalar Scalar;
28 typedef ImpulseModelAbstractTpl<Scalar> ImpulseModelAbstract;
29
30 ImpulseItemTpl() {}
31 266 ImpulseItemTpl(const std::string& name,
32 std::shared_ptr<ImpulseModelAbstract> impulse,
33 const bool active = true)
34 266 : name(name), impulse(impulse), active(active) {}
35
36 template <typename NewScalar>
37 ImpulseItemTpl<NewScalar> cast() const {
38 typedef ImpulseItemTpl<NewScalar> ReturnType;
39 ReturnType ret(name, impulse->template cast<NewScalar>(), active);
40 return ret;
41 }
42
43 /**
44 * @brief Print information on the impulse item
45 */
46 friend std::ostream& operator<<(std::ostream& os,
47 const ImpulseItemTpl<Scalar>& model) {
48 os << "{" << *model.impulse << "}";
49 return os;
50 }
51
52 std::string name;
53 std::shared_ptr<ImpulseModelAbstract> impulse;
54 bool active;
55 };
56
57 /**
58 * @brief Define a stack of impulse models
59 *
60 * The impulse models can be defined with active and inactive status. The idea
61 * behind this design choice is to be able to create a mechanism that allocates
62 * the entire data needed for the computations. Then, there are designed
63 * routines that update the only active impulse.
64 */
65 template <typename _Scalar>
66 class ImpulseModelMultipleTpl {
67 public:
68 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
69
70 typedef _Scalar Scalar;
71 typedef MathBaseTpl<Scalar> MathBase;
72 typedef StateMultibodyTpl<Scalar> StateMultibody;
73 typedef ImpulseDataAbstractTpl<Scalar> ImpulseDataAbstract;
74 typedef ImpulseDataMultipleTpl<Scalar> ImpulseDataMultiple;
75 typedef ImpulseModelAbstractTpl<Scalar> ImpulseModelAbstract;
76
77 typedef ImpulseItemTpl<Scalar> ImpulseItem;
78
79 typedef typename MathBase::Vector2s Vector2s;
80 typedef typename MathBase::Vector3s Vector3s;
81 typedef typename MathBase::VectorXs VectorXs;
82 typedef typename MathBase::MatrixXs MatrixXs;
83
84 typedef std::map<std::string, std::shared_ptr<ImpulseItem> >
85 ImpulseModelContainer;
86 typedef std::map<std::string, std::shared_ptr<ImpulseDataAbstract> >
87 ImpulseDataContainer;
88 typedef typename pinocchio::container::aligned_vector<
89 pinocchio::ForceTpl<Scalar> >::iterator ForceIterator;
90
91 /**
92 * @brief Initialize the multi-impulse model
93 *
94 * @param[in] state Multibody state
95 */
96 explicit ImpulseModelMultipleTpl(std::shared_ptr<StateMultibody> state);
97 ~ImpulseModelMultipleTpl();
98
99 /**
100 * @brief Add impulse item
101 *
102 * Note that the memory is allocated for inactive impulses as well.
103 *
104 * @param[in] name Impulse name
105 * @param[in] impulse Impulse model
106 * @param[in] active Impulse status (active by default)
107 */
108 void addImpulse(const std::string& name,
109 std::shared_ptr<ImpulseModelAbstract> impulse,
110 const bool active = true);
111
112 /**
113 * @brief Remove impulse item
114 *
115 * @param[in] name Impulse name
116 */
117 void removeImpulse(const std::string& name);
118
119 /**
120 * @brief Change the impulse status
121 *
122 * @param[in] name Impulse name
123 * @param[in] active Impulse status (True for active)
124 */
125 void changeImpulseStatus(const std::string& name, const bool active);
126
127 /**
128 * @brief Compute the total impulse Jacobian and impulse velocity
129 *
130 * @param[in] data Multi-impulse data
131 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
132 */
133 void calc(const std::shared_ptr<ImpulseDataMultiple>& data,
134 const Eigen::Ref<const VectorXs>& x);
135
136 /**
137 * @brief Compute the derivatives of the impulse holonomic constraint
138 *
139 * @param[in] data Multi-impulse data
140 * @param[in] x State point \f$\mathbf{x}\in\mathbb{R}^{ndx}\f$
141 */
142 void calcDiff(const std::shared_ptr<ImpulseDataMultiple>& data,
143 const Eigen::Ref<const VectorXs>& x);
144
145 /**
146 * @brief Update the system velocity after impulse
147 *
148 * @param[in] data Multi-impulse data
149 * @param[in] vnext System velocity after impulse
150 * \f$\mathbf{v}'\in\mathbb{R}^{nv}\f$
151 */
152 void updateVelocity(const std::shared_ptr<ImpulseDataMultiple>& data,
153 const VectorXs& vnext) const;
154
155 /**
156 * @brief Update the spatial impulse defined in frame coordinate
157 *
158 * @param[in] data Multi-impulse data
159 * @param[in] impulse Spatial impulse defined in frame coordinate
160 * \f${}^o\underline{\boldsymbol{\Lambda}}_c\in\mathbb{R}^{nc}\f$
161 */
162 void updateForce(const std::shared_ptr<ImpulseDataMultiple>& data,
163 const VectorXs& impulse);
164
165 /**
166 * @brief Update the Jacobian of the system velocity after impulse
167 *
168 * @param[in] data Multi-impulse data
169 * @param[in] dvnext_dx Jacobian of the system velocity after impact in
170 * generalized coordinates
171 * \f$\frac{\partial\dot{\mathbf{v}'}}{\partial\mathbf{x}}\in\mathbb{R}^{nv\times{ndx}}\f$
172 */
173 void updateVelocityDiff(const std::shared_ptr<ImpulseDataMultiple>& data,
174 const MatrixXs& dvnext_dx) const;
175
176 /**
177 * @brief Update the Jacobian of the spatial impulse defined in frame
178 * coordinate
179 *
180 * @param[in] data Multi-contact data
181 * @param[in] df_dx Jacobian of the spatial impulse defined in frame
182 * coordinate
183 * \f$\frac{\partial{}^o\underline{\boldsymbol{\Lambda}}_c}{\partial\mathbf{x}}\in\mathbb{R}^{nc\times{ndx}}\f$
184 */
185 void updateForceDiff(const std::shared_ptr<ImpulseDataMultiple>& data,
186 const MatrixXs& df_dx) const;
187
188 /**
189 * @brief Update the RNEA derivatives dtau_dq by adding the skew term
190 * (necessary for impulses expressed in LOCAL_WORLD_ALIGNED / WORLD)
191 * @brief as explained in this document :
192 * https://www.overleaf.com/read/tzvrrxxtntwk
193 *
194 * @param[in] data Multi-contact data
195 * @param[in] pinocchio Pinocchio data
196 */
197 void updateRneaDiff(const std::shared_ptr<ImpulseDataMultiple>& data,
198 pinocchio::DataTpl<Scalar>& pinocchio) const;
199
200 /**
201 * @brief Create the multi-impulse data
202 *
203 * @param[in] data Pinocchio data
204 * @return the multi-impulse data.
205 */
206 std::shared_ptr<ImpulseDataMultiple> createData(
207 pinocchio::DataTpl<Scalar>* const data);
208
209 /**
210 * @brief Cast the multi-impulse model to a different scalar type.
211 *
212 * It is useful for operations requiring different precision or scalar types.
213 *
214 * @tparam NewScalar The new scalar type to cast to.
215 * @return ImpulseModelMultipleTpl<NewScalar> A multi-impulse model with the
216 * new scalar type.
217 */
218 template <typename NewScalar>
219 ImpulseModelMultipleTpl<NewScalar> cast() const;
220
221 /**
222 * @brief Return the multibody state
223 */
224 const std::shared_ptr<StateMultibody>& get_state() const;
225
226 /**
227 * @brief Return the impulse models
228 */
229 const ImpulseModelContainer& get_impulses() const;
230
231 /**
232 * @brief Return the dimension of active impulses
233 */
234 std::size_t get_nc() const;
235
236 /**
237 * @brief Return the dimension of all impulses
238 */
239 std::size_t get_nc_total() const;
240
241 /**
242 * @brief Return the names of the set of active impulses
243 */
244 const std::set<std::string>& get_active_set() const;
245
246 /**
247 * @brief Return the names of the set of inactive impulses
248 */
249 const std::set<std::string>& get_inactive_set() const;
250
251 /**
252 * @brief Return the status of a given impulse name
253 */
254 bool getImpulseStatus(const std::string& name) const;
255
256 /**
257 * @brief Print information on the impulse models
258 */
259 template <class Scalar>
260 friend std::ostream& operator<<(std::ostream& os,
261 const ImpulseModelMultipleTpl<Scalar>& model);
262
263 private:
264 std::shared_ptr<StateMultibody> state_;
265 ImpulseModelContainer impulses_;
266 std::size_t nc_;
267 std::size_t nc_total_;
268 std::set<std::string> active_set_;
269 std::set<std::string> inactive_set_;
270 };
271
272 /**
273 * @brief Define the multi-impulse data
274 *
275 * \sa ImpulseModelMultipleTpl
276 */
277 template <typename _Scalar>
278 struct ImpulseDataMultipleTpl {
279 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
280
281 typedef _Scalar Scalar;
282 typedef MathBaseTpl<Scalar> MathBase;
283 typedef ImpulseModelMultipleTpl<Scalar> ImpulseModelMultiple;
284 typedef ImpulseItemTpl<Scalar> ImpulseItem;
285 typedef typename MathBase::VectorXs VectorXs;
286 typedef typename MathBase::MatrixXs MatrixXs;
287
288 /**
289 * @brief Initialized a multi-impulse data
290 *
291 * @param[in] model Multi-impulse model
292 * @param[in] data Pinocchio data
293 */
294 template <template <typename Scalar> class Model>
295 4281 ImpulseDataMultipleTpl(Model<Scalar>* const model,
296 pinocchio::DataTpl<Scalar>* const data)
297
2/4
✓ Branch 4 taken 4270 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4270 times.
✗ Branch 8 not taken.
4281 : Jc(model->get_nc_total(), model->get_state()->get_nv()),
298
4/8
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4270 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 4270 times.
✗ Branch 12 not taken.
4281 dv0_dq(model->get_nc_total(), model->get_state()->get_nv()),
299
3/6
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4270 times.
✗ Branch 9 not taken.
4281 vnext(model->get_state()->get_nv()),
300
5/10
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4270 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4270 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 4270 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 4270 times.
✗ Branch 16 not taken.
4281 dvnext_dx(model->get_state()->get_nv(), model->get_state()->get_ndx()),
301
4/8
✓ Branch 2 taken 4270 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4270 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4270 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 4270 times.
✗ Branch 14 not taken.
4281 fext(model->get_state()->get_pinocchio()->njoints,
302 4281 pinocchio::ForceTpl<Scalar>::Zero()) {
303
1/2
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
4281 Jc.setZero();
304
1/2
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
4281 dv0_dq.setZero();
305
1/2
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
4281 vnext.setZero();
306
1/2
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
4281 dvnext_dx.setZero();
307 4281 for (typename ImpulseModelMultiple::ImpulseModelContainer::const_iterator
308
1/2
✓ Branch 1 taken 4270 times.
✗ Branch 2 not taken.
4281 it = model->get_impulses().begin();
309
3/4
✓ Branch 1 taken 14501 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10231 times.
✓ Branch 6 taken 4270 times.
14524 it != model->get_impulses().end(); ++it) {
310 10243 const std::shared_ptr<ImpulseItem>& item = it->second;
311
1/2
✓ Branch 1 taken 10231 times.
✗ Branch 2 not taken.
10243 impulses.insert(
312
2/4
✓ Branch 3 taken 10231 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 10231 times.
✗ Branch 8 not taken.
10243 std::make_pair(item->name, item->impulse->createData(data)));
313 }
314 4281 }
315
316 MatrixXs Jc; //!< Contact Jacobian in frame coordinate
317 //!< \f$\mathbf{J}_c\in\mathbb{R}^{ni_{total}\times{nv}}\f$
318 //!< (memory defined for active and inactive impulses)
319 MatrixXs
320 dv0_dq; //!< Jacobian of the desired spatial contact acceleration in
321 //!< frame coordinate
322 //!< \f$\frac{\partial\underline{\mathbf{v}}_0}{\partial\mathbf{q}}\in\mathbb{R}^{ni_{total}\times{nv}}\f$
323 //!< (memory defined for active and inactive impulse)
324 VectorXs vnext; //!< Constrained system velocity after impact in generalized
325 //!< coordinates \f$\dot{\mathbf{v}'}\in\mathbb{R}^{nv}\f$
326 MatrixXs
327 dvnext_dx; //!< Jacobian of the system velocity after impact in
328 //!< generalized coordinates
329 //!< \f$\frac{\partial\dot{\mathbf{v}'}}{\partial\mathbf{x}}\in\mathbb{R}^{nv\times
330 //!< ndx}\f$
331 typename ImpulseModelMultiple::ImpulseDataContainer
332 impulses; //!< Stack of impulse data
333 pinocchio::container::aligned_vector<pinocchio::ForceTpl<Scalar> >
334 fext; //!< External spatial forces in body coordinates
335 };
336
337 } // namespace crocoddyl
338
339 /* --- Details -------------------------------------------------------------- */
340 /* --- Details -------------------------------------------------------------- */
341 /* --- Details -------------------------------------------------------------- */
342 #include "crocoddyl/multibody/impulses/multiple-impulses.hxx"
343
344 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(crocoddyl::ImpulseItemTpl)
345 CROCODDYL_DECLARE_EXTERN_TEMPLATE_CLASS(crocoddyl::ImpulseModelMultipleTpl)
346 CROCODDYL_DECLARE_EXTERN_TEMPLATE_STRUCT(crocoddyl::ImpulseDataMultipleTpl)
347
348 #endif // CROCODDYL_MULTIBODY_IMPULSES_MULTIPLE_IMPULSES_HPP_
349