FiberPrintPlugIn.cpp
Go to the documentation of this file.
1 #include <ros/console.h>
2 
4 
5 // moveit model
7 
8 // msg
9 #include <choreo_msgs/ElementCandidatePoses.h>
10 #include <choreo_msgs/ModelInputParameters.h>
11 #include <choreo_msgs/TaskSequenceInputParameters.h>
12 #include <choreo_msgs/CollisionObjectList.h>
13 
14 // srv
15 #include <moveit_msgs/ApplyPlanningScene.h>
16 
17 // util
20 
21 const static std::string COLLISION_OBJ_PREFIX = "wireframe_element";
22 const static std::string APPLY_PLANNING_SCENE_SERVICE = "apply_planning_scene";
23 
24 namespace{
25 double dist(const Eigen::Vector3d& from, const Eigen::Vector3d& to)
26 {
27  return (from - to).norm();
28 }
29 
30 void createShrinkedEndPoint(Eigen::Vector3d& st_pt, Eigen::Vector3d& end_pt,
31  double shrink_length)
32 {
33  Eigen::Vector3d translation_vec = end_pt - st_pt;
34  translation_vec.normalize();
35 
36  if(2 * shrink_length > (st_pt - end_pt).norm())
37  {
38  ROS_WARN_STREAM("[tsp] shrink length longer than element length!");
39  shrink_length = 0.2 * (st_pt - end_pt).norm();
40  }
41 
42  st_pt = st_pt + shrink_length * translation_vec;
43  end_pt = end_pt - shrink_length * translation_vec;
44 }
45 
46 geometry_msgs::Pose computeCylinderPose(const Eigen::Vector3d& st_pt, const Eigen::Vector3d& end_pt)
47 {
48  geometry_msgs::Pose cylinder_pose;
49 
50  // rotation
51  Eigen::Vector3d axis = end_pt - st_pt;
52  axis.normalize();
53  Eigen::Vector3d z_vec(0.0, 0.0, 1.0);
54  const Eigen::Vector3d& x_vec = axis.cross(z_vec);
55 
56  tf::Quaternion tf_q;
57  if(0 == x_vec.norm())
58  {
59  // axis = z_vec
60  tf_q = tf::Quaternion(0, 0, 0, 1);
61  }
62  else
63  {
64  double theta = axis.dot(z_vec);
65  double angle = -1.0 * acos(theta);
66 
67  // convert eigen vertor to tf::Vector3
68  tf::Vector3 x_vec_tf;
69  tf::vectorEigenToTF(x_vec, x_vec_tf);
70 
71  // Create quaternion
72  tf_q = tf::Quaternion(x_vec_tf, angle);
73  tf_q.normalize();
74  }
75 
76  //back to ros coords
77  tf::quaternionTFToMsg(tf_q, cylinder_pose.orientation);
78  tf::pointEigenToMsg((end_pt + st_pt) * 0.5, cylinder_pose.position);
79 
80  return cylinder_pose;
81 }
82 
83 moveit_msgs::CollisionObject convertWFEdgeToCollisionObject(
84  int edge_id, const Eigen::Vector3d st_pt, const Eigen::Vector3d end_pt, double element_diameter,
85  const std::string world_frame)
86 {
87  moveit_msgs::CollisionObject collision_cylinder;
88  std::string cylinder_id = COLLISION_OBJ_PREFIX + std::to_string(edge_id);
89 
90  collision_cylinder.id = cylinder_id;
91  collision_cylinder.header.frame_id = world_frame;
92  collision_cylinder.operation = moveit_msgs::CollisionObject::ADD;
93 
94  shape_msgs::SolidPrimitive cylinder_solid;
95  cylinder_solid.type = shape_msgs::SolidPrimitive::CYLINDER;
96  cylinder_solid.dimensions.resize(2);
97 
98  cylinder_solid.dimensions[0] = dist(st_pt, end_pt);
99 
100  cylinder_solid.dimensions[1] = element_diameter;
101  collision_cylinder.primitives.push_back(cylinder_solid);
102  collision_cylinder.primitive_poses.push_back(computeCylinderPose(st_pt, end_pt));
103 
104  return collision_cylinder;
105 }
106 
107 void convertWireFrameToMsg(
108  const choreo_msgs::ModelInputParameters& model_params,
109  WireFrame& wire_frame, std::vector<choreo_msgs::ElementCandidatePoses>& wf_msgs,
110  double& unit_scale,
111  const std::string world_frame)
112 {
113  wf_msgs.clear();
114 
115  // set unit scale
116  switch (model_params.unit_type)
117  {
118  case choreo_msgs::ModelInputParameters::MILLIMETER:
119  {
120  unit_scale = 0.001;
121  break;
122  }
123  case choreo_msgs::ModelInputParameters::CENTIMETER:
124  {
125  unit_scale = 0.01;
126  break;
127  }
128  case choreo_msgs::ModelInputParameters::INCH:
129  {
130  unit_scale = 0.0254;
131  break;
132  }
133  case choreo_msgs::ModelInputParameters::FOOT:
134  {
135  unit_scale = 0.3048;
136  break;
137  }
138  default:
139  {
140  ROS_ERROR("Unrecognized Unit type in Model Input Parameters!");
141  }
142  }
143 
144  // TODO: this might cause out-of-scale problem!!!
145  // default wireframe is in millimeter and might be different to user-specified unit in mpp
146  // wireframe default unit is mm, convert to meter
147  const auto &base_pt = wire_frame.GetBaseCenterPos();
148  Eigen::Vector3d transf_vec = Eigen::Vector3d(model_params.ref_pt_x * unit_scale - base_pt.x() * 0.001,
149  model_params.ref_pt_y * unit_scale - base_pt.y() * 0.001,
150  model_params.ref_pt_z * unit_scale - base_pt.z() * 0.001);
151 
152  wf_msgs.resize(wire_frame.SizeOfEdgeList());
153 
154  for (std::size_t i = 0; i < wire_frame.SizeOfEdgeList(); i++)
155  {
156  WF_edge *e = wire_frame.GetEdge(i);
157 
158  if (e->ID() < e->ppair_->ID())
159  {
160  choreo_msgs::ElementCandidatePoses element_msg;
161  element_msg.element_id = e->ID();
162 
163  // notice these node positions are out-of-scale, default wireframe unit is millimeter
164  // unit converted to meter
165  Eigen::Vector3d eigen_st_pt(e->ppair_->pvert_->Position().x(),
166  e->ppair_->pvert_->Position().y(),
167  e->ppair_->pvert_->Position().z());
168  eigen_st_pt = eigen_st_pt * 0.001 + transf_vec;
169 
170  Eigen::Vector3d eigen_end_pt(e->pvert_->Position().x(),
171  e->pvert_->Position().y(),
172  e->pvert_->Position().z());
173  eigen_end_pt = eigen_end_pt * 0.001 + transf_vec;
174 
175  // in meter
176  tf::pointEigenToMsg(eigen_st_pt, element_msg.start_pt);
177  tf::pointEigenToMsg(eigen_end_pt, element_msg.end_pt);
178 
179  element_msg.element_diameter = model_params.element_diameter * unit_scale;
180 
181  element_msg.layer_id = e->Layer();
182 
183  // create collision objs
184  Eigen::Vector3d shrinked_st_pt = eigen_st_pt;
185  Eigen::Vector3d shrinked_end_pt = eigen_end_pt;
186  createShrinkedEndPoint(shrinked_st_pt, shrinked_end_pt, model_params.shrink_length * unit_scale);
187 
188  element_msg.both_side_shrinked_collision_object = convertWFEdgeToCollisionObject(
189  e->ID(), shrinked_st_pt, shrinked_end_pt, element_msg.element_diameter, world_frame);
190 
191  element_msg.st_shrinked_collision_object = convertWFEdgeToCollisionObject(
192  e->ID(), shrinked_st_pt, eigen_end_pt, element_msg.element_diameter, world_frame );
193 
194  element_msg.end_shrinked_collision_object = convertWFEdgeToCollisionObject(
195  e->ID(), eigen_st_pt, shrinked_end_pt, element_msg.element_diameter, world_frame);
196 
197  element_msg.full_collision_object = convertWFEdgeToCollisionObject(
198  e->ID(), eigen_st_pt, eigen_end_pt, element_msg.element_diameter, world_frame);
199 
200  // TODO: this is redundant, a quick patch to make it work with wireframe's double-edge
201  // data structure
202  wf_msgs[e->ID()] = element_msg;
203  wf_msgs[e->ppair_->ID()] = element_msg;
204  }
205  }
206 }
207 
208 // TODO: temp functions
209 moveit_msgs::CollisionObject createPrintTable(const Eigen::Vector3d& ref_pt, const double unit_scale, const std::string world_frame)
210 {
211  // for now, only a simple flat box, representing the build plate, is added.
212  // TODO: might need to use load mesh approach for user-customized scene collision setup
213  // https://github.com/JeroenDM/descartes_tutorials/blob/indigo-devel/tutorial_utilities/src/collision_object_utils.cpp
214 
215  moveit_msgs::CollisionObject collision_env_obj;
216  std::string env_obj_id = "env_obj_table";
217 
218  // table box's dimension
219  double dx = 1;
220  double dy = 1;
221  double dz = 0.03;
222 
223  // pose
224  Eigen::Affine3d rtn = Eigen::Translation3d(ref_pt[0] * unit_scale,
225  ref_pt[1] * unit_scale,
226  ref_pt[2] * unit_scale - dz/2)
227  * Eigen::AngleAxisd(0, Eigen::Vector3d::UnitX())
228  * Eigen::AngleAxisd(0, Eigen::Vector3d::UnitY())
229  * Eigen::AngleAxisd(0, Eigen::Vector3d::UnitZ());
230  geometry_msgs::Pose pose;
231  tf::poseEigenToMsg(rtn, pose);
232 
233  collision_env_obj.id = env_obj_id;
234  collision_env_obj.header.frame_id = world_frame;
235  collision_env_obj.operation = moveit_msgs::CollisionObject::ADD;
236 
237  shape_msgs::SolidPrimitive env_obj_solid;
238  env_obj_solid.type = shape_msgs::SolidPrimitive::BOX;
239  env_obj_solid.dimensions.resize(3);
240  env_obj_solid.dimensions[0] = dx;
241  env_obj_solid.dimensions[1] = dy;
242  env_obj_solid.dimensions[2] = dz;
243  collision_env_obj.primitives.push_back(env_obj_solid);
244  collision_env_obj.primitive_poses.push_back(pose);
245 
246  return collision_env_obj;
247 }
248 
249 bool addCollisionObject(const moveit_msgs::CollisionObject& c_obj)
250 {
251  ros::NodeHandle nh;
252  ros::ServiceClient planning_scene_diff_client =
253  nh.serviceClient<moveit_msgs::ApplyPlanningScene>(APPLY_PLANNING_SCENE_SERVICE);
254 
255  if(planning_scene_diff_client.waitForExistence())
256  {
257 // ROS_INFO_STREAM("planning scene diff srv connected!");
258  }
259  else
260  {
261  ROS_ERROR_STREAM("[ts planning] cannot connect with planning scene diff server...");
262  }
263 
264  moveit_msgs::ApplyPlanningScene srv;
265 
266  moveit_msgs::PlanningScene planning_scene_msg;
267  planning_scene_msg.world.collision_objects.push_back(c_obj);
268  planning_scene_msg.is_diff = true;
269  srv.request.scene = planning_scene_msg;
270 
271  if(planning_scene_diff_client.call(srv))
272  {
273 // ROS_INFO_STREAM("adding new collision object to planning scene published!");
274  return true;
275  }
276  else
277  {
278  ROS_ERROR_STREAM("[ts planning] Failed to publish planning scene diff srv!");
279  return false;
280  }
281 }
282 
283 }// util namespace
284 
285 FiberPrintPlugIn::FiberPrintPlugIn(const std::string& world_frame,
286  const std::string& hotend_group, const std::string& hotend_tcp, const std::string& hotend_base,
287  const std::string& robot_model_plugin)
288  : plugin_loader_("descartes_core", "descartes_core::RobotModel"),
289  hotend_group_name_(hotend_group)
290 {
291  ptr_frame_ = NULL;
292  ptr_dualgraph_ = NULL;
293  ptr_collision_ = NULL;
294  ptr_stiffness_ = NULL;
295 
296  ptr_seqanalyzer_ = NULL;
297  ptr_procanalyzer_ = NULL;
298 
299  ptr_path_ = NULL;
300  ptr_parm_ = NULL;
301 
302  terminal_output_ = false;
303  file_output_ = false;
304 
305  // Attempt to load and initialize the printing robot model (hotend)
306  hotend_model_ = plugin_loader_.createInstance(robot_model_plugin);
307  if (!hotend_model_)
308  {
309  throw std::runtime_error(std::string("[seq planner] Could not load: ") + robot_model_plugin);
310  }
311 
312  if (!hotend_model_->initialize("robot_description", hotend_group, hotend_base, hotend_tcp))
313  {
314  throw std::runtime_error("[seq planner] Unable to initialize printing robot model");
315  }
316 
317  // Load the moveit model
319  moveit_model_ = robot_model_loader.getModel();
320 
321  if (moveit_model_.get() == NULL)
322  {
323  throw std::runtime_error("[seq planner] Could not load moveit robot model");
324  }
325 
326  // Enable Collision Checks
327  hotend_model_->setCheckCollisions(true);
328 
329  // set world frame
330  world_frame_ = world_frame;
331 }
332 
334 {
335  delete ptr_dualgraph_;
336  ptr_dualgraph_ = NULL;
337 
338  delete ptr_collision_;
339  ptr_collision_ = NULL;
340 
341  delete ptr_stiffness_;
342  ptr_stiffness_ = NULL;
343 
344  delete ptr_seqanalyzer_;
345  ptr_seqanalyzer_ = NULL;
346 
347  delete ptr_procanalyzer_;
348  ptr_procanalyzer_ = NULL;
349 
350  delete ptr_parm_;
351  ptr_parm_ = NULL;
352 
353  delete ptr_frame_;
354  ptr_frame_ = NULL;
355 }
356 
358 {
359  if(ptr_frame_ != NULL && ptr_parm_ != NULL && ptr_path_ != NULL)
360  {
361  delete ptr_dualgraph_;
363 
364  delete ptr_collision_;
366 
367  delete ptr_stiffness_;
370  ptr_path_, false);
371 
372  delete ptr_seqanalyzer_;
373  ptr_seqanalyzer_ = NULL;
374 
375  delete ptr_procanalyzer_;
376  ptr_procanalyzer_ = NULL;
377 
378  return true;
379  }
380  else
381  {
382  return false;
383  }
384 }
385 
387 {
389 
390  if(Init())
391  {
392  assert(ptr_frame_->SizeOfEdgeList() == frame_msgs_.size());
393 
398  ptr_parm_,
399  ptr_path_,
401  file_output_,
405  );
406 
407  ptr_seqanalyzer_->setFrameMsgs(frame_msgs_);
408 
409  ROS_INFO_STREAM("[TSP] Seq Analyzer init.");
410 
411  std::vector<int> target_ids;
412  for(int i = 37; i <= 39; i++)
413  {
414  target_ids.push_back(i);
415  }
416 
417  if (!ptr_seqanalyzer_->SeqPrint())
418  {
419  ROS_WARN("Model not printable!");
420  return false;
421  }
422 
423  fiber_print_.Stop();
424  fiber_print_.Print("Direct Search:");
425 
426  return true;
427  }
428  else
429  {
430  ROS_WARN_STREAM("[ts planning] wireframe, fiber_print parm or output_path not initiated."
431  << "ts planning failed.");
432  return false;
433  }
434 }
435 
436 bool FiberPrintPlugIn::ConstructCollisionObjects(const std::vector<int>& print_queue_edge_ids,
437  std::vector<choreo_msgs::WireFrameCollisionObject>& collision_objs)
438 {
439  if(Init())
440  {
441  assert(ptr_frame_->SizeOfEdgeList() == frame_msgs_.size());
442 
447  ptr_parm_,
448  ptr_path_,
450  file_output_,
454  );
455 
456  ptr_seqanalyzer_->setFrameMsgs(frame_msgs_);
457 
458  return ptr_seqanalyzer_->ConstructCollisionObjsInQueue(print_queue_edge_ids, collision_objs);
459  }
460  else
461  {
462  ROS_WARN_STREAM("[ts planning] wireframe, fiber_print parm or output_path not initiated."
463  << "constructing collision objs in ts planning failed.");
464  return false;
465  }
466 }
467 
469 {
470  bool success = false;
471 
472  if(NULL != ptr_parm_)
473  {
474  delete ptr_parm_;
475  }
476 
477  ptr_parm_ = new FiberPrintPARM();
478 
479  // dummy choreo output path
480  ptr_path_ = "/home";
481 
482  if(Init())
483  {
485 
486  VX D;
487  ptr_stiffness_->Init();
490 
491  success = ptr_stiffness_->CalculateD(D, NULL, true, 0, "FiberTest");
492 
493  if (success)
494  {
495  ROS_INFO_STREAM("[ts planner] Maximal node deforamtion (mm): " << D.maxCoeff()
496  << ", tolerance (mm): " << ptr_parm_->seq_D_tol_);
497  }
498  else
499  {
500  ROS_ERROR("[ts planner] stiffness computation fails.");
501  }
502 
504  }
505  else
506  {
507  success = false;
508  ROS_ERROR("[ts planner] Get Deformation: init fails.");
509  }
510 
511  if(!success)
512  {
513  ROS_ERROR("[ts planner] whole model deformation fails.");
514  }
515 }
516 
518  choreo_msgs::TaskSequencePlanning::Request& req,
519  choreo_msgs::TaskSequencePlanning::Response& res)
520 {
521  switch(req.action)
522  {
523  case choreo_msgs::TaskSequencePlanning::Request::READ_WIREFRAME:
524  {
525  std::string file_path = req.model_params.file_name;
526 
527  // TODO: all of these char* should be const char*
528  // convert std::string to writable char*
529  std::vector<char> fp(file_path.begin(), file_path.end());
530  fp.push_back('\0');
531 
532  if(NULL != ptr_frame_)
533  {
534  delete ptr_frame_;
535  }
536 
537  // TODO: if contains keyword "pwf"
538  ptr_frame_ = new WireFrame();
539  ptr_frame_->LoadFromPWF(&fp[0]);
540 
541  ROS_INFO_STREAM("[Ts planning] wire frame read : " << file_path);
542 
543  double unit_scale;
544  Eigen::Vector3d ref_pt(req.model_params.ref_pt_x, req.model_params.ref_pt_y, req.model_params.ref_pt_z);
545 
546  // TODO: temp functions
547  convertWireFrameToMsg(req.model_params, *ptr_frame_, frame_msgs_, unit_scale, world_frame_);
548 
549  moveit_msgs::CollisionObject table = createPrintTable(ref_pt, unit_scale, world_frame_);
550  addCollisionObject(table);
551 
552  res.element_array = frame_msgs_;
553 
554  // get deformation
555 // GetDeformation();
556 
557  break;
558  }
559  case choreo_msgs::TaskSequencePlanning::Request::TASK_SEQUENCE_SEARCHING:
560  {
561  double Wp = 1.0;
562  double Wa = 1.0;
563  double Wi = 3.0;
564 
565  if(NULL != ptr_parm_)
566  {
567  delete ptr_parm_;
568  }
569 
570  ptr_parm_ = new FiberPrintPARM(Wp, Wa, Wi);
571 
572  // dummy choreo output path
573  ptr_path_ = "/home";
574  const char* json_output_path = req.task_sequence_params.file_path.c_str();
575 
576  terminal_output_ = true;
577 
578  if(DirectSearch())
579  {
580  assert(NULL != ptr_seqanalyzer_);
581 
582  ptr_procanalyzer_ = new ProcAnalyzer(ptr_seqanalyzer_, json_output_path);
583 
585  {
586  ROS_ERROR_STREAM("[ts planner] proc analyzer failed.");
587  return false;
588  }
589  }
590  else
591  {
592  ROS_ERROR_STREAM("[ts planner] direct searching failed.");
593  return false;
594  }
595 
596  break;
597  }
598  case choreo_msgs::TaskSequencePlanning::Request::REQUEST_COLLISION_OBJS:
599  {
600  if(NULL != ptr_parm_)
601  {
602  delete ptr_parm_;
603  }
604 
605  // dummy parm
606  ptr_parm_ = new FiberPrintPARM(0, 0, 0);
607 
608  // dummy choreo output path
609  ptr_path_ = "/home";
610 
611  terminal_output_ = true;
612 
613  // construct wireframe ids in the queue
614  std::vector<int> wireframe_ids;
615 
616  for(const auto& element : req.element_array)
617  {
618  wireframe_ids.push_back(element.wireframe_id);
619  }
620 
621  if(!ConstructCollisionObjects(wireframe_ids, res.wf_collision_objs))
622  {
623  ROS_ERROR_STREAM("[ts planner] construct collision objects failed.");
624  return false;
625  }
626 
627  break;
628  }
629  default:
630  {
631  ROS_ERROR_STREAM("[ts planning] unknown task sequence planning request action.");
632  return false;
633  }
634  }
635 
636  return true;
637 }
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
bool CalculateD(VX &D, VX *ptr_x=NULL, bool cond_num=false, int file_id=0, string file_name="")
Definition: Stiffness.cpp:407
axis
SeqAnalyzer * ptr_seqanalyzer_
WireFrame * ptr_frame_
static const std::string COLLISION_OBJ_PREFIX
Eigen::VectorXd VX
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
GLenum GLenum GLsizei void * table
FiberPrintPlugIn(const std::string &world_frame, const std::string &hotend_group, const std::string &hotend_tcp, const std::string &hotend_base, const std::string &robot_model_plugin)
void Init()
Definition: Stiffness.cpp:54
GLfloat angle
bool call(MReq &req, MRes &res)
WF_edge * GetEdge(int i)
Definition: WireFrame.h:238
reference x()
Definition: Vec.h:194
static const std::string APPLY_PLANNING_SCENE_SERVICE
Quaternion & normalize()
void vectorEigenToTF(const Eigen::Vector3d &e, tf::Vector3 &t)
StiffnessSolver stiff_solver_
Definition: Stiffness.h:144
#define ROS_WARN(...)
moveit::core::RobotModelConstPtr moveit_model_
static const T dist(const Vec< D, T > &v1, const Vec< D, T > &v2)
Definition: Vec.h:905
void LoadFromPWF(const char *path)
Definition: WireFrame.cpp:148
Vec3f GetBaseCenterPos() const
Definition: WireFrame.h:249
QuadricCollision * ptr_collision_
pluginlib::ClassLoader< descartes_core::RobotModel > plugin_loader_
void Stop()
Definition: Timer.cpp:21
descartes_core::RobotModelPtr hotend_model_
int ID() const
Definition: WireFrame.h:123
Stiffness * ptr_stiffness_
bool handleTaskSequencePlanning(choreo_msgs::TaskSequencePlanning::Request &req, choreo_msgs::TaskSequencePlanning::Response &res)
WF_edge * ppair_
Definition: WireFrame.h:166
int Layer() const
Definition: WireFrame.h:124
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
FiberPrintPARM * ptr_parm_
std::vector< choreo_msgs::ElementCandidatePoses > frame_msgs_
std::string world_frame_
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
DualGraph * ptr_dualgraph_
bool ProcPrint()
reference y()
Definition: Vec.h:203
#define ROS_WARN_STREAM(args)
void PrintOutTimer()
Definition: Stiffness.cpp:704
bool ConstructCollisionObjects(const std::vector< int > &print_queue_edge_ids, std::vector< choreo_msgs::WireFrameCollisionObject > &collision_objs)
void pointEigenToMsg(const Eigen::Vector3d &e, geometry_msgs::Point &m)
void Start()
Definition: Timer.cpp:15
WF_vert * pvert_
Definition: WireFrame.h:164
#define ROS_INFO_STREAM(args)
void Print(char *item)
Definition: Timer.cpp:37
ProcAnalyzer * ptr_procanalyzer_
void Dualization()
Definition: DualGraph.cpp:103
GLuint res
const robot_model::RobotModelPtr & getModel() const
#define ROS_ERROR_STREAM(args)
bool terminal_output_
Definition: Stiffness.h:172
reference z()
Definition: Vec.h:212
#define ROS_ERROR(...)
std::string hotend_group_name_
int SizeOfEdgeList() const
Definition: WireFrame.h:228
point Position() const
Definition: WireFrame.h:78


choreo_task_sequence_planner
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:03:14