Line |
Branch |
Exec |
Source |
1 |
|
|
// Copyright (c) 2016, Joseph Mirabel |
2 |
|
|
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr) |
3 |
|
|
// |
4 |
|
|
|
5 |
|
|
// Redistribution and use in source and binary forms, with or without |
6 |
|
|
// modification, are permitted provided that the following conditions are |
7 |
|
|
// met: |
8 |
|
|
// |
9 |
|
|
// 1. Redistributions of source code must retain the above copyright |
10 |
|
|
// notice, this list of conditions and the following disclaimer. |
11 |
|
|
// |
12 |
|
|
// 2. Redistributions in binary form must reproduce the above copyright |
13 |
|
|
// notice, this list of conditions and the following disclaimer in the |
14 |
|
|
// documentation and/or other materials provided with the distribution. |
15 |
|
|
// |
16 |
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 |
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 |
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 |
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 |
|
|
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 |
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 |
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 |
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 |
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 |
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 |
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
27 |
|
|
// DAMAGE. |
28 |
|
|
|
29 |
|
|
#include <array> |
30 |
|
|
#include <boost/regex.hpp> |
31 |
|
|
#include <hpp/constraints/differentiable-function.hh> |
32 |
|
|
#include <hpp/constraints/locked-joint.hh> |
33 |
|
|
#include <hpp/manipulation/graph/edge.hh> |
34 |
|
|
#include <hpp/manipulation/graph/guided-state-selector.hh> |
35 |
|
|
#include <hpp/manipulation/graph/helper.hh> |
36 |
|
|
#include <hpp/manipulation/graph/state-selector.hh> |
37 |
|
|
#include <hpp/manipulation/graph/state.hh> |
38 |
|
|
#include <hpp/manipulation/handle.hh> |
39 |
|
|
#include <hpp/manipulation/problem-solver.hh> |
40 |
|
|
#include <hpp/pinocchio/gripper.hh> |
41 |
|
|
#include <hpp/util/debug.hh> |
42 |
|
|
#include <iterator> |
43 |
|
|
#include <pinocchio/multibody/model.hpp> |
44 |
|
|
#include <unordered_map> |
45 |
|
|
#include <unordered_set> |
46 |
|
|
|
47 |
|
|
#define CASE_TO_STRING(var, value) \ |
48 |
|
|
((var & value) ? std::string(#value) : std::string()) |
49 |
|
|
|
50 |
|
|
namespace hpp { |
51 |
|
|
namespace manipulation { |
52 |
|
|
namespace graph { |
53 |
|
|
namespace helper { |
54 |
|
|
typedef constraints::Implicit Implicit; |
55 |
|
|
typedef constraints::ImplicitPtr_t ImplicitPtr_t; |
56 |
|
|
|
57 |
|
|
template <bool forPath> |
58 |
|
✗ |
void addToComp(const NumericalConstraints_t& nc, GraphComponentPtr_t comp) { |
59 |
|
✗ |
if (nc.empty()) return; |
60 |
|
✗ |
StatePtr_t n; |
61 |
|
|
if (forPath) { |
62 |
|
|
n = HPP_DYNAMIC_PTR_CAST(State, comp); |
63 |
|
|
if (!n) throw std::logic_error("Wrong type: expect a State"); |
64 |
|
|
} |
65 |
|
✗ |
for (const auto& c : nc) |
66 |
|
✗ |
if (c) { |
67 |
|
|
if (forPath) |
68 |
|
|
n->addNumericalConstraintForPath(c); |
69 |
|
|
else |
70 |
|
✗ |
comp->addNumericalConstraint(c); |
71 |
|
|
} |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
template <bool param> |
75 |
|
|
void specifyFoliation(const NumericalConstraints_t& nc, LevelSetEdgePtr_t lse) { |
76 |
|
|
for (const auto& c : nc) |
77 |
|
|
if (c) { |
78 |
|
|
if (param) |
79 |
|
|
lse->insertParamConstraint(c); |
80 |
|
|
else |
81 |
|
|
lse->insertConditionConstraint(c); |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
|
85 |
|
✗ |
void FoliatedManifold::addToState(StatePtr_t comp) const { |
86 |
|
✗ |
addToComp<false>(nc, comp); |
87 |
|
✗ |
addToComp<false>(nc_path, comp); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
✗ |
void FoliatedManifold::addToEdge(EdgePtr_t comp) const { |
91 |
|
✗ |
addToComp<false>(nc_fol, comp); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
✗ |
void FoliatedManifold::specifyFoliation(LevelSetEdgePtr_t lse) const { |
95 |
|
✗ |
for (const auto& c : nc) lse->insertConditionConstraint(c); |
96 |
|
✗ |
for (const auto& c : nc_fol) lse->insertConditionConstraint(c); |
97 |
|
|
} |
98 |
|
|
|
99 |
|
|
namespace { |
100 |
|
|
template <int gCase> |
101 |
|
|
struct CaseTraits { |
102 |
|
|
static const bool pregrasp = (gCase & WithPreGrasp); |
103 |
|
|
static const bool preplace = (gCase & WithPrePlace); |
104 |
|
|
static const bool intersec = !((gCase & NoGrasp) || (gCase & NoPlace)); |
105 |
|
|
|
106 |
|
|
static const bool valid = |
107 |
|
|
((gCase & WithPreGrasp) || (gCase & GraspOnly) || (gCase & NoGrasp)) && |
108 |
|
|
((gCase & WithPrePlace) || (gCase & PlaceOnly) || (gCase & NoPlace)) && |
109 |
|
|
!((gCase & NoGrasp) && (gCase & NoPlace)); |
110 |
|
|
|
111 |
|
|
static const std::size_t nbWaypoints = |
112 |
|
|
(pregrasp ? 1 : 0) + (intersec ? 1 : 0) + (preplace ? 1 : 0); |
113 |
|
|
static const std::size_t Nstates = 2 + nbWaypoints; |
114 |
|
|
static const std::size_t Nedges = 1 + nbWaypoints; |
115 |
|
|
// static const std::size_t iNpregrasp = pregrasp?1 + 1:nbWaypoints; |
116 |
|
|
// static const std::size_t iNpreplace = pregrasp?1 + 1:nbWaypoints; |
117 |
|
|
typedef std::array<StatePtr_t, Nstates> StateArray; |
118 |
|
|
typedef std::array<EdgePtr_t, Nedges> EdgeArray; |
119 |
|
|
|
120 |
|
✗ |
static inline const StatePtr_t& Npregrasp(const StateArray& n) { |
121 |
|
|
assert(pregrasp); |
122 |
|
✗ |
return n[1]; |
123 |
|
|
} |
124 |
|
✗ |
static inline const StatePtr_t& Nintersec(const StateArray& n) { |
125 |
|
|
assert(intersec); |
126 |
|
✗ |
return n[1 + (pregrasp ? 1 : 0)]; |
127 |
|
|
} |
128 |
|
✗ |
static inline const StatePtr_t& Npreplace(const StateArray& n) { |
129 |
|
|
assert(preplace); |
130 |
|
✗ |
return n[1 + (pregrasp ? 1 : 0) + (intersec ? 1 : 0)]; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
static inline std::string caseToString() { |
134 |
|
|
return CASE_TO_STRING(gCase, NoGrasp) + CASE_TO_STRING(gCase, GraspOnly) + |
135 |
|
|
CASE_TO_STRING(gCase, WithPreGrasp) + " - " + |
136 |
|
|
CASE_TO_STRING(gCase, NoPlace) + CASE_TO_STRING(gCase, PlaceOnly) + |
137 |
|
|
CASE_TO_STRING(gCase, WithPrePlace); |
138 |
|
|
} |
139 |
|
|
|
140 |
|
✗ |
static inline EdgePtr_t makeWE(const std::string& name, |
141 |
|
|
const StatePtr_t& from, const StatePtr_t& to, |
142 |
|
|
const size_type& w) { |
143 |
|
|
if (Nedges > 1) { |
144 |
|
✗ |
WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>( |
145 |
|
|
from->linkTo(name, to, w, WaypointEdge::create)); |
146 |
|
✗ |
we->nbWaypoints(nbWaypoints); |
147 |
|
✗ |
return we; |
148 |
|
✗ |
} else |
149 |
|
✗ |
return from->linkTo(name, to, w, Edge::create); |
150 |
|
|
} |
151 |
|
|
|
152 |
|
✗ |
static inline StateArray makeWaypoints(const StatePtr_t& from, |
153 |
|
|
const StatePtr_t& to, |
154 |
|
|
const std::string& name) { |
155 |
|
✗ |
StateSelectorPtr_t ns = from->parentGraph()->stateSelector(); |
156 |
|
✗ |
StateArray states; |
157 |
|
✗ |
std::size_t r = 0; |
158 |
|
✗ |
states[r] = from; |
159 |
|
✗ |
++r; |
160 |
|
|
if (pregrasp) { |
161 |
|
✗ |
states[r] = ns->createState(name + "_pregrasp", true); |
162 |
|
✗ |
++r; |
163 |
|
|
} |
164 |
|
|
if (intersec) { |
165 |
|
✗ |
states[r] = ns->createState(name + "_intersec", true); |
166 |
|
✗ |
++r; |
167 |
|
|
} |
168 |
|
|
if (preplace) { |
169 |
|
✗ |
states[r] = ns->createState(name + "_preplace", true); |
170 |
|
✗ |
++r; |
171 |
|
|
} |
172 |
|
✗ |
states[r] = to; |
173 |
|
✗ |
return states; |
174 |
|
|
} |
175 |
|
|
|
176 |
|
✗ |
static inline EdgePtr_t makeLSEgrasp(const std::string& name, |
177 |
|
|
const StateArray& n, const EdgeArray& e, |
178 |
|
|
const size_type w, |
179 |
|
|
LevelSetEdgePtr_t& gls) { |
180 |
|
|
if (Nedges > 1) { |
181 |
|
✗ |
const std::size_t T = (pregrasp ? 1 : 0) + (intersec ? 1 : 0); |
182 |
|
✗ |
WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>( |
183 |
|
✗ |
n.front()->linkTo(name + "_ls", n.back(), w, WaypointEdge::create)); |
184 |
|
✗ |
we->nbWaypoints(nbWaypoints); |
185 |
|
✗ |
gls = linkWaypoint<LevelSetEdge>(n, T - 1, T, name, "ls"); |
186 |
|
✗ |
for (std::size_t i = 0; i < Nedges; ++i) |
187 |
|
✗ |
we->setWaypoint(i, e[i], n[i + 1]); |
188 |
|
✗ |
we->setWaypoint(T - 1, gls, n[T]); |
189 |
|
✗ |
gls->state(n.front()); |
190 |
|
✗ |
gls->setShort(pregrasp); |
191 |
|
✗ |
return we; |
192 |
|
✗ |
} else { |
193 |
|
|
assert(gCase == (GraspOnly | NoPlace) && |
194 |
|
|
"Cannot implement a LevelSetEdge for grasping"); |
195 |
|
✗ |
gls = static_pointer_cast<LevelSetEdge>( |
196 |
|
✗ |
n.front()->linkTo(name + "_ls", n.back(), w, LevelSetEdge::create)); |
197 |
|
✗ |
return gls; |
198 |
|
|
} |
199 |
|
|
} |
200 |
|
|
|
201 |
|
✗ |
static inline EdgePtr_t makeLSEplace(const std::string& name, |
202 |
|
|
const StateArray& n, const EdgeArray& e, |
203 |
|
|
const size_type w, |
204 |
|
|
LevelSetEdgePtr_t& pls) { |
205 |
|
|
if (Nedges > 1) { |
206 |
|
✗ |
const std::size_t T = (pregrasp ? 1 : 0) + (intersec ? 1 : 0); |
207 |
|
✗ |
WaypointEdgePtr_t we = static_pointer_cast<WaypointEdge>( |
208 |
|
✗ |
n.back()->linkTo(name + "_ls", n.front(), w, WaypointEdge::create)); |
209 |
|
✗ |
we->nbWaypoints(nbWaypoints); |
210 |
|
✗ |
pls = linkWaypoint<LevelSetEdge>(n, T + 1, T, name, "ls"); |
211 |
|
|
// for (std::size_t i = Nedges - 1; i != 0; --i) |
212 |
|
✗ |
for (std::size_t k = 0; k < Nedges; ++k) { |
213 |
|
✗ |
std::size_t i = Nedges - 1 - k; |
214 |
|
✗ |
we->setWaypoint(Nedges - 1 - i, e[i], n[i]); |
215 |
|
|
} |
216 |
|
✗ |
we->setWaypoint(Nedges - 1 - T, pls, n[T]); |
217 |
|
✗ |
pls->state(n.back()); |
218 |
|
✗ |
pls->setShort(preplace); |
219 |
|
✗ |
return we; |
220 |
|
✗ |
} else { |
221 |
|
✗ |
assert(gCase == (NoGrasp | PlaceOnly) && |
222 |
|
|
"Cannot implement a LevelSetEdge for placement"); |
223 |
|
|
pls = static_pointer_cast<LevelSetEdge>( |
224 |
|
|
n.back()->linkTo(name + "_ls", n.front(), w, LevelSetEdge::create)); |
225 |
|
|
return pls; |
226 |
|
|
} |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
template <typename EdgeType> |
230 |
|
✗ |
static inline shared_ptr<EdgeType> linkWaypoint( |
231 |
|
|
const StateArray& states, const std::size_t& iF, const std::size_t& iT, |
232 |
|
|
const std::string& prefix, const std::string& suffix = "") { |
233 |
|
✗ |
std::stringstream ss; |
234 |
|
✗ |
ss << prefix << "_" << iF << iT; |
235 |
|
✗ |
if (suffix.length() > 0) ss << "_" << suffix; |
236 |
|
|
return static_pointer_cast<EdgeType>( |
237 |
|
✗ |
states[iF]->linkTo(ss.str(), states[iT], -1, EdgeType::create)); |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
template <bool forward> |
241 |
|
✗ |
static inline EdgeArray linkWaypoints(const StateArray& states, |
242 |
|
|
const EdgePtr_t& edge, |
243 |
|
|
const std::string& name) { |
244 |
|
✗ |
EdgeArray e; |
245 |
|
✗ |
WaypointEdgePtr_t we = HPP_DYNAMIC_PTR_CAST(WaypointEdge, edge); |
246 |
|
|
if (forward) |
247 |
|
✗ |
for (std::size_t i = 0; i < Nedges; ++i) { |
248 |
|
✗ |
e[i] = linkWaypoint<Edge>(states, i, i + 1, name); |
249 |
|
✗ |
we->setWaypoint(i, e[i], states[i + 1]); |
250 |
|
|
} |
251 |
|
|
else |
252 |
|
|
// for (std::size_t i = Nedges - 1; i != 0; --i) { |
253 |
|
✗ |
for (std::size_t k = 0; k < Nedges; ++k) { |
254 |
|
✗ |
std::size_t i = Nedges - 1 - k; |
255 |
|
✗ |
e[i] = linkWaypoint<Edge>(states, i + 1, i, name); |
256 |
|
✗ |
we->setWaypoint(Nedges - 1 - i, e[i], states[i]); |
257 |
|
|
} |
258 |
|
✗ |
return e; |
259 |
|
|
} |
260 |
|
|
|
261 |
|
✗ |
static inline void setStateConstraints(const StateArray& n, |
262 |
|
|
const FoliatedManifold& g, |
263 |
|
|
const FoliatedManifold& pg, |
264 |
|
|
const FoliatedManifold& p, |
265 |
|
|
const FoliatedManifold& pp, |
266 |
|
|
const FoliatedManifold& m) { |
267 |
|
|
// From and to are not populated automatically |
268 |
|
|
// to avoid duplicates. |
269 |
|
|
if (pregrasp) { |
270 |
|
✗ |
p.addToState(Npregrasp(n)); |
271 |
|
✗ |
pg.addToState(Npregrasp(n)); |
272 |
|
✗ |
m.addToState(Npregrasp(n)); |
273 |
|
|
} |
274 |
|
|
if (intersec) { |
275 |
|
✗ |
p.addToState(Nintersec(n)); |
276 |
|
✗ |
g.addToState(Nintersec(n)); |
277 |
|
✗ |
m.addToState(Nintersec(n)); |
278 |
|
|
} |
279 |
|
|
if (preplace) { |
280 |
|
✗ |
pp.addToState(Npreplace(n)); |
281 |
|
✗ |
g.addToState(Npreplace(n)); |
282 |
|
✗ |
m.addToState(Npreplace(n)); |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
|
|
286 |
|
✗ |
static inline void setEdgeConstraints(const EdgeArray& e, |
287 |
|
|
const FoliatedManifold& g, |
288 |
|
|
const FoliatedManifold& p, |
289 |
|
|
const FoliatedManifold& m) { |
290 |
|
|
// The border B |
291 |
|
✗ |
const std::size_t B = (pregrasp ? 1 : 0) + (intersec ? 1 : 0); |
292 |
|
✗ |
for (std::size_t i = 0; i < B; ++i) p.addToEdge(e[i]); |
293 |
|
✗ |
for (std::size_t i = B; i < Nedges; ++i) g.addToEdge(e[i]); |
294 |
|
✗ |
for (std::size_t i = 0; i < Nedges; ++i) m.addToEdge(e[i]); |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
template <bool forward> |
298 |
|
✗ |
static inline void setEdgeProp(const EdgeArray& e, const StateArray& n) { |
299 |
|
|
/// Last is short |
300 |
|
✗ |
const std::size_t K = (forward ? 1 : 0); |
301 |
|
✗ |
for (std::size_t i = K; i < Nedges - 1 + K; ++i) e[i]->setShort(true); |
302 |
|
|
// The border B |
303 |
|
|
std::size_t B; |
304 |
|
|
if ((gCase & NoGrasp)) // There is no grasp |
305 |
|
|
B = 0; |
306 |
|
|
else // There is a grasp |
307 |
|
✗ |
B = 1 + (pregrasp ? 1 : 0); |
308 |
|
✗ |
for (std::size_t i = 0; i < B; ++i) e[i]->state(n[0]); |
309 |
|
✗ |
for (std::size_t i = B; i < Nedges; ++i) e[i]->state(n[Nstates - 1]); |
310 |
|
|
} |
311 |
|
|
}; |
312 |
|
|
} // namespace |
313 |
|
|
|
314 |
|
|
template <int gCase> |
315 |
|
✗ |
Edges_t createEdges(const std::string& forwName, const std::string& backName, |
316 |
|
|
const StatePtr_t& from, const StatePtr_t& to, |
317 |
|
|
const size_type& wForw, const size_type& wBack, |
318 |
|
|
const FoliatedManifold& grasp, |
319 |
|
|
const FoliatedManifold& pregrasp, |
320 |
|
|
const FoliatedManifold& place, |
321 |
|
|
const FoliatedManifold& preplace, const bool levelSetGrasp, |
322 |
|
|
const bool levelSetPlace, |
323 |
|
|
const FoliatedManifold& submanifoldDef) { |
324 |
|
|
typedef CaseTraits<gCase> T; |
325 |
|
|
hppDout(info, "Creating edges " << forwName << " and " << backName |
326 |
|
|
<< "\ncase is " << T::caseToString()); |
327 |
|
|
assert(T::valid && "Not a valid case."); |
328 |
|
|
typedef typename T::StateArray StateArray; |
329 |
|
|
typedef typename T::EdgeArray EdgeArray; |
330 |
|
|
|
331 |
|
|
// Create the edges |
332 |
|
✗ |
EdgePtr_t weForw = T::makeWE(forwName, from, to, wForw), |
333 |
|
✗ |
weBack = T::makeWE(backName, to, from, wBack), weForwLs, weBackLs; |
334 |
|
|
|
335 |
|
✗ |
std::string name = forwName; |
336 |
|
✗ |
StateArray n = T::makeWaypoints(from, to, name); |
337 |
|
|
|
338 |
|
✗ |
EdgeArray eF = T::template linkWaypoints<true>(n, weForw, name); |
339 |
|
|
|
340 |
|
|
// Set the states constraints |
341 |
|
|
// Note that submanifold is not taken into account for states |
342 |
|
|
// because the edges constraints will enforce configuration to stay |
343 |
|
|
// in a leaf, and so in the manifold itself. |
344 |
|
✗ |
T::setStateConstraints(n, grasp, pregrasp, place, preplace, submanifoldDef); |
345 |
|
|
|
346 |
|
|
// Set the edges properties |
347 |
|
✗ |
T::template setEdgeProp<true>(eF, n); |
348 |
|
|
|
349 |
|
|
// Set the edges constraints |
350 |
|
✗ |
T::setEdgeConstraints(eF, grasp, place, submanifoldDef); |
351 |
|
|
|
352 |
|
✗ |
LevelSetEdgePtr_t gls; |
353 |
|
✗ |
if (levelSetGrasp) weForwLs = T::makeLSEgrasp(name, n, eF, 10 * wForw, gls); |
354 |
|
|
|
355 |
|
|
// Populate bacward edge |
356 |
|
✗ |
name = backName; |
357 |
|
✗ |
EdgeArray eB = T::template linkWaypoints<false>(n, weBack, name); |
358 |
|
|
|
359 |
|
✗ |
T::template setEdgeProp<false>(eB, n); |
360 |
|
|
|
361 |
|
✗ |
T::setEdgeConstraints(eB, grasp, place, submanifoldDef); |
362 |
|
|
|
363 |
|
✗ |
LevelSetEdgePtr_t pls; |
364 |
|
✗ |
if (levelSetPlace) weBackLs = T::makeLSEplace(name, n, eB, 10 * wBack, pls); |
365 |
|
|
|
366 |
|
✗ |
Edges_t ret{weForw, weBack}; |
367 |
|
|
|
368 |
|
✗ |
if (levelSetPlace) { |
369 |
|
✗ |
if (!place.foliated()) { |
370 |
|
|
hppDout(warning, |
371 |
|
|
"You asked for a LevelSetEdge for placement, " |
372 |
|
|
"but did not specify the target foliation. " |
373 |
|
|
"It will have no effect"); |
374 |
|
|
} |
375 |
|
✗ |
grasp.addToEdge(pls); |
376 |
|
✗ |
place.specifyFoliation(pls); |
377 |
|
✗ |
submanifoldDef.addToEdge(pls); |
378 |
|
✗ |
pls->buildHistogram(); |
379 |
|
✗ |
place.addToEdge(weBackLs); |
380 |
|
✗ |
submanifoldDef.addToEdge(weBackLs); |
381 |
|
✗ |
ret.push_back(weBackLs); |
382 |
|
|
} |
383 |
|
✗ |
if (levelSetGrasp) { |
384 |
|
✗ |
if (!grasp.foliated()) { |
385 |
|
|
hppDout(warning, |
386 |
|
|
"You asked for a LevelSetEdge for grasping, " |
387 |
|
|
"but did not specify the target foliation. " |
388 |
|
|
"It will have no effect"); |
389 |
|
|
} |
390 |
|
✗ |
place.addToEdge(gls); |
391 |
|
✗ |
grasp.specifyFoliation(gls); |
392 |
|
✗ |
submanifoldDef.addToEdge(gls); |
393 |
|
✗ |
gls->buildHistogram(); |
394 |
|
✗ |
grasp.addToEdge(weForwLs); |
395 |
|
✗ |
submanifoldDef.addToEdge(weForwLs); |
396 |
|
✗ |
ret.push_back(weForwLs); |
397 |
|
|
} |
398 |
|
|
|
399 |
|
✗ |
return ret; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
✗ |
EdgePtr_t createLoopEdge(const std::string& loopName, const StatePtr_t& state, |
403 |
|
|
const size_type& w, const bool levelSet, |
404 |
|
|
const FoliatedManifold& submanifoldDef) { |
405 |
|
|
// Create the edges |
406 |
|
✗ |
EdgePtr_t loop; |
407 |
|
✗ |
if (levelSet) |
408 |
|
✗ |
loop = state->linkTo(loopName, state, w, LevelSetEdge::create); |
409 |
|
|
else |
410 |
|
✗ |
loop = state->linkTo(loopName, state, w, Edge::create); |
411 |
|
|
|
412 |
|
✗ |
loop->state(state); |
413 |
|
✗ |
submanifoldDef.addToEdge(loop); |
414 |
|
|
|
415 |
|
✗ |
if (levelSet) { |
416 |
|
✗ |
if (!submanifoldDef.foliated()) { |
417 |
|
|
hppDout(warning, |
418 |
|
|
"You asked for a LevelSetEdge for looping, " |
419 |
|
|
"but did not specify the target foliation. " |
420 |
|
|
"It will have no effect"); |
421 |
|
|
} |
422 |
|
✗ |
LevelSetEdgePtr_t ls = HPP_DYNAMIC_PTR_CAST(LevelSetEdge, loop); |
423 |
|
✗ |
submanifoldDef.specifyFoliation(ls); |
424 |
|
✗ |
ls->buildHistogram(); |
425 |
|
|
} |
426 |
|
|
|
427 |
|
✗ |
return loop; |
428 |
|
|
} |
429 |
|
|
|
430 |
|
✗ |
void graspManifold(const GripperPtr_t& gripper, const HandlePtr_t& handle, |
431 |
|
|
FoliatedManifold& grasp, FoliatedManifold& pregrasp) { |
432 |
|
✗ |
ImplicitPtr_t gc = handle->createGrasp(gripper, ""); |
433 |
|
✗ |
grasp.nc.push_back(gc); |
434 |
|
✗ |
grasp.nc_path.push_back(gc); |
435 |
|
✗ |
ImplicitPtr_t gcc = handle->createGraspComplement(gripper, ""); |
436 |
|
✗ |
if (gcc->function().outputSize() > 0) grasp.nc_fol.push_back(gcc); |
437 |
|
|
|
438 |
|
✗ |
const value_type c = handle->clearance() + gripper->clearance(); |
439 |
|
✗ |
ImplicitPtr_t pgc = handle->createPreGrasp(gripper, c, ""); |
440 |
|
✗ |
pregrasp.nc.push_back(pgc); |
441 |
|
✗ |
pregrasp.nc_path.push_back(pgc); |
442 |
|
|
} |
443 |
|
|
|
444 |
|
✗ |
void strictPlacementManifold(const ImplicitPtr_t placement, |
445 |
|
|
const ImplicitPtr_t preplacement, |
446 |
|
|
const ImplicitPtr_t placementComplement, |
447 |
|
|
FoliatedManifold& place, |
448 |
|
|
FoliatedManifold& preplace) { |
449 |
|
✗ |
place.nc.push_back(placement); |
450 |
|
✗ |
place.nc_path.push_back(placement); |
451 |
|
✗ |
if (placementComplement && placementComplement->function().outputSize() > 0) |
452 |
|
✗ |
place.nc_fol.push_back(placementComplement); |
453 |
|
|
|
454 |
|
✗ |
preplace.nc.push_back(preplacement); |
455 |
|
✗ |
preplace.nc_path.push_back(preplacement); |
456 |
|
|
} |
457 |
|
|
|
458 |
|
✗ |
void relaxedPlacementManifold(const ImplicitPtr_t placement, |
459 |
|
|
const ImplicitPtr_t preplacement, |
460 |
|
|
const LockedJoints_t objectLocks, |
461 |
|
|
FoliatedManifold& place, |
462 |
|
|
FoliatedManifold& preplace) { |
463 |
|
✗ |
if (placement) { |
464 |
|
✗ |
place.nc.push_back(placement); |
465 |
|
|
// The placement constraints are not required in the path, as long as |
466 |
|
|
// they are satisfied at both ends and the object does not move. The |
467 |
|
|
// former condition is ensured by the placement constraints on both |
468 |
|
|
// ends and the latter is ensure by the LockedJoint constraints. |
469 |
|
✗ |
place.nc_path.push_back(placement); |
470 |
|
|
} |
471 |
|
✗ |
std::copy(objectLocks.begin(), objectLocks.end(), |
472 |
|
✗ |
std::back_inserter(place.lj_fol)); |
473 |
|
|
|
474 |
|
✗ |
if (placement && preplacement) { |
475 |
|
✗ |
preplace.nc.push_back(preplacement); |
476 |
|
|
// preplace.nc_path.push_back (preplacement); |
477 |
|
|
} |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
namespace { |
481 |
|
|
typedef std::size_t index_t; |
482 |
|
|
typedef std::vector<index_t> IndexV_t; |
483 |
|
|
typedef std::list<index_t> IndexL_t; |
484 |
|
|
typedef std::pair<index_t, index_t> Grasp_t; |
485 |
|
|
typedef std::tuple<StatePtr_t, FoliatedManifold> StateAndManifold_t; |
486 |
|
|
// typedef std::vector <index_t, index_t> GraspV_t; |
487 |
|
|
/// GraspV_t corresponds to a unique ID of a permutation. |
488 |
|
|
/// - its size is the number of grippers, |
489 |
|
|
/// - the values correpond to the index of the handle (0..nbHandle-1), or |
490 |
|
|
/// nbHandle to mean no handle. |
491 |
|
|
typedef std::vector<index_t> GraspV_t; |
492 |
|
|
struct Result; |
493 |
|
|
struct CompiledRule { |
494 |
|
|
enum Status { Accept, Refuse, NoMatch, Undefined }; |
495 |
|
|
std::vector<boost::regex> handles; |
496 |
|
|
Status status; |
497 |
|
|
CompiledRule(const Result& res, const Rule& r); |
498 |
|
✗ |
Status check(const std::vector<std::string>& names, const GraspV_t& g) const { |
499 |
|
✗ |
const std::size_t nG = g.size(); |
500 |
|
✗ |
assert(nG == handles.size()); |
501 |
|
✗ |
for (std::size_t i = 0; i < nG; ++i) { |
502 |
|
✗ |
if (handles[i].empty()) continue; |
503 |
|
✗ |
if (!boost::regex_match(names[g[i]], handles[i])) return NoMatch; |
504 |
|
|
} |
505 |
|
✗ |
return status; |
506 |
|
|
} |
507 |
|
|
}; |
508 |
|
|
typedef std::vector<CompiledRule> CompiledRules_t; |
509 |
|
|
|
510 |
|
|
struct Result { |
511 |
|
|
ProblemSolverPtr_t ps; |
512 |
|
|
GraphPtr_t graph; |
513 |
|
|
typedef unsigned long stateid_type; |
514 |
|
|
std::unordered_map<stateid_type, StateAndManifold_t> states; |
515 |
|
|
typedef std::pair<stateid_type, stateid_type> edgeid_type; |
516 |
|
|
struct edgeid_hash { |
517 |
|
|
std::hash<edgeid_type::first_type> first; |
518 |
|
|
std::hash<edgeid_type::second_type> second; |
519 |
|
✗ |
std::size_t operator()(const edgeid_type& eid) const { |
520 |
|
✗ |
return first(eid.first) + second(eid.second); |
521 |
|
|
} |
522 |
|
|
}; |
523 |
|
|
std::unordered_set<edgeid_type, edgeid_hash> edges; |
524 |
|
|
std::vector<std::array<ImplicitPtr_t, 3> > graspCs; |
525 |
|
|
index_t nG, nOH; |
526 |
|
|
GraspV_t dims; |
527 |
|
|
const Grippers_t& gs; |
528 |
|
|
const Objects_t& ohs; |
529 |
|
|
std::vector<std::string> handleNames; |
530 |
|
|
CompiledRules_t rules; |
531 |
|
|
CompiledRule::Status defaultAcceptationPolicy; |
532 |
|
|
|
533 |
|
✗ |
Result(const ProblemSolverPtr_t problem, const Grippers_t& grippers, |
534 |
|
|
const Objects_t& objects, GraphPtr_t g) |
535 |
|
✗ |
: ps(problem), |
536 |
|
✗ |
graph(g), |
537 |
|
✗ |
nG(grippers.size()), |
538 |
|
✗ |
nOH(0), |
539 |
|
✗ |
gs(grippers), |
540 |
|
✗ |
ohs(objects), |
541 |
|
✗ |
defaultAcceptationPolicy(CompiledRule::Refuse) { |
542 |
|
✗ |
for (const Object_t& o : objects) { |
543 |
|
✗ |
nOH += std::get<1>(o).size(); |
544 |
|
✗ |
for (const HandlePtr_t& h : std::get<1>(o)) |
545 |
|
✗ |
handleNames.push_back(h->name()); |
546 |
|
|
} |
547 |
|
✗ |
handleNames.push_back(""); |
548 |
|
✗ |
dims.resize(nG); |
549 |
|
✗ |
dims[0] = nOH + 1; |
550 |
|
✗ |
for (index_t i = 1; i < nG; ++i) dims[i] = dims[i - 1] * (nOH + 1); |
551 |
|
✗ |
graspCs.resize(nG * nOH); |
552 |
|
|
} |
553 |
|
|
|
554 |
|
✗ |
void setRules(const Rules_t& r) { |
555 |
|
✗ |
for (Rules_t::const_iterator _r = r.begin(); _r != r.end(); ++_r) |
556 |
|
✗ |
rules.push_back(CompiledRule(*this, *_r)); |
557 |
|
|
} |
558 |
|
|
|
559 |
|
✗ |
bool graspIsAllowed(const GraspV_t& idxOH) const { |
560 |
|
✗ |
assert(idxOH.size() == nG); |
561 |
|
✗ |
for (std::size_t r = 0; r < rules.size(); ++r) { |
562 |
|
✗ |
switch (rules[r].check(handleNames, idxOH)) { |
563 |
|
✗ |
case CompiledRule::Accept: |
564 |
|
✗ |
return true; |
565 |
|
✗ |
case CompiledRule::Refuse: |
566 |
|
✗ |
return false; |
567 |
|
✗ |
case CompiledRule::NoMatch: |
568 |
|
✗ |
continue; // Check next rule |
569 |
|
✗ |
default: |
570 |
|
✗ |
throw std::invalid_argument("Rules are ill-defined."); |
571 |
|
|
} |
572 |
|
|
} |
573 |
|
✗ |
return (defaultAcceptationPolicy == CompiledRule::Accept); |
574 |
|
|
} |
575 |
|
|
|
576 |
|
✗ |
inline stateid_type stateid(const GraspV_t& iG) { |
577 |
|
✗ |
stateid_type iGOH = iG[0]; |
578 |
|
|
stateid_type res; |
579 |
|
✗ |
for (index_t i = 1; i < nG; ++i) { |
580 |
|
✗ |
res = iGOH + dims[i] * (iG[i]); |
581 |
|
|
if (res < iGOH) { |
582 |
|
|
hppDout(info, "State ID overflowed. There are too many states..."); |
583 |
|
|
} |
584 |
|
✗ |
iGOH = res; |
585 |
|
|
// iGOH += dims[i] * (iG[i]); |
586 |
|
|
} |
587 |
|
✗ |
return iGOH; |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
bool hasState(const GraspV_t& iG) { return states.count(stateid(iG)) > 0; } |
591 |
|
|
|
592 |
|
✗ |
StateAndManifold_t& operator()(const GraspV_t& iG) { |
593 |
|
✗ |
return states[stateid(iG)]; |
594 |
|
|
} |
595 |
|
|
|
596 |
|
✗ |
bool hasEdge(const GraspV_t& g1, const GraspV_t& g2) { |
597 |
|
✗ |
return edges.count(edgeid_type(stateid(g1), stateid(g2))) > 0; |
598 |
|
|
} |
599 |
|
|
|
600 |
|
✗ |
void addEdge(const GraspV_t& g1, const GraspV_t& g2) { |
601 |
|
✗ |
edges.insert(edgeid_type(stateid(g1), stateid(g2))); |
602 |
|
|
} |
603 |
|
|
|
604 |
|
✗ |
inline std::array<ImplicitPtr_t, 3>& graspConstraint(const index_t& iG, |
605 |
|
|
const index_t& iOH) { |
606 |
|
✗ |
std::array<ImplicitPtr_t, 3>& gcs = graspCs[iG * nOH + iOH]; |
607 |
|
✗ |
if (!gcs[0]) { |
608 |
|
|
hppDout(info, |
609 |
|
|
"Create grasps constraints for (" << iG << ", " << iOH << ")"); |
610 |
|
✗ |
const GripperPtr_t& g(gs[iG]); |
611 |
|
✗ |
const HandlePtr_t& h(handle(iOH)); |
612 |
|
✗ |
const std::string& grasp = g->name() + " grasps " + h->name(); |
613 |
|
✗ |
if (!ps->numericalConstraints.has(grasp)) { |
614 |
|
✗ |
ps->createGraspConstraint(grasp, g->name(), h->name()); |
615 |
|
|
} |
616 |
|
✗ |
gcs[0] = ps->numericalConstraints.get(grasp); |
617 |
|
✗ |
gcs[1] = ps->numericalConstraints.get(grasp + "/complement"); |
618 |
|
✗ |
const std::string& pregrasp = g->name() + " pregrasps " + h->name(); |
619 |
|
✗ |
if (!ps->numericalConstraints.has(pregrasp)) { |
620 |
|
✗ |
ps->createPreGraspConstraint(pregrasp, g->name(), h->name()); |
621 |
|
|
} |
622 |
|
✗ |
gcs[2] = ps->numericalConstraints.get(pregrasp); |
623 |
|
|
} |
624 |
|
✗ |
return gcs; |
625 |
|
|
} |
626 |
|
|
|
627 |
|
✗ |
const Object_t& object(const index_t& iOH) const { |
628 |
|
✗ |
index_t iH = iOH; |
629 |
|
✗ |
for (const Object_t& o : ohs) { |
630 |
|
✗ |
if (iH < std::get<1>(o).size()) return o; |
631 |
|
✗ |
iH -= std::get<1>(o).size(); |
632 |
|
|
} |
633 |
|
✗ |
throw std::out_of_range("Handle index"); |
634 |
|
|
} |
635 |
|
|
|
636 |
|
✗ |
const HandlePtr_t& handle(const index_t& iOH) const { |
637 |
|
✗ |
index_t iH = iOH; |
638 |
|
✗ |
for (const Object_t& o : ohs) { |
639 |
|
✗ |
if (iH < std::get<1>(o).size()) return std::get<1>(o)[iH]; |
640 |
|
✗ |
iH -= std::get<1>(o).size(); |
641 |
|
|
} |
642 |
|
✗ |
throw std::out_of_range("Handle index"); |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
/// Check if an object can be placed |
646 |
|
✗ |
bool objectCanBePlaced(const Object_t& o) const { |
647 |
|
|
// If the object has no joint, then it cannot be placed. |
648 |
|
✗ |
return (std::get<2>(std::get<0>(o)).size() > 0); |
649 |
|
|
} |
650 |
|
|
|
651 |
|
|
/// Check is an object is grasped by the GraspV_t |
652 |
|
✗ |
bool isObjectGrasped(const GraspV_t& idxOH, const Object_t& o) const { |
653 |
|
✗ |
assert(idxOH.size() == nG); |
654 |
|
✗ |
for (std::size_t i = 0; i < idxOH.size(); ++i) |
655 |
|
✗ |
if (idxOH[i] < nOH) // This grippers grasps an object |
656 |
|
✗ |
if (std::get<2>(o) == std::get<2>(object(idxOH[i]))) return true; |
657 |
|
✗ |
return false; |
658 |
|
|
} |
659 |
|
|
|
660 |
|
|
/// Get a state name from a set of grasps |
661 |
|
✗ |
std::string name(const GraspV_t& idxOH, bool abbrev = false) const { |
662 |
|
✗ |
assert(idxOH.size() == nG); |
663 |
|
✗ |
std::stringstream ss; |
664 |
|
✗ |
bool first = true; |
665 |
|
✗ |
std::string sepGOH = (abbrev ? "-" : " grasps "), |
666 |
|
✗ |
sep = (abbrev ? ":" : " : "); |
667 |
|
✗ |
for (std::size_t i = 0; i < idxOH.size(); ++i) { |
668 |
|
✗ |
if (idxOH[i] < nOH) { // This grippers grasps an object |
669 |
|
✗ |
if (first) |
670 |
|
✗ |
first = false; |
671 |
|
|
else |
672 |
|
✗ |
ss << sep; |
673 |
|
✗ |
if (abbrev) |
674 |
|
✗ |
ss << i << sepGOH << idxOH[i]; |
675 |
|
|
else |
676 |
|
✗ |
ss << gs[i]->name() << sepGOH << handle(idxOH[i])->name(); |
677 |
|
|
} |
678 |
|
|
} |
679 |
|
✗ |
if (first) return (abbrev ? "f" : "free"); |
680 |
|
✗ |
return ss.str(); |
681 |
|
|
} |
682 |
|
|
|
683 |
|
|
/// Get an edge name from a set of grasps |
684 |
|
✗ |
std::pair<std::string, std::string> name(const GraspV_t& gFrom, |
685 |
|
|
const GraspV_t& gTo, |
686 |
|
|
const index_t iG) { |
687 |
|
✗ |
const std::string nf(name(gFrom, true)), nt(name(gTo, true)); |
688 |
|
✗ |
std::stringstream ssForw, ssBack; |
689 |
|
✗ |
const char sep[] = " | "; |
690 |
|
✗ |
ssForw << gs[iG]->name() << " > " << handle(gTo[iG])->name() << sep << nf; |
691 |
|
✗ |
ssBack << gs[iG]->name() << " < " << handle(gTo[iG])->name() << sep << nt; |
692 |
|
✗ |
return std::make_pair(ssForw.str(), ssBack.str()); |
693 |
|
|
} |
694 |
|
|
|
695 |
|
✗ |
std::string nameLoopEdge(const GraspV_t& gFrom) { |
696 |
|
✗ |
const std::string nf(name(gFrom, true)); |
697 |
|
✗ |
std::stringstream ss; |
698 |
|
✗ |
const char sep[] = " | "; |
699 |
|
✗ |
ss << "Loop" << sep << nf; |
700 |
|
✗ |
return ss.str(); |
701 |
|
|
} |
702 |
|
|
|
703 |
|
✗ |
void graspManifold(const index_t& iG, const index_t& iOH, |
704 |
|
|
FoliatedManifold& grasp, FoliatedManifold& pregrasp) { |
705 |
|
✗ |
std::array<ImplicitPtr_t, 3>& gcs = graspConstraint(iG, iOH); |
706 |
|
✗ |
grasp.nc.push_back(gcs[0]); |
707 |
|
✗ |
grasp.nc_path.push_back(gcs[0]); |
708 |
|
✗ |
if (gcs[1]->function().outputSize() > 0) grasp.nc_fol.push_back(gcs[1]); |
709 |
|
|
|
710 |
|
✗ |
pregrasp.nc.push_back(gcs[2]); |
711 |
|
✗ |
pregrasp.nc_path.push_back(gcs[2]); |
712 |
|
|
} |
713 |
|
|
}; |
714 |
|
|
|
715 |
|
✗ |
CompiledRule::CompiledRule(const Result& res, const Rule& r) |
716 |
|
✗ |
: handles(res.nG), status(r.link_ ? Accept : Refuse) { |
717 |
|
✗ |
assert(r.grippers_.size() == r.handles_.size()); |
718 |
|
✗ |
for (std::size_t j = 0; j < r.grippers_.size(); ++j) { |
719 |
|
✗ |
boost::regex gripper(r.grippers_[j]); |
720 |
|
✗ |
for (std::size_t i = 0; i < res.nG; ++i) { |
721 |
|
✗ |
if (boost::regex_match(res.gs[i]->name(), gripper)) { |
722 |
|
✗ |
assert(handles[i].empty() && |
723 |
|
|
"Two gripper regex match the different gripper names."); |
724 |
|
✗ |
handles[i] = r.handles_[j]; |
725 |
|
|
} |
726 |
|
|
} |
727 |
|
|
} |
728 |
|
|
} |
729 |
|
|
|
730 |
|
✗ |
const StateAndManifold_t& makeState(Result& r, const GraspV_t& g, |
731 |
|
|
const int priority) { |
732 |
|
✗ |
StateAndManifold_t& nam = r(g); |
733 |
|
✗ |
if (!std::get<0>(nam)) { |
734 |
|
|
hppDout(info, "Creating state " << r.name(g)); |
735 |
|
✗ |
std::get<0>(nam) = |
736 |
|
✗ |
r.graph->stateSelector()->createState(r.name(g), false, priority); |
737 |
|
|
// Loop over the grippers and create grasping constraints if required |
738 |
|
✗ |
FoliatedManifold unused; |
739 |
|
✗ |
std::set<index_t> idxsOH; |
740 |
|
✗ |
for (index_t i = 0; i < r.nG; ++i) { |
741 |
|
✗ |
if (g[i] < r.nOH) { |
742 |
|
✗ |
idxsOH.insert(g[i]); |
743 |
|
✗ |
r.graspManifold(i, g[i], std::get<1>(nam), unused); |
744 |
|
|
} |
745 |
|
|
} |
746 |
|
✗ |
index_t iOH = 0; |
747 |
|
✗ |
for (const Object_t& o : r.ohs) { |
748 |
|
✗ |
if (!r.objectCanBePlaced(o)) continue; |
749 |
|
✗ |
bool oIsGrasped = false; |
750 |
|
|
// TODO: use the fact that the set is sorted. |
751 |
|
|
// for (const HandlePtr_t& h : std::get<0>(o)) |
752 |
|
✗ |
for (index_t i = 0; i < std::get<1>(o).size(); ++i) { |
753 |
|
✗ |
if (idxsOH.erase(iOH) == 1) oIsGrasped = true; |
754 |
|
✗ |
++iOH; |
755 |
|
|
} |
756 |
|
✗ |
if (!oIsGrasped) { |
757 |
|
✗ |
const auto& pc(std::get<0>(o)); |
758 |
|
✗ |
relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc), |
759 |
|
✗ |
std::get<2>(pc), std::get<1>(nam), unused); |
760 |
|
|
} |
761 |
|
|
} |
762 |
|
✗ |
std::get<1>(nam).addToState(std::get<0>(nam)); |
763 |
|
|
|
764 |
|
✗ |
createLoopEdge(r.nameLoopEdge(g), std::get<0>(nam), 0, false, |
765 |
|
|
// TODO std::get<1>(nam).foliated(), |
766 |
|
✗ |
std::get<1>(nam)); |
767 |
|
|
} |
768 |
|
✗ |
return nam; |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
/// Arguments are such that |
772 |
|
|
/// \li gTo[iG] != gFrom[iG] |
773 |
|
|
/// \li for all i != iG, gTo[iG] == gFrom[iG] |
774 |
|
✗ |
void makeEdge(Result& r, const GraspV_t& gFrom, const GraspV_t& gTo, |
775 |
|
|
const index_t iG, const int priority) { |
776 |
|
✗ |
if (r.hasEdge(gFrom, gTo)) { |
777 |
|
|
hppDout(warning, "Prevented creation of duplicated edge\nfrom " |
778 |
|
|
<< r.name(gFrom) << "\nto " << r.name(gTo)); |
779 |
|
✗ |
return; |
780 |
|
|
} |
781 |
|
✗ |
const StateAndManifold_t &from = makeState(r, gFrom, priority), |
782 |
|
✗ |
to = makeState(r, gTo, priority + 1); |
783 |
|
✗ |
const Object_t& o = r.object(gTo[iG]); |
784 |
|
|
|
785 |
|
|
// Detect when grasping an object already grasped. |
786 |
|
|
// or when there is no placement information for it. |
787 |
|
✗ |
bool noPlace = !r.objectCanBePlaced(o) || r.isObjectGrasped(gFrom, o); |
788 |
|
|
|
789 |
|
✗ |
FoliatedManifold grasp, pregrasp, place, preplace, submanifold; |
790 |
|
✗ |
r.graspManifold(iG, gTo[iG], grasp, pregrasp); |
791 |
|
✗ |
if (!noPlace) { |
792 |
|
✗ |
const auto& pc(std::get<0>(o)); |
793 |
|
✗ |
relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc), std::get<2>(pc), |
794 |
|
|
place, preplace); |
795 |
|
|
} |
796 |
|
✗ |
std::pair<std::string, std::string> names = r.name(gFrom, gTo, iG); |
797 |
|
|
{ |
798 |
|
✗ |
FoliatedManifold unused; |
799 |
|
✗ |
std::set<index_t> idxsOH; |
800 |
|
✗ |
for (index_t i = 0; i < r.nG; ++i) { |
801 |
|
✗ |
if (gFrom[i] < r.nOH) { |
802 |
|
✗ |
idxsOH.insert(gFrom[i]); |
803 |
|
✗ |
r.graspManifold(i, gFrom[i], submanifold, unused); |
804 |
|
|
} |
805 |
|
|
} |
806 |
|
✗ |
index_t iOH = 0; |
807 |
|
✗ |
for (const Object_t& o : r.ohs) { |
808 |
|
✗ |
if (!r.objectCanBePlaced(o)) continue; |
809 |
|
✗ |
bool oIsGrasped = false; |
810 |
|
✗ |
const index_t iOHstart = iOH; |
811 |
|
✗ |
for (; iOH < iOHstart + std::get<1>(o).size(); ++iOH) { |
812 |
|
✗ |
if (iOH == gTo[iG]) { |
813 |
|
✗ |
oIsGrasped = true; |
814 |
|
✗ |
iOH = iOHstart + std::get<1>(o).size(); |
815 |
|
✗ |
break; |
816 |
|
|
} |
817 |
|
✗ |
if (idxsOH.erase(iOH) == 1) oIsGrasped = true; |
818 |
|
|
} |
819 |
|
✗ |
if (!oIsGrasped) { |
820 |
|
✗ |
const auto& pc(std::get<0>(o)); |
821 |
|
✗ |
relaxedPlacementManifold(std::get<0>(pc), std::get<1>(pc), |
822 |
|
✗ |
std::get<2>(pc), submanifold, unused); |
823 |
|
|
} |
824 |
|
|
} |
825 |
|
|
} |
826 |
|
✗ |
if (pregrasp.empty()) { |
827 |
|
✗ |
if (noPlace) |
828 |
|
✗ |
createEdges<GraspOnly | NoPlace>( |
829 |
|
✗ |
names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1, |
830 |
|
✗ |
grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(), |
831 |
|
|
submanifold); |
832 |
|
✗ |
else if (preplace.empty()) |
833 |
|
✗ |
createEdges<GraspOnly | PlaceOnly>( |
834 |
|
✗ |
names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1, |
835 |
|
✗ |
grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(), |
836 |
|
|
submanifold); |
837 |
|
|
else { |
838 |
|
|
hppDout(error, "GraspOnly | WithPrePlace not implemeted yet"); |
839 |
|
|
/* |
840 |
|
|
createEdges <GraspOnly | WithPrePlace> ( |
841 |
|
|
names.first , names.second, |
842 |
|
|
std::get<0>(from) , std::get<0>(to), |
843 |
|
|
1 , 1, |
844 |
|
|
grasp , pregrasp, |
845 |
|
|
place , preplace, |
846 |
|
|
grasp.foliated () , place.foliated(), |
847 |
|
|
submanifold); // */ |
848 |
|
|
} |
849 |
|
|
} else { |
850 |
|
✗ |
if (noPlace) |
851 |
|
✗ |
createEdges<WithPreGrasp | NoPlace>( |
852 |
|
✗ |
names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1, |
853 |
|
✗ |
grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(), |
854 |
|
|
submanifold); |
855 |
|
✗ |
else if (preplace.empty()) |
856 |
|
✗ |
createEdges<WithPreGrasp | PlaceOnly>( |
857 |
|
✗ |
names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1, |
858 |
|
✗ |
grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(), |
859 |
|
|
submanifold); |
860 |
|
|
else |
861 |
|
✗ |
createEdges<WithPreGrasp | WithPrePlace>( |
862 |
|
✗ |
names.first, names.second, std::get<0>(from), std::get<0>(to), 1, 1, |
863 |
|
✗ |
grasp, pregrasp, place, preplace, grasp.foliated(), place.foliated(), |
864 |
|
|
submanifold); |
865 |
|
|
} |
866 |
|
✗ |
r.addEdge(gFrom, gTo); |
867 |
|
|
} |
868 |
|
|
|
869 |
|
|
/// idx are the available grippers |
870 |
|
✗ |
void recurseGrippers(Result& r, const IndexV_t& idx_g, const IndexV_t& idx_oh, |
871 |
|
|
const GraspV_t& grasps, const int depth) { |
872 |
|
✗ |
bool curGraspIsAllowed = r.graspIsAllowed(grasps); |
873 |
|
✗ |
if (curGraspIsAllowed) makeState(r, grasps, depth); |
874 |
|
|
|
875 |
|
✗ |
if (idx_g.empty() || idx_oh.empty()) return; |
876 |
|
✗ |
IndexV_t nIdx_g(idx_g.size() - 1); |
877 |
|
✗ |
IndexV_t nIdx_oh(idx_oh.size() - 1); |
878 |
|
✗ |
for (IndexV_t::const_iterator itx_g = idx_g.begin(); itx_g != idx_g.end(); |
879 |
|
✗ |
++itx_g) { |
880 |
|
|
// Copy all element except itx_g |
881 |
|
✗ |
std::copy(std::next(itx_g), idx_g.end(), |
882 |
|
|
std::copy(idx_g.begin(), itx_g, nIdx_g.begin())); |
883 |
|
✗ |
for (IndexV_t::const_iterator itx_oh = idx_oh.begin(); |
884 |
|
✗ |
itx_oh != idx_oh.end(); ++itx_oh) { |
885 |
|
|
// Create the edge for the selected grasp |
886 |
|
✗ |
GraspV_t nGrasps = grasps; |
887 |
|
✗ |
nGrasps[*itx_g] = *itx_oh; |
888 |
|
|
|
889 |
|
✗ |
bool nextGraspIsAllowed = r.graspIsAllowed(nGrasps); |
890 |
|
✗ |
if (nextGraspIsAllowed) makeState(r, nGrasps, depth + 1); |
891 |
|
|
|
892 |
|
✗ |
if (curGraspIsAllowed && nextGraspIsAllowed) |
893 |
|
✗ |
makeEdge(r, grasps, nGrasps, *itx_g, depth); |
894 |
|
|
|
895 |
|
|
// Copy all element except itx_oh |
896 |
|
✗ |
std::copy(std::next(itx_oh), idx_oh.end(), |
897 |
|
|
std::copy(idx_oh.begin(), itx_oh, nIdx_oh.begin())); |
898 |
|
|
// Do all the possible combination below this new grasp |
899 |
|
✗ |
recurseGrippers(r, nIdx_g, nIdx_oh, nGrasps, depth + 2); |
900 |
|
|
} |
901 |
|
|
} |
902 |
|
|
} |
903 |
|
|
} // namespace |
904 |
|
|
|
905 |
|
✗ |
void graphBuilder(const ProblemSolverPtr_t& ps, const Objects_t& objects, |
906 |
|
|
const Grippers_t& grippers, GraphPtr_t graph, |
907 |
|
|
const Rules_t& rules) { |
908 |
|
✗ |
if (!graph) throw std::logic_error("The graph must be initialized"); |
909 |
|
✗ |
StateSelectorPtr_t ns = graph->stateSelector(); |
910 |
|
✗ |
if (!ns) throw std::logic_error("The graph does not have a StateSelector"); |
911 |
|
|
|
912 |
|
✗ |
Result r(ps, grippers, objects, graph); |
913 |
|
✗ |
r.setRules(rules); |
914 |
|
|
|
915 |
|
✗ |
IndexV_t availG(r.nG), availOH(r.nOH); |
916 |
|
✗ |
for (index_t i = 0; i < r.nG; ++i) availG[i] = i; |
917 |
|
✗ |
for (index_t i = 0; i < r.nOH; ++i) availOH[i] = i; |
918 |
|
|
|
919 |
|
✗ |
GraspV_t iG(r.nG, r.nOH); |
920 |
|
|
|
921 |
|
✗ |
recurseGrippers(r, availG, availOH, iG, 0); |
922 |
|
|
|
923 |
|
|
hppDout(info, "Created a graph with " << r.states.size() |
924 |
|
|
<< " states " |
925 |
|
|
"and " |
926 |
|
|
<< r.edges.size() << " edges."); |
927 |
|
|
} |
928 |
|
|
|
929 |
|
✗ |
GraphPtr_t graphBuilder(const ProblemSolverPtr_t& ps, |
930 |
|
|
const std::string& graphName, const Strings_t& griNames, |
931 |
|
|
const std::vector<ObjectDef_t>& objs, |
932 |
|
|
const Strings_t& envNames, |
933 |
|
|
const std::vector<Rule>& rules, |
934 |
|
|
const value_type& prePlaceWidth) { |
935 |
|
✗ |
if (ps->graphs.has(graphName)) |
936 |
|
✗ |
throw std::invalid_argument("A graph named " + graphName + |
937 |
|
✗ |
" already exists."); |
938 |
|
|
|
939 |
|
✗ |
const Device& robot = *(ps->robot()); |
940 |
|
✗ |
const pinocchio::Model& model = robot.model(); |
941 |
|
✗ |
Grippers_t grippers(griNames.size()); |
942 |
|
✗ |
index_t i = 0; |
943 |
|
✗ |
for (const std::string& gn : griNames) { |
944 |
|
✗ |
grippers[i] = robot.grippers.get(gn); |
945 |
|
✗ |
++i; |
946 |
|
|
} |
947 |
|
✗ |
Objects_t objects(objs.size()); |
948 |
|
✗ |
i = 0; |
949 |
|
✗ |
const value_type margin = 1e-3; |
950 |
|
✗ |
bool prePlace = (prePlaceWidth > 0); |
951 |
|
✗ |
for (const ObjectDef_t& od : objs) { |
952 |
|
|
// Create handles |
953 |
|
✗ |
std::get<2>(objects[i]) = i; |
954 |
|
✗ |
std::get<1>(objects[i]).resize(od.handles.size()); |
955 |
|
✗ |
Handles_t::iterator it = std::get<1>(objects[i]).begin(); |
956 |
|
✗ |
for (const std::string& hn : od.handles) { |
957 |
|
✗ |
*it = robot.handles.get(hn); |
958 |
|
✗ |
++it; |
959 |
|
|
} |
960 |
|
|
// Create placement |
961 |
|
✗ |
const std::string placeN = "place_" + od.name; |
962 |
|
✗ |
const std::string preplaceN = "pre" + placeN; |
963 |
|
|
// If user provides constraint "place_objectName", |
964 |
|
|
// then |
965 |
|
|
// use this as placement and use "preplace_objectName" for |
966 |
|
|
// pre-placement if defined. |
967 |
|
|
// else if contact surfaces are defined and selected |
968 |
|
|
// create default placement constraint using the ProblemSolver |
969 |
|
|
// methods createPlacementConstraint and createPrePlacementConstraint |
970 |
|
✗ |
auto& pc(std::get<0>(objects[i])); |
971 |
|
✗ |
if (ps->numericalConstraints.has(placeN)) { |
972 |
|
✗ |
std::get<0>(pc) = ps->numericalConstraints.get(placeN); |
973 |
|
✗ |
if (ps->numericalConstraints.has(preplaceN)) { |
974 |
|
✗ |
std::get<1>(pc) = ps->numericalConstraints.get(preplaceN); |
975 |
|
|
} |
976 |
|
✗ |
} else if (!envNames.empty() && !od.shapes.empty()) { |
977 |
|
✗ |
ps->createPlacementConstraint(placeN, od.shapes, envNames, margin); |
978 |
|
✗ |
std::get<0>(pc) = ps->numericalConstraints.get(placeN); |
979 |
|
✗ |
if (prePlace) { |
980 |
|
✗ |
ps->createPrePlacementConstraint(preplaceN, od.shapes, envNames, margin, |
981 |
|
|
prePlaceWidth); |
982 |
|
✗ |
std::get<1>(pc) = ps->numericalConstraints.get(preplaceN); |
983 |
|
|
} |
984 |
|
|
} |
985 |
|
|
// Create object lock |
986 |
|
|
// Loop over all frames of object, detect joint and create locked |
987 |
|
|
// joint. |
988 |
|
✗ |
assert(robot.robotFrames(od.name).size() != 0); |
989 |
|
✗ |
for (const FrameIndex& f : robot.robotFrames(od.name)) { |
990 |
|
✗ |
if (model.frames[f].type != ::pinocchio::JOINT) continue; |
991 |
|
✗ |
const JointIndex j = model.frames[f].parent; |
992 |
|
✗ |
JointPtr_t oj(Joint::create(ps->robot(), j)); |
993 |
|
✗ |
LiegroupSpacePtr_t space(oj->configurationSpace()); |
994 |
|
✗ |
LiegroupElement lge(robot.currentConfiguration().segment( |
995 |
|
|
oj->rankInConfiguration(), oj->configSize()), |
996 |
|
✗ |
space); |
997 |
|
✗ |
LockedJointPtr_t lj = core::LockedJoint::create(oj, lge); |
998 |
|
✗ |
ps->numericalConstraints.add("lock_" + oj->name(), lj); |
999 |
|
✗ |
std::get<2>(pc).push_back(lj); |
1000 |
|
|
} |
1001 |
|
✗ |
++i; |
1002 |
|
|
} |
1003 |
|
✗ |
GraphPtr_t graph = Graph::create(graphName, ps->robot(), ps->problem()); |
1004 |
|
✗ |
ps->graphs.add(graphName, graph); |
1005 |
|
✗ |
ps->constraintGraph(graphName); |
1006 |
|
✗ |
graph->stateSelector( |
1007 |
|
✗ |
GuidedStateSelector::create("stateSelector", ps->roadmap())); |
1008 |
|
✗ |
graph->maxIterations(ps->maxIterProjection()); |
1009 |
|
✗ |
graph->errorThreshold(ps->errorThreshold()); |
1010 |
|
|
|
1011 |
|
✗ |
graphBuilder(ps, objects, grippers, graph, rules); |
1012 |
|
✗ |
return graph; |
1013 |
|
|
} |
1014 |
|
|
} // namespace helper |
1015 |
|
|
} // namespace graph |
1016 |
|
|
} // namespace manipulation |
1017 |
|
|
} // namespace hpp |
1018 |
|
|
|