Directory: | ./ |
---|---|
File: | include/pinocchio/algorithm/constraints/coulomb-friction-cone.hpp |
Date: | 2025-02-12 21:03:38 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 74 | 92 | 80.4% |
Branches: | 64 | 162 | 39.5% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2022 INRIA | ||
3 | // | ||
4 | |||
5 | #ifndef __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__ | ||
6 | #define __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__ | ||
7 | |||
8 | #include "pinocchio/algorithm/constraints/fwd.hpp" | ||
9 | #include "pinocchio/math/fwd.hpp" | ||
10 | #include "pinocchio/math/comparison-operators.hpp" | ||
11 | |||
12 | namespace pinocchio | ||
13 | { | ||
14 | |||
15 | template<typename Scalar> | ||
16 | struct DualCoulombFrictionConeTpl; | ||
17 | |||
18 | /// \brief 3d Coulomb friction cone. | ||
19 | template<typename _Scalar> | ||
20 | struct CoulombFrictionConeTpl | ||
21 | { | ||
22 | typedef _Scalar Scalar; | ||
23 | typedef DualCoulombFrictionConeTpl<Scalar> DualCone; | ||
24 | typedef Eigen::Matrix<Scalar, 3, 1> Vector3; | ||
25 | |||
26 | /// \brief Default constructor | ||
27 | /// | ||
28 | /// \param[in] mu Friction coefficient | ||
29 | 15 | explicit CoulombFrictionConeTpl(const Scalar mu) | |
30 | 15 | : mu(mu) | |
31 | { | ||
32 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | assert(mu >= 0 && "mu must be positive"); |
33 | 15 | } | |
34 | |||
35 | /// \brief Copy constructor. | ||
36 | CoulombFrictionConeTpl(const CoulombFrictionConeTpl & other) = default; | ||
37 | |||
38 | /// \brief Copy operator | ||
39 | CoulombFrictionConeTpl & operator=(const CoulombFrictionConeTpl & other) = default; | ||
40 | |||
41 | /// \brief Comparison operator | ||
42 | ✗ | bool operator==(const CoulombFrictionConeTpl & other) const | |
43 | { | ||
44 | ✗ | return mu == other.mu; | |
45 | } | ||
46 | |||
47 | /// \brief Difference operator | ||
48 | ✗ | bool operator!=(const CoulombFrictionConeTpl & other) const | |
49 | { | ||
50 | ✗ | return !(*this == other); | |
51 | } | ||
52 | |||
53 | /// \brief Check whether a vector x lies within the cone. | ||
54 | /// | ||
55 | /// \param[in] f vector to check (assimilated to a force vector). | ||
56 | /// | ||
57 | template<typename Vector3Like> | ||
58 | 800002 | bool isInside(const Eigen::MatrixBase<Vector3Like> & f, const Scalar prec = Scalar(0)) const | |
59 | { | ||
60 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 400001 times.
|
800002 | assert(mu >= 0 && "mu must be positive"); |
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 400001 times.
|
800002 | assert(prec >= 0 && "prec should be positive"); |
62 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
63 |
2/4✓ Branch 2 taken 400001 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 400001 times.
✗ Branch 6 not taken.
|
800002 | return f.template head<2>().norm() <= mu * f[2] + prec; |
64 | } | ||
65 | |||
66 | /// \brief Project a vector x onto the cone. | ||
67 | /// | ||
68 | /// \param[in] x a 3d vector to project. | ||
69 | /// | ||
70 | template<typename Vector3Like> | ||
71 | typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) | ||
72 | 400010 | project(const Eigen::MatrixBase<Vector3Like> & x) const | |
73 | { | ||
74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200009 times.
|
400010 | assert(mu >= 0 && "mu must be positive"); |
75 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
76 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain; | ||
77 |
1/2✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
|
400010 | const Scalar & z = x[2]; |
78 | 400010 | const Scalar mu_z = mu * z; | |
79 | |||
80 |
2/4✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 200009 times.
✗ Branch 5 not taken.
|
400010 | const Eigen::Matrix<Scalar, 2, 1> t = x.template head<2>(); |
81 |
1/2✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
|
400010 | const Scalar t_norm = t.norm(); |
82 | |||
83 |
2/2✓ Branch 0 taken 69179 times.
✓ Branch 1 taken 130830 times.
|
400010 | if (mu * t_norm <= -z) |
84 |
2/4✓ Branch 1 taken 69179 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69179 times.
✗ Branch 5 not taken.
|
138350 | return Vector3Plain::Zero(); |
85 |
2/2✓ Branch 0 taken 54212 times.
✓ Branch 1 taken 76618 times.
|
261660 | else if (t_norm <= mu_z) |
86 | { | ||
87 |
1/2✓ Branch 1 taken 54212 times.
✗ Branch 2 not taken.
|
108424 | return x; |
88 | } | ||
89 | else | ||
90 | { | ||
91 |
1/2✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
|
153236 | Vector3Plain res; |
92 |
3/6✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76618 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 76618 times.
✗ Branch 8 not taken.
|
153236 | res.template head<2>() = (mu / t_norm) * t; |
93 |
1/2✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
|
153236 | res[2] = 1; |
94 |
1/2✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
|
153236 | res.normalize(); |
95 |
1/2✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
|
153236 | const Scalar scale = x.dot(res); |
96 |
1/2✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
|
153236 | res *= scale; |
97 | 153236 | return res; | |
98 | } | ||
99 | } | ||
100 | |||
101 | /// \brief Project a vector x onto the cone with a matric specified by the diagonal matrix R. | ||
102 | /// | ||
103 | /// \param[in] x a 3d vector to project. | ||
104 | /// \param[in] R a 3d vector representing the diagonal of the weights matrix. The tangential | ||
105 | /// components (the first two) of R should be equal. | ||
106 | /// | ||
107 | template<typename Vector3Like> | ||
108 | 8 | typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) weightedProject( | |
109 | const Eigen::MatrixBase<Vector3Like> & x, const Eigen::MatrixBase<Vector3Like> & R) const | ||
110 | { | ||
111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | assert(mu >= 0 && "mu must be positive"); |
112 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
113 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain; | ||
114 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | assert(R(2) > 0 && "R(2) must be strictly positive"); |
115 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | Scalar weighted_mu = mu * math::sqrt(R(0) / R(2)); |
116 | 8 | CoulombFrictionConeTpl weighted_cone(weighted_mu); | |
117 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | Vector3Plain R_sqrt = R.cwiseSqrt(); |
118 |
5/10✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
|
8 | Vector3Plain R_sqrt_times_x = (R_sqrt.array() * x.array()).matrix(); |
119 |
6/12✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
|
8 | Vector3Plain res = (weighted_cone.project(R_sqrt_times_x).array() / R_sqrt.array()).matrix(); |
120 | 16 | return res; | |
121 | } | ||
122 | |||
123 | /// \brief Compute the complementary shift associted to the Coulomb friction cone for | ||
124 | /// complementarity satisfaction in complementary problems. | ||
125 | /// | ||
126 | /// \param[in] v a dual vector. | ||
127 | /// | ||
128 | template<typename Vector3Like> | ||
129 | typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) | ||
130 | 8 | computeNormalCorrection(const Eigen::MatrixBase<Vector3Like> & v) const | |
131 | { | ||
132 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
133 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain; | ||
134 | |||
135 | 8 | Vector3Plain res; | |
136 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
8 | res.template head<2>().setZero(); |
137 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
8 | res[2] = mu * v.template head<2>().norm(); |
138 | |||
139 | 8 | return res; | |
140 | } | ||
141 | |||
142 | /// \brief Compute the radial projection associted to the Coulomb friction cone. | ||
143 | /// | ||
144 | /// \param[in] f a force vector. | ||
145 | /// | ||
146 | template<typename Vector3Like> | ||
147 | typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) | ||
148 | 200000 | computeRadialProjection(const Eigen::MatrixBase<Vector3Like> & f) const | |
149 | { | ||
150 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
151 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain; | ||
152 | |||
153 |
1/2✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
|
200000 | Vector3Plain res; |
154 |
1/2✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
|
200000 | const auto & ft = f.template head<2>(); |
155 |
1/2✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
|
200000 | const Scalar ft_norm = ft.norm(); |
156 | |||
157 |
3/6✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 200000 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 200000 times.
✗ Branch 8 not taken.
|
200000 | res[2] = math::max(Scalar(0), f[2]); |
158 |
1/2✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
|
200000 | const Scalar mu_fz = mu * res[2]; |
159 |
2/2✓ Branch 0 taken 107170 times.
✓ Branch 1 taken 92830 times.
|
200000 | if (ft_norm > mu_fz) |
160 | { | ||
161 |
3/6✓ Branch 1 taken 107170 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 107170 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 107170 times.
✗ Branch 8 not taken.
|
107170 | res.template head<2>() = Scalar(mu_fz / ft_norm) * ft; |
162 | } | ||
163 | else | ||
164 |
2/4✓ Branch 1 taken 92830 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 92830 times.
✗ Branch 5 not taken.
|
92830 | res.template head<2>() = ft; |
165 | |||
166 | 400000 | return res; | |
167 | } | ||
168 | |||
169 | template<typename Vector3Like1, typename Vector3Like2> | ||
170 | ✗ | Scalar computeContactComplementarity( | |
171 | const Eigen::MatrixBase<Vector3Like1> & v, const Eigen::MatrixBase<Vector3Like2> & f) const | ||
172 | { | ||
173 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like1) Vector3Plain; | ||
174 | ✗ | return math::fabs(f.dot(Vector3Plain(v + computeNormalCorrection(v)))); | |
175 | } | ||
176 | |||
177 | template<typename Vector3Like1, typename Vector3Like2> | ||
178 | ✗ | Scalar computeConicComplementarity( | |
179 | const Eigen::MatrixBase<Vector3Like1> & v, const Eigen::MatrixBase<Vector3Like2> & f) const | ||
180 | { | ||
181 | ✗ | return math::fabs(f.dot(v)); | |
182 | } | ||
183 | |||
184 | /// \brief Returns the dual cone associated to this. | ||
185 | 1 | DualCone dual() const | |
186 | { | ||
187 | 1 | return DualCone(mu); | |
188 | } | ||
189 | |||
190 | /// \brief Returns the dimension of the cone. | ||
191 | ✗ | static int dim() | |
192 | { | ||
193 | ✗ | return 3; | |
194 | } | ||
195 | |||
196 | /// \var Friction coefficient | ||
197 | Scalar mu; | ||
198 | }; // CoulombFrictionConeTpl | ||
199 | |||
200 | /// \brief Dual of the 3d Coulomb friction cone. | ||
201 | template<typename _Scalar> | ||
202 | struct DualCoulombFrictionConeTpl | ||
203 | { | ||
204 | typedef _Scalar Scalar; | ||
205 | typedef CoulombFrictionConeTpl<Scalar> DualCone; | ||
206 | |||
207 | /// \brief Default constructor | ||
208 | /// | ||
209 | /// \param[in] mu Friction coefficient | ||
210 | 1 | explicit DualCoulombFrictionConeTpl(const Scalar mu) | |
211 | 1 | : mu(mu) | |
212 | { | ||
213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(mu >= 0 && "mu must be positive"); |
214 | 1 | } | |
215 | |||
216 | /// \brief Copy constructor. | ||
217 | DualCoulombFrictionConeTpl(const DualCoulombFrictionConeTpl & other) = default; | ||
218 | |||
219 | /// \brief Copy operator | ||
220 | DualCoulombFrictionConeTpl & operator=(const DualCoulombFrictionConeTpl & other) = default; | ||
221 | |||
222 | /// \brief Comparison operator | ||
223 | ✗ | bool operator==(const DualCoulombFrictionConeTpl & other) const | |
224 | { | ||
225 | ✗ | return mu == other.mu; | |
226 | } | ||
227 | |||
228 | /// \brief Difference operator | ||
229 | ✗ | bool operator!=(const DualCoulombFrictionConeTpl & other) const | |
230 | { | ||
231 | ✗ | return !(*this == other); | |
232 | } | ||
233 | |||
234 | /// \brief Check whether a vector v lies within the cone. | ||
235 | /// | ||
236 | /// \param[in] v vector to check (assimilated to a linear velocity). | ||
237 | /// | ||
238 | template<typename Vector3Like> | ||
239 | 600002 | bool isInside(const Eigen::MatrixBase<Vector3Like> & v, const Scalar prec = Scalar(0)) const | |
240 | { | ||
241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 300001 times.
|
600002 | assert(mu >= 0 && "mu must be positive"); |
242 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
243 |
2/4✓ Branch 2 taken 300001 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 300001 times.
✗ Branch 6 not taken.
|
600002 | return mu * v.template head<2>().norm() <= v[2] + prec; |
244 | } | ||
245 | |||
246 | /// \brief Project a vector x onto the cone | ||
247 | template<typename Vector3Like> | ||
248 | typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) | ||
249 | 200001 | project(const Eigen::MatrixBase<Vector3Like> & x) const | |
250 | { | ||
251 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
200001 | assert(mu >= 0 && "mu must be positive"); |
252 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3); | ||
253 | typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain; | ||
254 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
200001 | const Scalar & z = x[2]; |
255 | |||
256 |
0/4✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
200001 | const Eigen::Matrix<Scalar, 2, 1> t = x.template head<2>(); |
257 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
200001 | const Scalar t_norm = t.norm(); |
258 | |||
259 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
200001 | if (t_norm <= -mu * z) |
260 |
0/4✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4045 | return Vector3Plain::Zero(); |
261 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
195956 | else if (mu * t_norm <= z) |
262 | { | ||
263 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
116606 | return x; |
264 | } | ||
265 | else | ||
266 | { | ||
267 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
79350 | Vector3Plain res; |
268 |
0/4✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
79350 | res.template head<2>() = t; |
269 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
79350 | res[2] = mu * t_norm; |
270 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
79350 | res.normalize(); |
271 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
79350 | const Scalar scale = x.dot(res); |
272 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
79350 | res *= scale; |
273 | 79350 | return res; | |
274 | } | ||
275 | } | ||
276 | |||
277 | /// \brief Returns the dimension of the cone. | ||
278 | ✗ | static int dim() | |
279 | { | ||
280 | ✗ | return 3; | |
281 | } | ||
282 | |||
283 | /// \brief Returns the dual cone associated to this. /// | ||
284 | ✗ | DualCone dual() const | |
285 | { | ||
286 | ✗ | return DualCone(mu); | |
287 | } | ||
288 | |||
289 | /// \var Friction coefficient | ||
290 | Scalar mu; | ||
291 | |||
292 | }; // DualCoulombFrictionConeTpl | ||
293 | |||
294 | } // namespace pinocchio | ||
295 | |||
296 | #endif // ifndef __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__ | ||
297 |