@@ -84,7 +84,8 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
84
84
const HPolyhedron& domain, const IrisZoOptions& options) {
85
85
auto start = std::chrono::high_resolution_clock::now ();
86
86
const int num_threads_to_use =
87
- checker.SupportsParallelChecking ()
87
+ checker.SupportsParallelChecking () &&
88
+ options.get_parameterization_is_threadsafe ()
88
89
? std::min (options.parallelism .num_threads (),
89
90
checker.num_allocated_contexts ())
90
91
: 1 ;
@@ -100,14 +101,30 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
100
101
// Prevent directly terminating if the ellipsoid is too large.
101
102
double previous_volume = 0 ;
102
103
103
- const int dim = starting_ellipsoid.ambient_dimension ();
104
- int current_num_faces = domain.A ().rows ();
104
+ const int ambient_dimension = checker.plant ().num_positions ();
105
+ const int parameterized_dimension =
106
+ options.get_parameterization_dimension ().value_or (ambient_dimension);
105
107
106
108
DRAKE_THROW_UNLESS (num_threads_to_use > 0 );
107
- DRAKE_THROW_UNLESS (domain.ambient_dimension () == dim);
109
+ DRAKE_THROW_UNLESS (starting_ellipsoid.ambient_dimension () ==
110
+ parameterized_dimension);
111
+ DRAKE_THROW_UNLESS (domain.ambient_dimension () == parameterized_dimension);
108
112
DRAKE_THROW_UNLESS (domain.IsBounded ());
109
113
DRAKE_THROW_UNLESS (domain.PointInSet (current_ellipsoid_center));
110
114
115
+ const int computed_ambient_dimension =
116
+ options.get_parameterization ()(starting_ellipsoid_center).size ();
117
+ if (computed_ambient_dimension != ambient_dimension) {
118
+ throw std::runtime_error (fmt::format (
119
+ " The plant has {} positions, but the given parameterization "
120
+ " returned a point with the wrong dimension (its size was "
121
+ " {}) when called on {}." ,
122
+ ambient_dimension, computed_ambient_dimension,
123
+ fmt_eigen (starting_ellipsoid_center.transpose ())));
124
+ }
125
+
126
+ int current_num_faces = domain.A ().rows ();
127
+
111
128
if (options.max_iterations_separating_planes <= 0 ) {
112
129
throw std::runtime_error (
113
130
" The maximum number of iterations for separating planes "
@@ -116,7 +133,7 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
116
133
VPolytope cvxh_vpoly;
117
134
if (options.containment_points .has_value ()) {
118
135
cvxh_vpoly = VPolytope (options.containment_points .value ());
119
- DRAKE_THROW_UNLESS (domain. ambient_dimension () ==
136
+ DRAKE_THROW_UNLESS (parameterized_dimension ==
120
137
options.containment_points ->rows ());
121
138
122
139
constexpr float kPointInSetTol = 1e-5 ;
@@ -133,7 +150,8 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
133
150
134
151
for (int col = 0 ; col < options.containment_points ->cols (); ++col) {
135
152
Eigen::VectorXd conf = options.containment_points ->col (col);
136
- cont_vec.emplace_back (conf);
153
+ cont_vec.emplace_back (options.get_parameterization ()(conf));
154
+ DRAKE_ASSERT (cont_vec.back ().size () == ambient_dimension);
137
155
}
138
156
139
157
std::vector<uint8_t > containment_point_col_free =
@@ -147,11 +165,14 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
147
165
}
148
166
// For debugging visualization.
149
167
Eigen::Vector3d point_to_draw = Eigen::Vector3d::Zero ();
150
- if (options.meshcat && dim <= 3 ) {
168
+ if (options.meshcat && ambient_dimension <= 3 ) {
151
169
std::string path = " seedpoint" ;
152
170
options.meshcat ->SetObject (path, Sphere (0.06 ),
153
171
geometry::Rgba (0.1 , 1 , 1 , 1.0 ));
154
- point_to_draw.head (dim) = current_ellipsoid_center;
172
+ Eigen::VectorXd conf_ambient =
173
+ options.get_parameterization ()(current_ellipsoid_center);
174
+ DRAKE_ASSERT (conf_ambient.size () == ambient_dimension);
175
+ point_to_draw.head (ambient_dimension) = conf_ambient;
155
176
options.meshcat ->SetTransform (path, RigidTransform<double >(point_to_draw));
156
177
}
157
178
@@ -174,7 +195,8 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
174
195
log ()->info (" IrisZo worst case test requires {} samples." , N_max);
175
196
}
176
197
177
- std::vector<Eigen::VectorXd> particles (N_max, Eigen::VectorXd::Zero (dim));
198
+ std::vector<Eigen::VectorXd> particles (
199
+ N_max, Eigen::VectorXd::Zero (parameterized_dimension));
178
200
179
201
int iteration = 0 ;
180
202
HPolyhedron P = domain;
@@ -184,7 +206,7 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
184
206
// TODO(wernerpe): Find a better solution than hardcoding 300.
185
207
constexpr int kNumFacesToPreAllocate = 300 ;
186
208
Eigen::Matrix<double , Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A (
187
- P.A ().rows () + kNumFacesToPreAllocate , dim );
209
+ P.A ().rows () + kNumFacesToPreAllocate , parameterized_dimension );
188
210
Eigen::VectorXd b (P.A ().rows () + kNumFacesToPreAllocate );
189
211
190
212
while (true ) {
@@ -228,15 +250,24 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
228
250
options.mixing_steps );
229
251
}
230
252
231
- // Copy top slice of particles, due to collision checker only accepting
232
- // vectors of configurations.
233
- // TODO(wernerpe): Remove this copy operation.
234
- std::vector<Eigen::VectorXd> particles_step (particles.begin (),
235
- particles.begin () + N_k);
253
+ // Copy top slice of particles, applying thet parameterization function to
254
+ // each one, due to collision checker only accepting vectors of
255
+ // configurations.
256
+ // TODO(wernerpe, cohnt): Remove this copy operation.
257
+ // TODO(cohnt): Consider parallelizing the parameterization calls, in case
258
+ // it's an expensive operation.
259
+ std::vector<Eigen::VectorXd> ambient_particles (N_k);
260
+ std::transform (particles.begin (), particles.begin () + N_k,
261
+ ambient_particles.begin (), options.get_parameterization ());
262
+
263
+ for (int i = 0 ; i < ssize (ambient_particles); ++i) {
264
+ // Only run this check in debug mode, because it's expensive.
265
+ DRAKE_ASSERT (ambient_particles[i].size () == ambient_dimension);
266
+ }
236
267
237
268
// Find all particles in collision
238
269
std::vector<uint8_t > particle_col_free =
239
- checker.CheckConfigsCollisionFree (particles_step ,
270
+ checker.CheckConfigsCollisionFree (ambient_particles ,
240
271
options.parallelism );
241
272
std::vector<Eigen::VectorXd> particles_in_collision;
242
273
int number_particles_in_collision_unadaptive_test = 0 ;
@@ -280,34 +311,45 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
280
311
281
312
// For each particle in collision, we run a bisection search to find a
282
313
// configuration on the boundary of the obstacle.
283
- const auto particle_update_work =
284
- [&checker, &particles_in_collision_updated, &particles_in_collision,
285
- ¤t_ellipsoid_center,
286
- &options](const int thread_num, const int64_t index ) {
287
- const int point_idx = static_cast <int >(index );
288
- auto start_point = particles_in_collision[point_idx];
289
-
290
- Eigen::VectorXd current_point = start_point;
291
- Eigen::VectorXd curr_pt_lower = current_ellipsoid_center;
292
-
293
- // Update current point using a fixed number of bisection steps.
294
- if (!checker.CheckConfigCollisionFree (curr_pt_lower, thread_num)) {
295
- current_point = curr_pt_lower;
314
+ const auto particle_update_work = [&checker,
315
+ &particles_in_collision_updated,
316
+ &particles_in_collision,
317
+ ¤t_ellipsoid_center,
318
+ &options](const int thread_num,
319
+ const int64_t index ) {
320
+ const int point_idx = static_cast <int >(index );
321
+ auto start_point = particles_in_collision[point_idx];
322
+
323
+ Eigen::VectorXd current_point = start_point;
324
+ Eigen::VectorXd curr_pt_lower = current_ellipsoid_center;
325
+
326
+ // Update current point using a fixed number of bisection steps.
327
+ Eigen::VectorXd current_point_ambient =
328
+ options.get_parameterization ()(curr_pt_lower);
329
+ DRAKE_ASSERT (current_point_ambient.size () ==
330
+ checker.plant ().num_positions ());
331
+ if (!checker.CheckConfigCollisionFree (current_point_ambient,
332
+ thread_num)) {
333
+ current_point = curr_pt_lower;
334
+ } else {
335
+ Eigen::VectorXd curr_pt_upper = current_point;
336
+ for (int i = 0 ; i < options.bisection_steps ; ++i) {
337
+ Eigen::VectorXd query = 0.5 * (curr_pt_upper + curr_pt_lower);
338
+ Eigen::VectorXd query_ambient =
339
+ options.get_parameterization ()(query);
340
+ DRAKE_ASSERT (query_ambient.size () ==
341
+ checker.plant ().num_positions ());
342
+ if (checker.CheckConfigCollisionFree (query_ambient, thread_num)) {
343
+ curr_pt_lower = query;
296
344
} else {
297
- Eigen::VectorXd curr_pt_upper = current_point;
298
- for (int i = 0 ; i < options.bisection_steps ; ++i) {
299
- Eigen::VectorXd query = 0.5 * (curr_pt_upper + curr_pt_lower);
300
- if (checker.CheckConfigCollisionFree (query, thread_num)) {
301
- curr_pt_lower = query;
302
- } else {
303
- curr_pt_upper = query;
304
- current_point = query;
305
- }
306
- }
345
+ curr_pt_upper = query;
346
+ current_point = query;
307
347
}
348
+ }
349
+ }
308
350
309
- particles_in_collision_updated[point_idx] = current_point;
310
- };
351
+ particles_in_collision_updated[point_idx] = current_point;
352
+ };
311
353
312
354
// Update all particles in parallel.
313
355
DynamicParallelForIndexLoop (DegreeOfParallelism (num_threads_to_use), 0 ,
@@ -378,15 +420,18 @@ HPolyhedron IrisZo(const planning::CollisionChecker& checker,
378
420
}
379
421
380
422
// Fill in meshcat if added for debugging.
381
- if (options.meshcat && dim <= 3 ) {
423
+ if (options.meshcat && ambient_dimension <= 3 ) {
382
424
for (int pt_to_draw = 0 ; pt_to_draw < number_particles_in_collision;
383
425
++pt_to_draw) {
384
426
std::string path = fmt::format (
385
427
" face_pt/iteration{:02}/sepit{:02}/{:03}/pt" , iteration,
386
428
num_iterations_separating_planes, current_num_faces);
387
429
options.meshcat ->SetObject (path, Sphere (0.03 ),
388
430
geometry::Rgba (1 , 1 , 0.1 , 1.0 ));
389
- point_to_draw.head (dim) = nearest_particle;
431
+ Eigen::VectorXd ambient_particle =
432
+ options.get_parameterization ()(nearest_particle);
433
+ DRAKE_ASSERT (ambient_particle.size () == ambient_dimension);
434
+ point_to_draw.head (ambient_dimension) = ambient_particle;
390
435
options.meshcat ->SetTransform (
391
436
path, RigidTransform<double >(point_to_draw));
392
437
}
0 commit comments