capsulated_ladder_tree_RRTstar.cpp
Go to the documentation of this file.
1 //
2 // Created by yijiangh on 11/28/17.
3 //
4 
7 
9 #include "../include/choreo_descartes_planner/pose_verification_helpers.h"
10 
11 // ladder graph & DAG (solution extraction)
12 #include <descartes_planner/ladder_graph.h>
13 #include <descartes_planner/ladder_graph_dag_search.h>
14 
15 // pose conversion
17 #include <geometry_msgs/Pose.h>
18 
19 static const double DEFAULT_UNIT_PROCESS_TIMEOUT = 30.0;
20 
21 namespace // anon namespace to hide utility functions
22 {
23 static bool comparePtrCapVert(const descartes_planner::CapVert* lhs, const descartes_planner::CapVert* rhs)
24 {
25  return (lhs->getCost() < rhs->getCost());
26 }
27 } //end util namespace
28 
29 namespace descartes_planner
30 {
32  const std::vector<ConstrainedSegment>& segs,
33  const std::vector<planning_scene::PlanningScenePtr>& planning_scenes,
34  const std::vector<planning_scene::PlanningScenePtr>& planning_scenes_completed)
35 {
36  // sanity check
37  assert(segs.size() == planning_scenes.size());
38 
39  if(planning_scenes_completed.size() > 0)
40  {
41  assert(planning_scenes_completed.size() == planning_scenes.size());
42  }
43 
44  // intialize cap rungs
45  cap_rungs_.reserve(segs.size());
46  for(size_t i=0; i < segs.size(); i++)
47  {
48  CapRung cap_rung;
49 
50  // end effector path pts
51  auto points = discretizePositions(segs[i].start, segs[i].end, segs[i].linear_disc);
52  cap_rung.path_pts_.push_back(points);
53 
54  // feasible orientations
55  cap_rung.orientations_.resize(1);
56  cap_rung.orientations_[0].reserve(segs[i].orientations.size());
57 
58  for (auto& orient : segs[i].orientations)
59  {
60  cap_rung.orientations_[0].push_back(orient);
61  }
62 
63  // planning scene
64  cap_rung.planning_scene_.push_back(planning_scenes[i]);
65  cap_rung.sub_segment_ids_.push_back(points.size());
66 
67  if(planning_scenes_completed.size() > 0)
68  {
69  cap_rung.planning_scene_completed_.push_back(planning_scenes_completed[i]);
70  }
71 
72  // input z axis disc
73  cap_rung.z_axis_disc_ = segs[i].z_axis_disc;
74 
75  // linear speed
76  cap_rung.linear_vel_ = segs[i].linear_vel;
77 
78  cap_rungs_.push_back(cap_rung);
79  }
80 }
81 
83  const std::vector<ConstrainedSegmentPickNPlace>& segs)
84 {
85  // intialize cap rungs
86  cap_rungs_.reserve(segs.size());
87  for(size_t i=0; i < segs.size(); i++)
88  {
89  CapRung cap_rung;
90 
91  // at least two path pts
92  assert(segs[i].orientations.size() == segs[i].path_pts.size());
93  assert(segs[i].planning_scenes.size() == segs[i].path_pts.size());
94 
95  // iterate through all kinematics families
96  const int k_family_size = segs[i].path_pts.size();
97  cap_rung.path_pts_.resize(k_family_size);
98  cap_rung.orientations_.resize(k_family_size);
99  cap_rung.planning_scene_.resize(k_family_size);
100  cap_rung.sub_segment_ids_.resize(k_family_size);
101 
102  for(int j = 0; j < k_family_size; j++)
103  {
104  const std::vector<Eigen::Vector3d>& pts = segs[i].path_pts[j];
105 
106  assert(pts.size() >= 2);
107 
108  for(int k = 0; k < pts.size() - 1; k++)
109  {
110  // might be several segments (polyline) in one kinematics family
111  auto points = discretizePositions(pts[k], pts[k+1], segs[i].linear_disc);
112  cap_rung.path_pts_[j].insert(cap_rung.path_pts_[j].end(), points.begin(), points.end());
113  }
114 
115  // detailed disc size in each kinematic family
116  cap_rung.sub_segment_ids_[j] = cap_rung.path_pts_[j].size();
117  }
118 
119  cap_rung.orientations_ = segs[i].orientations;
120  // sanity check, enforce all orientations candidates set sizes are equal for all kinematics families
121  assert(cap_rung.orientations_.size()>0);
122  for(const auto& orients : cap_rung.orientations_)
123  {
124  assert(orients.size() == cap_rung.orientations_[0].size());
125  }
126 
127  cap_rung.planning_scene_ = segs[i].planning_scenes;
128 
129  // linear speed
130  cap_rung.linear_vel_ = segs[i].linear_vel;
131 
132  cap_rungs_.push_back(cap_rung);
133  }
134 }
135 
137 {
138  for(auto& cap_rung : cap_rungs_)
139  {
140  for(auto& ptr_vert : cap_rung.ptr_cap_verts_)
141  {
142  if(NULL != ptr_vert)
143  {
144  delete ptr_vert;
145  ptr_vert = NULL;
146  }
147  }
148  }
149 }
150 
151 double CapsulatedLadderTreeRRTstar::solve(descartes_core::RobotModel& model,
152  double unit_process_timeout,
153  double rrt_star_timeout)
154 {
155  if(unit_process_timeout < 1.0)
156  {
157  logWarn("[CLT-RRT] unit process sampling timeout %.2f s, smaller than 1.0, set to default timeout %.2f s",
158  unit_process_timeout, DEFAULT_UNIT_PROCESS_TIMEOUT);
159  unit_process_timeout = DEFAULT_UNIT_PROCESS_TIMEOUT;
160  }
161 
162  if(rrt_star_timeout < 5.0)
163  {
164  rrt_star_timeout = 4*cap_rungs_.size();
165  logWarn("[CLT-RRT] rrt star timeout %.2f s, smaller than 5.0s, set to default timeout %.2f s",
166  rrt_star_timeout, rrt_star_timeout);
167  }
168 
169  // find initial solution
170  size_t rung_id = 0;
171  CapVert* ptr_prev_vert = NULL;
172 
173  for(auto& cap_rung : cap_rungs_)
174  {
175  const auto unit_search_start = ros::Time::now();
176  auto unit_search_update = unit_search_start;
177  CapVert* ptr_cap_vert = new CapVert(model.getDOF());
178 
179  do
180  {
181  // TODO: app-dependent
182  std::vector<Eigen::Affine3d> poses = generateSample(cap_rung, *ptr_cap_vert);
183 
184  // TODO: app-dependent
185  if(checkFeasibility(model, poses, cap_rung, *ptr_cap_vert))
186  {
187  ptr_cap_vert->setParentVertPtr(ptr_prev_vert);
188  ptr_cap_vert->rung_id_ = rung_id;
189  cap_rung.ptr_cap_verts_.push_back(ptr_cap_vert);
190  ptr_prev_vert = ptr_cap_vert;
191  break;
192  }
193 
194  unit_search_update = ros::Time::now();
195  }
196  while((unit_search_update - unit_search_start).toSec() < unit_process_timeout);
197 
198  if(cap_rung.ptr_cap_verts_.empty())
199  {
200  // random sampling fails to find a solution
201  ROS_ERROR_STREAM("[CapRRTstar] process #" << rung_id
202  << " fails to find intial feasible sol within timeout "
203  << unit_process_timeout << "secs");
204  return std::numeric_limits<double>::max();
205  }
206 
207  ROS_INFO_STREAM("[CLTRRT] ik solutions found for process #" << rung_id);
208  rung_id++;
209  } // loop over cap_rungs
210 
211  double initial_sol_cost = cap_rungs_.back().ptr_cap_verts_.back()->getCost();
212  ROS_INFO_STREAM("[CLTRRT] initial sol found! cost: " << initial_sol_cost);
213  ROS_INFO_STREAM("[CLTRRT] RRT* improvement starts, computation time: " << rrt_star_timeout);
214 
215  // RRT* improve on the tree
216  const auto rrt_start_time = ros::Time::now();
217 
218  while((ros::Time::now() - rrt_start_time).toSec() < rrt_star_timeout)
219  {
220  // sample cap_rung
221  int rung_id_sample = randomSampleInt(0, cap_rungs_.size()-1);
222  auto& cap_rung_sample = cap_rungs_[rung_id_sample];
223 
224  // sample cap_vert
225  CapVert* ptr_new_vert = new CapVert(model.getDOF());
226 
227  // TODO: app-dependent
228  auto poses = generateSample(cap_rung_sample, *ptr_new_vert);
229 
230  // TODO: app-dependent
231  if(checkFeasibility(model, poses, cap_rung_sample, *ptr_new_vert))
232  {
233  // find nearest node in tree
234  double c_min = std::numeric_limits<double>::max();
235  CapVert* ptr_nearest_vert = NULL;
236 
237  if(rung_id_sample > 0)
238  {
239  for(auto& ptr_near_vert : this->cap_rungs_[rung_id_sample-1].ptr_cap_verts_)
240  {
241  double new_near_cost = ptr_near_vert->getCost() + ptr_new_vert->distance(ptr_near_vert);
242  if(c_min > new_near_cost)
243  {
244  ptr_nearest_vert = ptr_near_vert;
245  c_min = new_near_cost;
246  }
247  }
248  }
249 
250  // add new vert into CL tree (rung_id, parent_vert)
251  ptr_new_vert->rung_id_ = rung_id_sample;
252  ptr_new_vert->setParentVertPtr(ptr_nearest_vert);
253  cap_rung_sample.ptr_cap_verts_.push_back(ptr_new_vert);
254 
255  // update vert next (repair tree)
256  if(rung_id_sample < this->cap_rungs_.size()-1)
257  {
258  double new_vert_cost = ptr_new_vert->getCost();
259  for(auto& ptr_next_vert : this->cap_rungs_[rung_id_sample+1].ptr_cap_verts_)
260  {
261  double old_next_cost = ptr_next_vert->getCost();
262  double new_next_cost = new_vert_cost + ptr_next_vert->distance(ptr_new_vert);
263  if(old_next_cost > new_next_cost)
264  {
265  ptr_next_vert->setParentVertPtr(ptr_new_vert);
266  }
267  }
268  }
269  } // end if capvert feasible
270  }
271 
272  CapVert* ptr_last_cap_vert = *std::min_element(this->cap_rungs_.back().ptr_cap_verts_.begin(),
273  this->cap_rungs_.back().ptr_cap_verts_.end(), comparePtrCapVert);
274  double rrt_cost = ptr_last_cap_vert->getCost();
275 
276  ROS_INFO_STREAM("[CLTRRT] RRT* sol cost " << rrt_cost
277  << " after " << rrt_star_timeout << " secs.");
278  return rrt_cost;
279 }
280 
281 double CapsulatedLadderTreeRRTstar::solvePickNPlace(descartes_core::RobotModel& model,
282  double unit_process_timeout,
283  double rrt_star_timeout)
284 {
285  if(unit_process_timeout < 1.0)
286  {
287  logWarn("[CLT-RRT] unit process sampling timeout %.2f s, smaller than 1.0, set to default timeout %.2f s",
288  unit_process_timeout, DEFAULT_UNIT_PROCESS_TIMEOUT);
289  unit_process_timeout = DEFAULT_UNIT_PROCESS_TIMEOUT;
290  }
291 
292  if(rrt_star_timeout < 5.0)
293  {
294  double updated_rrt_star_timeout = 4*cap_rungs_.size();
295  logWarn("[CLT-RRT] rrt star timeout %.2f s, smaller than 5.0s, set to default timeout %.2f s",
296  rrt_star_timeout, updated_rrt_star_timeout);
297  }
298 
299  // find initial solution
300  size_t rung_id = 0;
301  CapVert* ptr_prev_vert = NULL;
302 
303  for(auto& cap_rung : cap_rungs_)
304  {
305  const auto unit_search_start = ros::Time::now();
306  auto unit_search_update = unit_search_start;
307  CapVert* ptr_cap_vert = new CapVert(model.getDOF());
308 
309  do
310  {
311  // TODO: app-dependent
312  std::vector<std::vector<Eigen::Affine3d>> poses = generateSamplePickNPlace(cap_rung, *ptr_cap_vert);
313 
314  // TODO: app-dependent
315  if(checkFeasibilityPickNPlace(model, poses, cap_rung, *ptr_cap_vert))
316  {
317  ptr_cap_vert->setParentVertPtr(ptr_prev_vert);
318  ptr_cap_vert->rung_id_ = rung_id;
319  cap_rung.ptr_cap_verts_.push_back(ptr_cap_vert);
320  ptr_prev_vert = ptr_cap_vert;
321  break;
322  }
323 
324  unit_search_update = ros::Time::now();
325  }
326  while((unit_search_update - unit_search_start).toSec() < unit_process_timeout);
327 
328  if(cap_rung.ptr_cap_verts_.empty())
329  {
330  // random sampling fails to find a solution
331  ROS_ERROR_STREAM("[CapRRTstar] process #" << rung_id
332  << " fails to find intial feasible sol within timeout "
333  << unit_process_timeout << "secs");
334  return std::numeric_limits<double>::max();
335  }
336 
337  ROS_INFO_STREAM("[CLTRRT] ik solutions found for process #" << rung_id);
338  rung_id++;
339  } // loop over cap_rungs
340 
341  double initial_sol_cost = cap_rungs_.back().ptr_cap_verts_.back()->getCost();
342  ROS_INFO_STREAM("[CLTRRT] initial sol found! cost: " << initial_sol_cost);
343  ROS_INFO_STREAM("[CLTRRT] RRT* improvement starts, computation time: " << rrt_star_timeout);
344 
345  // RRT* improve on the tree
346  const auto rrt_start_time = ros::Time::now();
347 
348  while((ros::Time::now() - rrt_start_time).toSec() < rrt_star_timeout)
349  {
350  // sample cap_rung
351  int rung_id_sample = randomSampleInt(0, cap_rungs_.size()-1);
352  auto& cap_rung_sample = cap_rungs_[rung_id_sample];
353 
354  // sample cap_vert
355  CapVert* ptr_new_vert = new CapVert(model.getDOF());
356 
357  // TODO: app-dependent
358  auto poses = generateSamplePickNPlace(cap_rung_sample, *ptr_new_vert);
359 
360  // TODO: app-dependent
361  if(checkFeasibilityPickNPlace(model, poses, cap_rung_sample, *ptr_new_vert))
362  {
363  // find nearest node in tree
364  double c_min = std::numeric_limits<double>::max();
365  CapVert* ptr_nearest_vert = NULL;
366 
367  if(rung_id_sample > 0)
368  {
369  for(auto& ptr_near_vert : this->cap_rungs_[rung_id_sample-1].ptr_cap_verts_)
370  {
371  double new_near_cost = ptr_near_vert->getCost() + ptr_new_vert->distance(ptr_near_vert);
372  if(c_min > new_near_cost)
373  {
374  ptr_nearest_vert = ptr_near_vert;
375  c_min = new_near_cost;
376  }
377  }
378  }
379 
380  // add new vert into CL tree (rung_id, parent_vert)
381  ptr_new_vert->rung_id_ = rung_id_sample;
382  ptr_new_vert->setParentVertPtr(ptr_nearest_vert);
383  cap_rung_sample.ptr_cap_verts_.push_back(ptr_new_vert);
384 
385  // update vert next (repair tree)
386  if(rung_id_sample < this->cap_rungs_.size()-1)
387  {
388  double new_vert_cost = ptr_new_vert->getCost();
389  for(auto& ptr_next_vert : this->cap_rungs_[rung_id_sample+1].ptr_cap_verts_)
390  {
391  double old_next_cost = ptr_next_vert->getCost();
392  double new_next_cost = new_vert_cost + ptr_next_vert->distance(ptr_new_vert);
393  if(old_next_cost > new_next_cost)
394  {
395  ptr_next_vert->setParentVertPtr(ptr_new_vert);
396  }
397  }
398  }
399  } // end if capvert feasible
400  }
401 
402  CapVert* ptr_last_cap_vert = *std::min_element(this->cap_rungs_.back().ptr_cap_verts_.begin(),
403  this->cap_rungs_.back().ptr_cap_verts_.end(), comparePtrCapVert);
404  double rrt_cost = ptr_last_cap_vert->getCost();
405 
406  ROS_INFO_STREAM("[CLTRRT] RRT* sol cost " << rrt_cost
407  << " after " << rrt_star_timeout << " secs.");
408  return rrt_cost;
409 }
410 
411 void CapsulatedLadderTreeRRTstar::extractSolution(descartes_core::RobotModel& model,
412  std::vector<descartes_core::TrajectoryPtPtr>& sol,
413  std::vector<descartes_planner::LadderGraph>& graphs,
414  std::vector<int>& graph_indices,
415  const bool use_saved_graph)
416 {
417  const auto graph_build_start = ros::Time::now();
418  const int dof = model.getDOF();
419 
420  if(!use_saved_graph)
421  {
422  graphs.clear();
423  graph_indices.clear();
424 
425  // find min cap_vert on last cap_rung
426  CapVert* ptr_last_cap_vert = *std::min_element(this->cap_rungs_.back().ptr_cap_verts_.begin(),
427  this->cap_rungs_.back().ptr_cap_verts_.end(), comparePtrCapVert);
428  while (ptr_last_cap_vert != NULL)
429  {
430  // construct unit ladder graph for each cap rungpath_pts_
431  const auto cap_rung = cap_rungs_[ptr_last_cap_vert->rung_id_];
432 
433  LadderGraph unit_ladder_graph(dof);
434 
435  // TODO: temp workaround to distinguish spatial extrusion and picknplace
436  if(-1 != ptr_last_cap_vert->z_axis_angle_)
437  {
438  double traverse_length = (cap_rung.path_pts_[0].front() - cap_rung.path_pts_[0].back()).norm();
439  const auto dt = traverse_length / cap_rung.linear_vel_;
440  model.setPlanningScene(cap_rung.planning_scene_[0]);
441 
442  unit_ladder_graph = sampleSingleConfig(model,
443  cap_rungs_[ptr_last_cap_vert->rung_id_].path_pts_[0],
444  dt,
445  ptr_last_cap_vert->orientation_[0],
446  ptr_last_cap_vert->z_axis_angle_);
447  }
448  else
449  {
450  assert(cap_rung.sub_segment_ids_.size() == cap_rung.path_pts_.size());
451  assert(cap_rung.sub_segment_ids_.size() == cap_rung.orientations_.size());
452  assert(cap_rung.sub_segment_ids_.size() == cap_rung. planning_scene_.size());
453 
454  for(int i=0; i < cap_rung.sub_segment_ids_.size(); i++)
455  {
456  double traverse_length = (cap_rung.path_pts_[i].front() - cap_rung.path_pts_[i].back()).norm();
457  const auto dt = traverse_length / cap_rung.linear_vel_;
458 
459  assert(cap_rung.path_pts_[i].size() == cap_rung.sub_segment_ids_[i]);
460 
461  model.setPlanningScene(cap_rung.planning_scene_[i]);
462 
463  appendInTime(unit_ladder_graph, sampleSingleConfig(model,
464  cap_rungs_[ptr_last_cap_vert->rung_id_].path_pts_[i],
465  ptr_last_cap_vert->orientation_[i],
466  dt));
467  }
468  }
469 
470  graphs.insert(graphs.begin(), unit_ladder_graph);
471  graph_indices.insert(graph_indices.begin(), unit_ladder_graph.size());
472  ptr_last_cap_vert = ptr_last_cap_vert->getParentVertPtr();
473  } // end while
474 
475  }
476  else
477  {
478  graph_indices.clear();
479  for(const auto& graph : graphs)
480  {
481  graph_indices.push_back(graph.size());
482  }
483  }
484 
485  // unify unit ladder graphs into one
486  descartes_planner::LadderGraph unified_graph(model.getDOF());
487  for(auto& graph : graphs)
488  {
489  assert(unified_graph.dof() == graph.dof());
490  descartes_planner::appendInTime(unified_graph, graph);
491  }
492 
493  // carry out DAG search on each ladder graph
494  descartes_planner::DAGSearch search(unified_graph);
495  double cost = search.run();
496  auto path_idxs = search.shortestPath();
497 
498  sol.clear();
499  for (size_t j = 0; j < path_idxs.size(); ++j)
500  {
501  const auto idx = path_idxs[j];
502  const auto* data = unified_graph.vertex(j, idx);
503  const auto& tm = unified_graph.getRung(j).timing;
504  auto pt = descartes_core::TrajectoryPtPtr(new descartes_trajectory::JointTrajectoryPt(
505  std::vector<double>(data, data + dof), tm));
506  sol.push_back(pt);
507  }
508 
509  auto graph_build_end = ros::Time::now();
510  ROS_INFO_STREAM("[CLTRRT] Graph construction and searching took: "
511  << (graph_build_end - graph_build_start).toSec() << " seconds");
512 }
513 
514 } //end namespace descartes planner
std::vector< planning_scene::PlanningScenePtr > planning_scene_
#define NULL
std::vector< Eigen::Vector3d > discretizePositions(const Eigen::Vector3d &start, const Eigen::Vector3d &stop, const double ds)
double solve(descartes_core::RobotModel &model, double clt_rrt_unit_process_timeout, double clt_rrt_timeout)
std::vector< std::vector< Eigen::Matrix3d > > orientations_
bool checkFeasibility(descartes_core::RobotModel &model, const std::vector< Eigen::Affine3d > &poses, descartes_planner::CapRung &cap_rung, descartes_planner::CapVert &cap_vert)
CapsulatedLadderTreeRRTstar(const std::vector< ConstrainedSegment > &segs, const std::vector< planning_scene::PlanningScenePtr > &planning_scenes, const std::vector< planning_scene::PlanningScenePtr > &planning_scenes_completed=std::vector< planning_scene::PlanningScenePtr >())
std::vector< std::vector< Eigen::Affine3d > > generateSamplePickNPlace(const descartes_planner::CapRung &cap_rung, descartes_planner::CapVert &cap_vert)
std::vector< std::vector< Eigen::Vector3d > > path_pts_
bool checkFeasibilityPickNPlace(descartes_core::RobotModel &model, const std::vector< std::vector< Eigen::Affine3d >> &poses, descartes_planner::CapRung &cap_rung, descartes_planner::CapVert &cap_vert)
double solvePickNPlace(descartes_core::RobotModel &model, double clt_rrt_unit_process_timeout, double clt_rrt_timeout)
std::vector< planning_scene::PlanningScenePtr > planning_scene_completed_
void setParentVertPtr(CapVert *ptr_v)
std::vector< Eigen::Matrix3d > orientation_
int randomSampleInt(int lower, int upper)
#define ROS_INFO_STREAM(args)
void extractSolution(descartes_core::RobotModel &model, std::vector< descartes_core::TrajectoryPtPtr > &sol, std::vector< descartes_planner::LadderGraph > &graphs, std::vector< int > &graph_indices, const bool use_saved_graph)
static Time now()
void appendInTime(LadderGraph &current, const LadderGraph &next)
static const double DEFAULT_UNIT_PROCESS_TIMEOUT
LadderGraph sampleSingleConfig(const descartes_core::RobotModel &model, const std::vector< Eigen::Vector3d > &origins, const Eigen::Matrix3d &orientation, const double dt)
#define ROS_ERROR_STREAM(args)
ROSCPP_DECL bool search(const std::string &ns, const std::string &key, std::string &result)
std::vector< Eigen::Affine3d > generateSample(const descartes_planner::CapRung &cap_rung, descartes_planner::CapVert &cap_vert)
double distance(CapVert *v) const


choreo_descartes_planner
Author(s): Yijiang Huang , Jonathan Meyer
autogenerated on Thu Jul 18 2019 03:58:35