path_transitions.cpp
Go to the documentation of this file.
1 //
2 // Created by yijiangh on 7/7/17.
3 //
4 #include "path_transitions.h"
5 #include "trajectory_utils.h"
6 
8 
9 // for extra descartes graph building feature
10 #include <descartes_planner/ladder_graph.h>
12 
13 // declare for descartes edge policy
14 namespace descartes_planner
15 {
16 typedef boost::function<double(const double*, const double*)> CostFunction;
17 }
18 
19 #include <descartes_planner/planning_graph_edge_policy.h>
20 #include <descartes_planner/ladder_graph_dag_search.h>
21 
23 #include <geometry_msgs/Vector3.h>
25 #include <Eigen/Geometry>
26 
27 const static double JTS_DISC_DELTA = 0.01; // radians
28 const static double RETRACT_OFFSET_SAMPLE_TIMEOUT = 5.0;
29 const static double MIN_RETRACTION_DIST = 0.003; // m
30 
31 namespace // anon namespace to hide utility functions
32 {
33 // TODO: should be moved to geometry_conversion_helpers
34 // convert orientations representing by Eigen3d::vector into Eigen::Matrix3d
35 void convertOrientationVector(
36  const std::vector<geometry_msgs::Vector3>& orients_msg,
37  std::vector<Eigen::Matrix3d>& m_orients)
38 {
39  m_orients.clear();
40 
41  for(auto v : orients_msg)
42  {
43  // eigen_vec = local z axis
44  Eigen::Vector3d eigen_vec;
45  tf::vectorMsgToEigen(v, eigen_vec);
46  eigen_vec *= -1.0;
47  eigen_vec.normalize();
48 
49  // construct local x axis & y axis
50  Eigen::Vector3d candidate_dir = Eigen::Vector3d::UnitX();
51  if (std::abs(eigen_vec.dot(Eigen::Vector3d::UnitX())) > 0.8)
52  {
53  // if z axis = UnitX,
54  candidate_dir = Eigen::Vector3d::UnitY();
55  }
56 
57  Eigen::Vector3d y_vec = eigen_vec.cross(candidate_dir).normalized();
58 
59  Eigen::Vector3d x_vec = y_vec.cross(eigen_vec).normalized();
60 
61  // JM
62  Eigen::Matrix3d m = Eigen::Matrix3d::Identity();
63  m.col(0) = x_vec;
64  m.col(1) = y_vec;
65  m.col(2) = eigen_vec;
66 
67  m_orients.push_back(m);
68  }
69 }
70 
71 } // end utility function ns
72 
74 {
75 std::vector<descartes_planner::ConstrainedSegmentPickNPlace> toDescartesConstrainedPath(
76  const choreo_msgs::AssemblySequencePickNPlace& as_pnp,
77  const std::vector<std::vector<planning_scene::PlanningScenePtr>>& planning_scene_subprocess,
78  const double& linear_vel, const double& linear_disc)
79 {
80  using ConstrainedSegmentPickNPlace = descartes_planner::ConstrainedSegmentPickNPlace;
81 
82  assert(linear_disc > 0 && linear_vel > 0);
83  assert(as_pnp.sequenced_elements.size() > 0);
84  assert(as_pnp.sequenced_elements.size() == planning_scene_subprocess.size());
85 
86  std::vector<ConstrainedSegmentPickNPlace> segs(as_pnp.sequenced_elements.size());
87 
88  for(int i=0;i <as_pnp.sequenced_elements.size(); i++)
89  {
90  const auto& se = as_pnp.sequenced_elements[i];
91 
92  assert(se.grasps.size() > 0);
93  segs[i].path_pts.resize(4);
94 
95  segs[i].path_pts[0].resize(2);
96  tf::pointMsgToEigen(se.grasps[0].pick_grasp_approach_pose.position, segs[i].path_pts[0][0]);
97  tf::pointMsgToEigen(se.grasps[0].pick_grasp_pose.position, segs[i].path_pts[0][1]);
98 
99  segs[i].path_pts[1].resize(2);
100  tf::pointMsgToEigen(se.grasps[0].pick_grasp_pose.position, segs[i].path_pts[1][0]);
101  tf::pointMsgToEigen(se.grasps[0].pick_grasp_retreat_pose.position, segs[i].path_pts[1][1]);
102 
103  segs[i].path_pts[2].resize(2);
104  tf::pointMsgToEigen(se.grasps[0].place_grasp_approach_pose.position, segs[i].path_pts[2][0]);
105  tf::pointMsgToEigen(se.grasps[0].place_grasp_pose.position, segs[i].path_pts[2][1]);
106 
107  segs[i].path_pts[3].resize(2);
108  tf::pointMsgToEigen(se.grasps[0].place_grasp_pose.position, segs[i].path_pts[3][0]);
109  tf::pointMsgToEigen(se.grasps[0].place_grasp_retreat_pose.position, segs[i].path_pts[3][1]);
110 
111  // six path points in total
112  segs[i].orientations.resize(4);
113 
114  for(int j=0; j < se.grasps.size(); j++)
115  {
116  const auto& g = se.grasps[j];
117  Eigen::Quaterniond q;
118 
119  // convert geometry_msgs::Quaterion back to eigen::Quaterion
120  // then back to matrix3d
121  tf::quaternionMsgToEigen(g.pick_grasp_approach_pose.orientation, q);
122  segs[i].orientations[0].push_back(q.toRotationMatrix());
123 
124  tf::quaternionMsgToEigen(g.pick_grasp_pose.orientation, q);
125  segs[i].orientations[1].push_back(q.toRotationMatrix());
126 
127  tf::quaternionMsgToEigen(g.place_grasp_approach_pose.orientation, q);
128  segs[i].orientations[2].push_back(q.toRotationMatrix());
129 
130  tf::quaternionMsgToEigen(g.place_grasp_pose.orientation, q);
131  segs[i].orientations[3].push_back(q.toRotationMatrix());
132  }
133 
134  // TODO: picknplace specific, hardcoded the number 4 here!
135  assert(planning_scene_subprocess[i].size() == 4);
136  segs[i].planning_scenes = planning_scene_subprocess[i];
137 
138  segs[i].linear_vel = linear_vel;
139  segs[i].linear_disc = linear_disc;
140  }
141 
142  return segs;
143 }
144 
145 std::vector <descartes_planner::ConstrainedSegment>
146 toDescartesConstrainedPath(const std::vector <choreo_msgs::ElementCandidatePoses> &task_sequence,
147  const ConstrainedSegParameters &seg_params)
148 {
149  using ConstrainedSegment = descartes_planner::ConstrainedSegment;
150 
151  assert(task_sequence.size() > 0);
152  std::vector<ConstrainedSegment> segs(task_sequence.size());
153 
154  assert(seg_params.linear_disc > 0 && seg_params.linear_vel > 0);
155  assert(seg_params.angular_disc > 0 && seg_params.retract_dist > 0);
156 
157  // Inline function for adding a sequence of motions
158  auto add_segment = [seg_params]
159  (ConstrainedSegment &seg, const choreo_msgs::ElementCandidatePoses path_pose)
160  {
161  tf::pointMsgToEigen(path_pose.start_pt, seg.start);
162  tf::pointMsgToEigen(path_pose.end_pt, seg.end);
163  convertOrientationVector(path_pose.feasible_orients, seg.orientations);
164 
165  seg.linear_vel = seg_params.linear_vel;
166  seg.linear_disc = seg_params.linear_disc;
167 
168  // TODO: spatial extrusion specific
169  switch (path_pose.type)
170  {
171  case choreo_msgs::ElementCandidatePoses::SUPPORT:
172  {
173  seg.process_type = ConstrainedSegment::PROCESS_TYPE::SUPPORT;
174  break;
175  }
176  case choreo_msgs::ElementCandidatePoses::CREATE:
177  {
178  seg.process_type = ConstrainedSegment::PROCESS_TYPE::CREATE;
179  break;
180  }
181  case choreo_msgs::ElementCandidatePoses::CONNECT:
182  {
183  seg.process_type = ConstrainedSegment::PROCESS_TYPE::CONNECT;
184  break;
185  }
186  }
187 
188  seg.z_axis_disc = seg_params.angular_disc;
189  seg.retract_dist = seg_params.retract_dist;
190  };
191 
192  for (std::size_t i = 0; i < task_sequence.size(); ++i)
193  {
194  add_segment(segs[i], task_sequence[i]);
195  } // end segments
196 
197  return segs;
198 }
199 
200 std::vector <descartes_planner::ConstrainedSegment> toDescartesConstrainedPath(
201  const std::vector<choreo_msgs::ElementCandidatePoses> &task_sequence,
202  const double &linear_vel, const double &linear_disc, const double &angular_disc, const double &retract_dist)
203 {
205  sp.linear_vel = linear_vel;
206  sp.linear_disc = linear_disc;
207  sp.angular_disc = angular_disc;
208  sp.retract_dist = retract_dist;
209 
210  return toDescartesConstrainedPath(task_sequence, sp);
211 }
212 
214  const std::vector<double> &start_joint, double retract_dist, double TCP_speed,
215  const std::vector <Eigen::Matrix3d> &eef_directions,
216  descartes_core::RobotModelPtr &model,
217  std::vector <std::vector<double>> &retract_jt_traj)
218 {
219  if (retract_dist < MIN_RETRACTION_DIST)
220  {
221  ROS_ERROR_STREAM("[process planning] recursive retraction sampling fails, retraction dist "
222  << retract_dist << "/" << MIN_RETRACTION_DIST);
223  return false;
224  }
225 
226  const int dof = model->getDOF();
227 
228  // solve FK to retrieve start eef plane
229  Eigen::Affine3d start_pose;
230  if (!model->getFK(start_joint, start_pose))
231  {
232  return false;
233  }
234 
235  const auto retract_sample_start = ros::Time::now();
236 
237  std::vector <Eigen::Affine3d> retract_eef_poses;
238  descartes_planner::LadderGraph graph(model->getDOF());
239 
240  const descartes_core::TimingConstraint timing(retract_dist / TCP_speed);
241 
242  // sample feasible directions for offset movement vector
243  bool first_try = true;
244  bool exist_pose_not_feasible = true;
245 
246  while ((ros::Time::now() - retract_sample_start).toSec() < RETRACT_OFFSET_SAMPLE_TIMEOUT)
247  {
248  // generate index sample
249  retract_eef_poses.clear();
250  graph.clear();
251 
252  Eigen::Matrix3d offset_vec;
253  if (first_try)
254  {
255  // transit the start eef plane along the direction of the local z axis
256  offset_vec = start_pose.matrix().block<3, 3>(0, 0);
257  }
258  else
259  {
260  int sample_id = descartes_planner::randomSampleInt(0, eef_directions.size() - 1);
261  offset_vec = eef_directions[sample_id];
262  }
263 
264  Eigen::Affine3d retract_pose =
265  start_pose * Eigen::Translation3d(retract_dist * offset_vec.col(2));
266 
267  auto st_pt = start_pose.matrix().col(3).head<3>();
268  auto end_pt = retract_pose.matrix().col(3).head<3>();
269  double ds = (st_pt - end_pt).norm() / 2;
270 
271  std::vector <Eigen::Vector3d> path_pts = descartes_planner::discretizePositions(st_pt, end_pt, ds);
272  graph.resize(path_pts.size());
273 
274  for (auto &pt : path_pts)
275  {
276  Eigen::Affine3d pose = start_pose;
277  pose.matrix().col(3).head<3>() = pt;
278 
279  retract_eef_poses.push_back(pose);
280  }
281 
282  exist_pose_not_feasible = false;
283 
284  for (int i = 0; i < retract_eef_poses.size(); i++)
285  {
286  std::vector <std::vector<double>> retract_jt_vec;
287  retract_jt_vec.clear();
288 
289  if (0 == i)
290  {
291  retract_jt_vec.push_back(start_joint);
292  }
293  else
294  {
295  if (!model->getAllIK(retract_eef_poses[i], retract_jt_vec))
296  {
297  exist_pose_not_feasible = true;
298  break;
299  }
300  }
301 
302  graph.assignRung(i, descartes_core::TrajectoryID::make_nil(), timing, retract_jt_vec);
303  }
304 
305  if (!exist_pose_not_feasible)
306  {
307  if (!first_try)
308  {
309  ROS_INFO_STREAM("[retraction planning] sampled retraction pose used.");
310  }
311 
312  break;
313  }
314 
315  first_try = false;
316  }
317 
318  for (std::size_t i = 0; i < graph.size(); i++)
319  {
320  if (0 == graph.rungSize(i) || exist_pose_not_feasible)
321  {
322  ROS_WARN_STREAM("[process planning] retraction sampling fails, recursively decrease retract dist to "
323  << retract_dist * 0.8);
324  return retractPath(start_joint, retract_dist * 0.8, TCP_speed, eef_directions, model, retract_jt_traj);
325  }
326  }
327 
328  // build edges
329  for (std::size_t i = 0; i < graph.size() - 1; ++i)
330  {
331  const auto start_idx = i;
332  const auto end_idx = i + 1;
333  const auto &joints1 = graph.getRung(start_idx).data;
334  const auto &joints2 = graph.getRung(end_idx).data;
335  const auto &tm = graph.getRung(end_idx).timing;
336 
337  const auto start_size = joints1.size() / dof;
338  const auto end_size = joints2.size() / dof;
339 
340  descartes_planner::DefaultEdgesWithTime builder(start_size, end_size, dof, tm.upper,
341  model->getJointVelocityLimits());
342  for (size_t k = 0; k < start_size; k++) // from rung
343  {
344  const auto start_index = k * dof;
345 
346  for (size_t j = 0; j < end_size; j++) // to rung
347  {
348  const auto end_index = j * dof;
349 
350  builder.consider(&joints1[start_index], &joints2[end_index], j);
351  }
352  builder.next(k);
353  }
354 
355  std::vector <descartes_planner::LadderGraph::EdgeList> edges = builder.result();
356 
357  graph.assignEdges(i, std::move(edges));
358  }
359 
360  descartes_planner::DAGSearch search(graph);
361  double cost = search.run();
362  auto path_idxs = search.shortestPath();
363 
364  retract_jt_traj.clear();
365  for (size_t j = 0; j < path_idxs.size(); ++j)
366  {
367  const auto idx = path_idxs[j];
368  const auto *data = graph.vertex(j, idx);
369  retract_jt_traj.push_back(std::vector<double>(data, data + dof));
370  }
371 
372  return true;
373 }
374 
375 }
std::vector< Eigen::Vector3d > discretizePositions(const Eigen::Vector3d &start, const Eigen::Vector3d &stop, const double ds)
q
boost::function< double(const double *, const double *)> CostFunction
static const double RETRACT_OFFSET_SAMPLE_TIMEOUT
std::size_t size(custom_string const &s)
v
bool retractPath(const std::vector< double > &start_joint, double retract_dist, double TCP_speed, const std::vector< Eigen::Matrix3d > &eef_directions, descartes_core::RobotModelPtr &model, std::vector< std::vector< double >> &retract_jt_traj)
void vectorMsgToEigen(const geometry_msgs::Vector3 &m, Eigen::Vector3d &e)
void pointMsgToEigen(const geometry_msgs::Point &m, Eigen::Vector3d &e)
static const double MIN_RETRACTION_DIST
#define ROS_WARN_STREAM(args)
static const double JTS_DISC_DELTA
std::vector< descartes_planner::ConstrainedSegment > toDescartesConstrainedPath(const std::vector< choreo_msgs::ElementCandidatePoses > &task_sequence, const double &linear_vel, const double &linear_disc, const double &angular_disc, const double &retract_dist)
int randomSampleInt(int lower, int upper)
#define ROS_INFO_STREAM(args)
void quaternionMsgToEigen(const geometry_msgs::Quaternion &m, Eigen::Quaterniond &e)
static Time now()
#define ROS_ERROR_STREAM(args)
ROSCPP_DECL bool search(const std::string &ns, const std::string &key, std::string &result)


choreo_process_planning
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:02