modify_trajectory.cpp
Go to the documentation of this file.
1 #include <mutex>
2 #include <string>
3 #include <strings.h>
4 
5 #include <ros/ros.h>
6 #include <Eigen/Geometry>
8 
9 #include <ram_modify_trajectory/AddPoses.h>
10 #include <ram_modify_trajectory/DeleteSelectedPoses.h>
11 #include <ram_modify_trajectory/ModifySelectedPoses.h>
12 #include <ram_modify_trajectory/ReflectSelectedPoses.h>
13 #include <ram_modify_trajectory/ResetSelectedPoses.h>
14 #include <ram_modify_trajectory/RotateSelectedPoses.h>
15 #include <ram_modify_trajectory/ScaleSelectedPoses.h>
16 #include <ram_msgs/AdditiveManufacturingPose.h>
17 #include <ram_msgs/AdditiveManufacturingTrajectory.h>
18 #include <ram_utils/UnmodifiedTrajectory.h>
19 #include <ram_utils/AddEntryExitStrategies.h>
20 
21 #include <unique_id/unique_id.h>
22 #include <uuid_msgs/UniqueID.h>
23 
27 
28 std::mutex layers_mutex;
29 ram_msgs::AdditiveManufacturingTrajectory layers;
30 
31 // Functions
32 
33 bool verifyPolygonLimits(ram_msgs::AdditiveManufacturingTrajectory trajectory)
34 {
35  bool pose_in_polygon = false;
36 
37  for (auto current_pose : trajectory.poses)
38  {
39  if ((current_pose.polygon_start || current_pose.polygon_end) && (current_pose.entry_pose || current_pose.exit_pose))
40  return false;
41 
42  if (current_pose.polygon_start && current_pose.polygon_end)
43  continue;
44 
45  if (current_pose.polygon_start)
46  {
47  if (!pose_in_polygon)
48  pose_in_polygon = true;
49  else
50  return false;
51  }
52  if (current_pose.polygon_end)
53  {
54  if (pose_in_polygon)
55  pose_in_polygon = false;
56  else
57  return false;
58  }
59  }
60  if (pose_in_polygon)
61  return false;
62 
63  return true;
64 }
65 
66 bool deletePoses(ram_msgs::AdditiveManufacturingTrajectory &trajectory,
67  std::vector<ram_msgs::AdditiveManufacturingPose> poses)
68 {
69  for (unsigned i(0); i < poses.size(); ++i)
70  {
71  std::string selected_pose_uuid = unique_id::toHexString(poses[i].unique_id);
72  bool pose_is_deleted = false;
73 
74  // Poses in the trajectory
75  for (unsigned j(0); j < trajectory.poses.size(); ++j)
76  {
77  std::string current_uuid = unique_id::toHexString(trajectory.poses[j].unique_id);
78  if (selected_pose_uuid.compare(current_uuid) != 0) // uuid are not equals
79  continue;
80 
81  trajectory.poses.erase(trajectory.poses.begin() + j); // Delete pose
82  pose_is_deleted = true;
83  break;
84  }
85 
86  if (!pose_is_deleted) // Selected pose is not in the trajectory
87  {
88  ROS_ERROR_STREAM("Pose to be deleted could not be found, UUID = " << selected_pose_uuid);
89  return false;
90  }
91  }
92 
93  trajectory.similar_layers = false;
94  return true;
95 }
96 
97 bool findPose(std::string pose_uuid, std::vector<ram_msgs::AdditiveManufacturingPose> poses,
98  ram_msgs::AdditiveManufacturingPose &pose)
99 {
100  for (auto current_pose : poses)
101  {
102  std::string current_pose_uuid = unique_id::toHexString(current_pose.unique_id);
103  if (pose_uuid.compare(current_pose_uuid) != 0) // uuid are not equals
104  continue;
105  // uuid are equals
106  pose = current_pose;
107  return true;
108  }
109  return false;
110 }
111 
112 void saveTrajectoryCallback(const ram_msgs::AdditiveManufacturingTrajectoryConstPtr& msg)
113 {
114  std::lock_guard<std::mutex> lock(layers_mutex);
115  layers = *msg;
116 }
117 
118 bool modifySelectedPosesCallback(ram_modify_trajectory::ModifySelectedPoses::Request &req,
119  ram_modify_trajectory::ModifySelectedPoses::Response &)
120 {
121  std::lock_guard<std::mutex> lock(layers_mutex);
122  // Make a copy and modify this copy
123  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
124 
125  if (req.poses.empty())
126  {
127  ROS_ERROR_STREAM("Request is empty");
128  return false;
129  }
130 
131  if (trajectory.poses.empty())
132  {
133  ROS_ERROR_STREAM("Trajectory is empty");
134  return false;
135  }
136 
137  std::vector<ram_msgs::AdditiveManufacturingPose> strategies_to_delete; // Strategies to delete when a polygon_start or a polygon_end is modified
138 
139  std::vector<ram_msgs::AdditiveManufacturingParams::_movement_type_type> move_types;
140  for (auto pose : req.poses)
141  move_types.push_back(pose.params.movement_type);
142 
143  if (std::adjacent_find(move_types.begin(), move_types.end(), std::not_equal_to<int>()) != move_types.end())
144  {
145  // Cannot modify speed if not all the poses have the same motion type
146  if (req.speed)
147  {
148  ROS_ERROR_STREAM("Cannot modify speed if not all the poses have the same motion type");
149  return false;
150  }
151  }
152 
153  // Modify poses
154  for (unsigned i(0); i < req.poses.size(); ++i)
155  {
156  std::string selected_pose_uuid = unique_id::toHexString(req.poses[i].unique_id);
157  bool pose_in_trajectory = false;
158 
159  for (unsigned j(0); j < trajectory.poses.size(); ++j)
160  {
161  std::string current_pose_uuid = unique_id::toHexString(trajectory.poses[j].unique_id);
162 
163  if (current_pose_uuid.compare(selected_pose_uuid) != 0) // uuid are not equals
164  continue;
165 
166  // uuid are equals. Modify this pose
167  pose_in_trajectory = true;
168  // Booleans
169  //
170  // Numerical value:
171  // True = Absolute
172  // False = Relative
173  //
174  // Non numerical value:
175  // True = Modify
176  // False = Keep value
177 
178  // Replace and check values
179  if (req.pose)
180  trajectory.poses[j].pose = req.pose_reference.pose;
181  else
182  {
183  Eigen::Affine3d current_pose_eigen, reference_pose;
184  tf::poseMsgToEigen(trajectory.poses[j].pose, current_pose_eigen);
185  tf::poseMsgToEigen(req.pose_reference.pose, reference_pose);
186 
187  current_pose_eigen.matrix() *= reference_pose.matrix();
188  tf::poseEigenToMsg(current_pose_eigen, trajectory.poses[j].pose);
189  }
190 
191  // Non numerical values
192  if (req.polygon_start)
193  {
194  if (trajectory.poses[j].polygon_start && !req.pose_reference.polygon_start)
195  {
196  // Save the entry strategy in the vector
197  for (int strategy_id(j - 1); strategy_id >= 0; --strategy_id)
198  {
199  if (trajectory.poses[strategy_id].entry_pose)
200  strategies_to_delete.push_back(trajectory.poses[strategy_id]);
201  else
202  break;
203  }
204  }
205 
206  trajectory.poses[j].polygon_start = req.pose_reference.polygon_start;
207  }
208 
209  if (req.polygon_end)
210  {
211  // Save the exit strategy in the vector
212  if (trajectory.poses[j].polygon_end && !req.pose_reference.polygon_end)
213  {
214  for (unsigned strategy_id(j + 1); strategy_id < trajectory.poses.size(); ++strategy_id)
215  {
216  if (trajectory.poses[strategy_id].exit_pose)
217  strategies_to_delete.push_back(trajectory.poses[strategy_id]);
218  else
219  break;
220  }
221  }
222  trajectory.poses[j].polygon_end = req.pose_reference.polygon_end;
223  }
224 
225  if (req.movement_type)
226  trajectory.poses[j].params.movement_type = req.pose_reference.params.movement_type;
227 
228  if (req.approach_type)
229  trajectory.poses[j].params.approach_type = req.pose_reference.params.approach_type;
230 
231  // Numerical values
232  if (req.blend_radius)
233  trajectory.poses[j].params.blend_radius = req.pose_reference.params.blend_radius;
234  else
235  {
236  trajectory.poses[j].params.blend_radius += req.pose_reference.params.blend_radius;
237 
238  if (trajectory.poses[j].params.blend_radius < 0)
239  {
240  ROS_ERROR_STREAM("Blend radius cannot be < 0");
241  return false;
242  }
243 
244  if (trajectory.poses[j].params.blend_radius > 100)
245  {
246  ROS_ERROR_STREAM("Blend radius cannot be > 100");
247  return false;
248  }
249  }
250 
251  if (req.speed)
252  trajectory.poses[j].params.speed = req.pose_reference.params.speed;
253  else
254  {
255  trajectory.poses[j].params.speed += req.pose_reference.params.speed;
256 
257  if (trajectory.poses[j].params.speed < 1e-12) // Cannot be zero
258  {
259  ROS_ERROR_STREAM("Robot speed cannot be < 1e-12");
260  return false;
261  }
262  }
263 
264  if (req.laser_power)
265  trajectory.poses[j].params.laser_power = req.pose_reference.params.laser_power;
266  else
267  {
268  trajectory.poses[j].params.laser_power += req.pose_reference.params.laser_power;
269 
270  if (trajectory.poses[j].params.laser_power < 0)
271  {
272  ROS_ERROR_STREAM("Laser power cannot be < 0");
273  return false;
274  }
275  }
276 
277  if (req.feed_rate)
278  trajectory.poses[j].params.feed_rate = req.pose_reference.params.feed_rate;
279  else
280  {
281  trajectory.poses[j].params.feed_rate += req.pose_reference.params.feed_rate;
282 
283  if (trajectory.poses[j].params.feed_rate < 0)
284  {
285  ROS_ERROR_STREAM("Feed rate cannot be < 0");
286  return false;
287  }
288  }
289 
290  break; // Exit to for loop
291  }
292  if (!pose_in_trajectory)
293  {
294  ROS_ERROR_STREAM("There are pose in the request that are not in the trajectory");
295  return false;
296  }
297  }
298 
299  // Delete the strategies
300  if (!deletePoses(trajectory, strategies_to_delete))
301  {
302  ROS_ERROR_STREAM("Errer deleting strategies_to_delete");
303  return false;
304  }
305 
306  // Verify polygon_start and polygon_end
307  if (!verifyPolygonLimits(trajectory))
308  {
309  ROS_ERROR_STREAM("Error in verifyPolygonLimits");
310  return false;
311  }
312 
313  // Add exit and entry Strategies
314  ram_utils::AddEntryExitStrategies srv;
315  srv.request.poses = trajectory.poses;
316  bool success = entry_exit_strategies_client.call(srv);
317  if (success)
318  trajectory.poses = srv.response.poses;
319 
320  // Publish trajectory
321  trajectory.modified = ros::Time::now();
322  trajectory_pub.publish(trajectory);
323  return true;
324 }
325 
326 // Reset the poses in the trajectory with the poses in the unmodified trajectory.
327 // the service request contains a list of uuid
328 bool resetSelectedPosesCallback(ram_modify_trajectory::ResetSelectedPoses::Request &req,
329  ram_modify_trajectory::ResetSelectedPoses::Response &)
330 {
331  std::lock_guard<std::mutex> lock(layers_mutex);
332  // Make a copy and modify this copy
333  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
334 
335  if (req.poses.empty()) // Request is empty
336  return false;
337 
338  if (trajectory.poses.empty()) // Trajectory is empty
339  return false;
340 
341  //Call buffer service
342  ram_utils::UnmodifiedTrajectory unmodified_trajectory;
343  unmodified_trajectory.request.generated = trajectory.generated;
344  if (!unmodified_trajectory_client.call(unmodified_trajectory))
345  return false;
346 
347  // Reset poses
348  // - Poses in the current layer added after the generation
349  // - Poses in the strategies to delete
350  std::vector<ram_msgs::AdditiveManufacturingPose> poses_to_delete;
351 
352  for (unsigned i(0); i < req.poses.size(); ++i)
353  {
354  std::string selected_uuid = unique_id::toHexString(req.poses[i].unique_id);
355  bool pose_in_current_traj = false;
356  for (unsigned j(0); j < trajectory.poses.size(); ++j)
357  {
358  std::string current_pose_uuid = unique_id::toHexString(trajectory.poses[j].unique_id);
359 
360  if (current_pose_uuid.compare(selected_uuid) != 0) // uuid are not equals
361  continue;
362 
363  // uuid are equals.
364  pose_in_current_traj = true;
365  //Find pose in unmodified trajectory
366  ram_msgs::AdditiveManufacturingPose unmodified_pose;
367  ram_msgs::AdditiveManufacturingPose p;
368 
369  if (findPose(current_pose_uuid, unmodified_trajectory.response.trajectory.poses, unmodified_pose))
370  {
371  // Save the entry strategy in the vector
372  if (trajectory.poses[j].polygon_start && !unmodified_pose.polygon_start)
373  {
374  // Save the entry strategy in the vector
375  for (int strategy_id(j - 1); strategy_id >= 0; --strategy_id)
376  {
377  if (trajectory.poses[strategy_id].entry_pose)
378  {
379  std::string strategy_uuid = unique_id::toHexString(trajectory.poses[strategy_id].unique_id);
380  if (!findPose(current_pose_uuid, poses_to_delete, p))
381  poses_to_delete.push_back(trajectory.poses[strategy_id]);
382  }
383  else
384  break;
385  }
386  }
387  // Save the exit strategy in the vector
388  for (unsigned strategy_id(j + 1); strategy_id < trajectory.poses.size(); ++strategy_id)
389  {
390  if (trajectory.poses[strategy_id].exit_pose)
391  {
392  std::string strategy_uuid = unique_id::toHexString(trajectory.poses[strategy_id].unique_id);
393  if (!findPose(current_pose_uuid, poses_to_delete, p))
394  poses_to_delete.push_back(trajectory.poses[strategy_id]);
395  }
396  else
397  break;
398  }
399  //update pose value
400  trajectory.poses[j] = unmodified_pose;
401  }
402  else
403  {
404  if (!findPose(current_pose_uuid, poses_to_delete, p))
405  poses_to_delete.push_back(trajectory.poses[j]); // Pose in request service does not exist in unmodified trajectory
406  }
407 
408  break;
409  }
410  if (!pose_in_current_traj) // Pose in the request that are not in the current trajectory
411  return false;
412  }
413  //Delete poses
414  if (!deletePoses(trajectory, poses_to_delete))
415  return false;
416 //Verify polygon_start and polygon_end
417  if (!verifyPolygonLimits(trajectory))
418  return false;
419 
420  // Add exit and entry Strategies
421  ram_utils::AddEntryExitStrategies srv;
422  srv.request.poses = trajectory.poses;
423  bool success = entry_exit_strategies_client.call(srv);
424  if (success)
425  trajectory.poses = srv.response.poses;
426 
427 // Publish trajectory
428  trajectory.modified = ros::Time::now();
429  trajectory_pub.publish(trajectory);
430 
431  return true;
432 }
433 
434 // Add a new pose before each pose in the request
435 bool addPosesCallback(ram_modify_trajectory::AddPoses::Request &req, ram_modify_trajectory::AddPoses::Response &)
436 {
437  std::lock_guard<std::mutex> lock(layers_mutex);
438 
439  // Make a copy and modify this copy
440  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
441 
442  if (req.poses.empty()) // Request is empty
443  return false;
444 
445  if (trajectory.poses.empty())
446  return false;
447 
448  // Find the selected pose
449  for (unsigned i(0); i < req.poses.size(); ++i)
450  {
451  std::string selected_uuid = unique_id::toHexString(req.poses[i].unique_id);
452 
453  bool pose_in_trajectory = false;
454  for (unsigned j(0); j < trajectory.poses.size(); ++j)
455  {
456  std::string layers_uuid = unique_id::toHexString(trajectory.poses[j].unique_id);
457  if (selected_uuid.compare(layers_uuid) != 0) // uuid are not equals
458  continue;
459 
460  // uuid are equals. Add new pose
461  pose_in_trajectory = true;
462  ram_msgs::AdditiveManufacturingPose new_pose = trajectory.poses[j];
463 
464  new_pose.unique_id = unique_id::toMsg(unique_id::fromRandom());
465 
466  new_pose.polygon_start = false;
467  new_pose.polygon_end = false;
468 
469  // Exit strategy
470  if (trajectory.poses[j].polygon_end)
471  trajectory.poses[j].exit_pose = true;
472 
473  if ((j + 1) == trajectory.poses.size()) // Last element in the trajectory
474  {
475  trajectory.poses.push_back(new_pose); // Insert new pose
476  }
477  else
478  {
479  // Modify position values
480  new_pose.pose.position.x = (trajectory.poses[j].pose.position.x + trajectory.poses[j + 1].pose.position.x) / 2;
481  new_pose.pose.position.y = (trajectory.poses[j].pose.position.y + trajectory.poses[j + 1].pose.position.y) / 2;
482  new_pose.pose.position.z = (trajectory.poses[j].pose.position.z + trajectory.poses[j + 1].pose.position.z) / 2;
483 
484  trajectory.poses.insert(trajectory.poses.begin() + j + 1, new_pose); // Insert new pose
485  }
486  break;
487  }
488  if (!pose_in_trajectory) // Pose in the request that are not in the trajectory
489  return false;
490  }
491 
492  trajectory.similar_layers = false;
493  trajectory.modified = ros::Time::now();
494  trajectory_pub.publish(trajectory);
495  return true;
496 }
497 
498 bool deleteSelectedPosesCallback(ram_modify_trajectory::DeleteSelectedPoses::Request &req,
499  ram_modify_trajectory::DeleteSelectedPoses::Response &)
500 {
501  std::lock_guard<std::mutex> lock(layers_mutex);
502  // Make a copy and modify this copy
503  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
504 
505  if (req.poses.empty()) // Request is empty
506  return false;
507 
508  if (trajectory.poses.empty())
509  return false;
510 
511  std::vector<ram_msgs::AdditiveManufacturingPose> strategies_to_delete; // Strategies to delete when a polygon_start or a polygon_end is modified
512 
513  // Delete poses
514  for (unsigned i(0); i < req.poses.size(); ++i)
515  {
516  std::string selected_pose_uuid = unique_id::toHexString(req.poses[i].unique_id);
517  bool pose_is_deleted = false;
518 
519  // Poses in the trajectory
520  for (unsigned j(0); j < trajectory.poses.size(); ++j)
521  {
522  std::string current_uuid = unique_id::toHexString(trajectory.poses[j].unique_id);
523  if (selected_pose_uuid.compare(current_uuid) != 0) // uuid are not equals
524  continue;
525 
526  // uuid are equals. Delete pose
527  ram_msgs::AdditiveManufacturingPose p;
528 
529  if (trajectory.poses[j].polygon_start)
530  {
531  // We also want to delete the entry strategy
532  for (int strategy_id(j - 1); strategy_id >= 0; --strategy_id)
533  {
534  if (trajectory.poses[strategy_id].entry_pose)
535  {
536  std::string strategy_uuid = unique_id::toHexString(trajectory.poses[strategy_id].unique_id);
537  // Do not add the pose if it is already in the req.poses vector: it will be deleted
538  // This avoids duplicates between the strategies_to_delete vector and req.poses
539  if (!findPose(strategy_uuid, req.poses, p))
540  if (!findPose(strategy_uuid, strategies_to_delete, p)) // Avoid duplicates in the strategies to delete
541  strategies_to_delete.push_back(trajectory.poses[strategy_id]);
542  }
543 
544  else
545  break;
546  }
547  }
548 
549  if (trajectory.poses[j].polygon_end)
550  {
551  // We also want to delete the exit strategy
552  for (unsigned strategy_id(j + 1); strategy_id < trajectory.poses.size(); ++strategy_id)
553  {
554  if (trajectory.poses[strategy_id].exit_pose)
555  {
556  std::string strategy_uuid = unique_id::toHexString(trajectory.poses[strategy_id].unique_id);
557  // Do not add the pose if it is already in the req.poses vector: it will be deleted
558  // This avoids duplicates between the strategies_to_delete vector and req.poses
559  if (!findPose(strategy_uuid, req.poses, p))
560  if (!findPose(strategy_uuid, strategies_to_delete, p)) // Avoid duplicates in the strategies to delete
561  strategies_to_delete.push_back(trajectory.poses[strategy_id]);
562  }
563  else
564  break;
565  }
566  }
567 
568  if (trajectory.poses[j].polygon_start && !trajectory.poses[j].polygon_end) // Verify polygon_start value
569  {
570  if ((j + 1) != trajectory.poses.size()) // Is not the last pose
571  trajectory.poses[j + 1].polygon_start = true; // The next pose is the new polygon_start
572  }
573  else if (trajectory.poses[j].polygon_end && !trajectory.poses[j].polygon_start) // Verify polygon_end value
574  {
575  if (j != 0) // Is not the first pose
576  trajectory.poses[j - 1].polygon_end = true; // The previous pose is the new polygon_end
577  }
578  // If pose is a polygon start AND a polygon end, do nothing
579 
580  trajectory.poses.erase(trajectory.poses.begin() + j); // Delete pose
581  pose_is_deleted = true;
582  break;
583  }
584 
585  if (!pose_is_deleted) // Selected pose are not in the trajectory
586  return false;
587  }
588 
589  if (trajectory.poses.empty())
590  return false;
591 
592  // Delete poses
593  if (!deletePoses(trajectory, strategies_to_delete))
594  return false;
595 
596  if (trajectory.poses.empty())
597  return false;
598 
599  bool trajectory_ok(false);
600  for (auto pose : trajectory.poses)
601  {
602  if (!pose.entry_pose && !pose.exit_pose)
603  {
604  trajectory_ok = true;
605  break;
606  }
607  }
608 
609  if (!trajectory_ok)
610  return false;
611 
612  // Verify polygon_start and polygon_end
613  if (!verifyPolygonLimits(trajectory))
614  return false;
615 
616  // Add exit and entry Strategies
617  ram_utils::AddEntryExitStrategies srv;
618  srv.request.poses = trajectory.poses;
619  bool success = entry_exit_strategies_client.call(srv);
620  if (success)
621  trajectory.poses = srv.response.poses;
622 
623  // Publish trajectory
624  trajectory.similar_layers = false;
625  trajectory.modified = ros::Time::now();
626  trajectory_pub.publish(trajectory);
627 
628  return true;
629 }
630 
631 bool rotateSelectedPosesCallback(ram_modify_trajectory::RotateSelectedPoses::Request &req,
632  ram_modify_trajectory::RotateSelectedPoses::Response &)
633 {
634  std::lock_guard<std::mutex> lock(layers_mutex);
635  if (req.poses.empty()) // Request is empty
636  return false;
637 
638  if (layers.poses.empty())
639  return false;
640 
641  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
642  // transform center of rotation
643  Eigen::Vector3d center_affine;
644  tf::pointMsgToEigen(req.center_of_rotation, center_affine);
645 
646  std::vector<ram_msgs::AdditiveManufacturingPose> selected_poses(req.poses);
647 
648  //Create transformation
649  //tf: trajectory frame
650  //cr: center of rotation
651  // P'_tf = [T_tf_cr * R(z,angle) * T_cr_tf]*P_tf
652  Eigen::Affine3d translation_tf_cr(Eigen::Affine3d::Identity());
653  translation_tf_cr.translate(center_affine);
654 
655  Eigen::Affine3d rot_z(Eigen::Affine3d::Identity());
656  rot_z.rotate(Eigen::AngleAxisd(req.rotation_angle, Eigen::Vector3d::UnitZ()));
657 
658  Eigen::Affine3d transformation(translation_tf_cr * rot_z * translation_tf_cr.inverse());
659 
660  //Rotate selection
661  for (auto &selected_pose : req.poses)
662  {
663  std::string selected_uuid = unique_id::toHexString(selected_pose.unique_id);
664  bool pose_in_trajectory = false;
665 
666  for (auto &current_pose : trajectory.poses)
667  {
668 
669  std::string current_uuid = unique_id::toHexString(current_pose.unique_id);
670 
671  if (current_uuid.compare(selected_uuid) != 0) // uuid are not equals
672  continue;
673 
674  // uuid are equals. Update geometry pose
675  pose_in_trajectory = true;
676  Eigen::Affine3d current_pose_affine;
677  tf::poseMsgToEigen(current_pose.pose, current_pose_affine);
678 
679  Eigen::Affine3d new_pose = Eigen::Affine3d::Identity();
680  new_pose = transformation * current_pose_affine;
681 
682  geometry_msgs::Pose new_pose_msg;
683  tf::poseEigenToMsg(new_pose, new_pose_msg);
684  current_pose.pose = new_pose_msg; // Update current ram pose
685 
686  break;
687  }
688  if (!pose_in_trajectory) // Pose in the request that are not in the trajectory
689  return false;
690  }
691 
692  trajectory.modified = ros::Time::now();
693  trajectory_pub.publish(trajectory);
694 
695  return true;
696 
697 }
698 
699 bool reflectSelectedPosesCallback(ram_modify_trajectory::ReflectSelectedPoses::Request &req,
700  ram_modify_trajectory::ReflectSelectedPoses::Response &)
701 {
702  std::lock_guard<std::mutex> lock(layers_mutex);
703  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
704 
705  if (req.poses.empty())
706  {
707  ROS_ERROR_STREAM("Request pose selection is empty");
708  return false;
709  }
710 
711  if (trajectory.poses.empty())
712  {
713  ROS_ERROR_STREAM("Trajectory is empty");
714  return false;
715  }
716 
717  // Transform center of rotation
718  Eigen::Vector3d p_plane;
719  tf::pointMsgToEigen(req.point_on_plane, p_plane);
720 
721  Eigen::Vector3d n_plane;
722  tf::vectorMsgToEigen(req.normal_vector, n_plane);
723  n_plane.normalize();
724 
725  // Create transformation
726  // o: origin
727  Eigen::Affine3d trans_o_plane(Eigen::Affine3d::Identity());
728  trans_o_plane.translate(p_plane);
729 
730  // Householder transformation (Using to reflection across a plane)
731  Eigen::Affine3d householder(Eigen::Affine3d::Identity());
732  householder.matrix().topLeftCorner(3, 3) = Eigen::Matrix3d::Identity() - 2 * n_plane * n_plane.transpose();
733 
734  Eigen::Affine3d reflect(trans_o_plane * householder * trans_o_plane.inverse());
735 
736  // Reflect selection
737  for (auto &selected_pose : req.poses)
738  {
739  std::string selected_uuid = unique_id::toHexString(selected_pose.unique_id);
740  bool pose_in_trajectory = false;
741 
742  for (auto &current_pose : trajectory.poses)
743  {
744 
745  std::string current_uuid = unique_id::toHexString(current_pose.unique_id);
746 
747  if (current_uuid.compare(selected_uuid) != 0) // uuid are not equals
748  continue;
749 
750  // uuid are equals. Update geometry pose
751  pose_in_trajectory = true;
752 
753  Eigen::Affine3d current_pose_affine;
754  tf::poseMsgToEigen(current_pose.pose, current_pose_affine);
755 
756  // Reflect the pose position
757  Eigen::Affine3d new_pose = current_pose_affine;
758  new_pose.translation() = reflect * current_pose_affine.translation();
759 
760  geometry_msgs::Pose new_pose_msg;
761  tf::poseEigenToMsg(new_pose, new_pose_msg);
762  current_pose.pose = new_pose_msg; // Update current ram pose
763 
764  break;
765  }
766  if (!pose_in_trajectory) // Pose in the request that are not in the trajectory
767  {
768  ROS_ERROR_STREAM("Some poses in the request are not in the trajectory");
769  return false;
770  }
771  }
772 
773  trajectory.modified = ros::Time::now();
774  trajectory_pub.publish(trajectory);
775 
776  return true;
777 }
778 
779 bool scaleSelectedPosesCallback(ram_modify_trajectory::ScaleSelectedPoses::Request &req,
780  ram_modify_trajectory::ScaleSelectedPoses::Response &)
781 {
782  std::lock_guard<std::mutex> lock(layers_mutex);
783  ram_msgs::AdditiveManufacturingTrajectory trajectory(layers);
784 
785  if (req.poses.empty())
786  {
787  ROS_ERROR_STREAM("Request pose selection is empty");
788  return false;
789  }
790 
791  if (trajectory.poses.empty())
792  {
793  ROS_ERROR_STREAM("Trajectory is empty");
794  return false;
795  }
796 
797  // Transform center of rotation
798  Eigen::Vector3d center_of_scaling;
799  tf::pointMsgToEigen(req.center_of_scaling, center_of_scaling);
800 
801  // Create transformation
802  // o: origin
803  Eigen::Affine3d translation(Eigen::Affine3d::Identity());
804  translation.translate(center_of_scaling);
805 
806  Eigen::Affine3d scaling(Eigen::Affine3d::Identity());
807  scaling.scale(Eigen::Vector3d(req.scale_factor, req.scale_factor, 1));
808 
809  Eigen::Affine3d transformation(translation * scaling * translation.inverse());
810  // Scale selection
811  for (auto &selected_pose : req.poses)
812  {
813  std::string selected_uuid = unique_id::toHexString(selected_pose.unique_id);
814  bool pose_in_trajectory = false;
815 
816  for (auto &current_pose : trajectory.poses)
817  {
818 
819  std::string current_uuid = unique_id::toHexString(current_pose.unique_id);
820 
821  if (current_uuid.compare(selected_uuid) != 0) // uuid are not equals
822  continue;
823 
824  // uuid are equals. Update geometry pose
825  pose_in_trajectory = true;
826 
827  Eigen::Affine3d current_pose_affine;
828  tf::poseMsgToEigen(current_pose.pose, current_pose_affine);
829 
830  // Scale the pose position
831  Eigen::Affine3d new_pose = current_pose_affine;
832  new_pose.translation() = transformation * current_pose_affine.translation();
833 
834  geometry_msgs::Pose new_pose_msg;
835  tf::poseEigenToMsg(new_pose, new_pose_msg);
836  current_pose.pose = new_pose_msg; // Update current ram pose
837 
838  break;
839  }
840  if (!pose_in_trajectory) // Pose in the request that are not in the trajectory
841  {
842  ROS_ERROR_STREAM("Some poses in the request are not in the trajectory");
843  return false;
844  }
845  }
846 
847  trajectory.modified = ros::Time::now();
848  trajectory_pub.publish(trajectory);
849 
850  return true;
851 }
852 
853 int main(int argc, char **argv)
854 {
855  ros::init(argc, argv, "modify_trajectory");
857 
858  // Publish on "ram/trajectory"
859  trajectory_pub = nh.advertise<ram_msgs::AdditiveManufacturingTrajectory>("ram/trajectory", 10, true);
860 
861  // Get unmodified trajectory from buffer node
862  unmodified_trajectory_client = nh.serviceClient<ram_utils::UnmodifiedTrajectory>(
863  "ram/buffer/get_unmodified_trajectory");
864  // Service to add strategies
865  entry_exit_strategies_client = nh.serviceClient<ram_utils::AddEntryExitStrategies>(
866  "ram/information/add_entry_exit_strategies");
867 
868  // Subscribe on "ram/trajectory"
869  ros::Subscriber sub = nh.subscribe("ram/trajectory", 10, saveTrajectoryCallback);
870 
871 // services to modify trajectory
872  ros::ServiceServer service_1 = nh.advertiseService("ram/modify_trajectory/modify_selected_poses",
874  ros::ServiceServer service_2 = nh.advertiseService("ram/modify_trajectory/reset_selected_poses",
876  ros::ServiceServer service_3 = nh.advertiseService("ram/modify_trajectory/add_poses", addPosesCallback);
877 
878  ros::ServiceServer service_4 = nh.advertiseService("ram/modify_trajectory/rotate_selected_poses",
880  ros::ServiceServer service_5 = nh.advertiseService("ram/modify_trajectory/reflect_selected_poses",
882  ros::ServiceServer service_6 = nh.advertiseService("ram/modify_trajectory/delete_selected_poses",
884  ros::ServiceServer service_7 = nh.advertiseService("ram/modify_trajectory/scale_selected_poses",
886 
888  spinner.start();
890  return 0;
891 }
static boost::uuids::uuid fromRandom(void)
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
bool addPosesCallback(ram_modify_trajectory::AddPoses::Request &req, ram_modify_trajectory::AddPoses::Response &)
void publish(const boost::shared_ptr< M > &message) const
bool modifySelectedPosesCallback(ram_modify_trajectory::ModifySelectedPoses::Request &req, ram_modify_trajectory::ModifySelectedPoses::Response &)
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
bool scaleSelectedPosesCallback(ram_modify_trajectory::ScaleSelectedPoses::Request &req, ram_modify_trajectory::ScaleSelectedPoses::Response &)
ros::ServiceClient entry_exit_strategies_client
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
std::unique_ptr< ros::NodeHandle > nh
void spinner()
bool deleteSelectedPosesCallback(ram_modify_trajectory::DeleteSelectedPoses::Request &req, ram_modify_trajectory::DeleteSelectedPoses::Response &)
bool resetSelectedPosesCallback(ram_modify_trajectory::ResetSelectedPoses::Request &req, ram_modify_trajectory::ResetSelectedPoses::Response &)
bool deletePoses(ram_msgs::AdditiveManufacturingTrajectory &trajectory, std::vector< ram_msgs::AdditiveManufacturingPose > poses)
void vectorMsgToEigen(const geometry_msgs::Vector3 &m, Eigen::Vector3d &e)
ros::ServiceClient unmodified_trajectory_client
int main(int argc, char **argv)
void pointMsgToEigen(const geometry_msgs::Point &m, Eigen::Vector3d &e)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool findPose(std::string pose_uuid, std::vector< ram_msgs::AdditiveManufacturingPose > poses, ram_msgs::AdditiveManufacturingPose &pose)
static std::string toHexString(boost::uuids::uuid const &uu)
void saveTrajectoryCallback(const ram_msgs::AdditiveManufacturingTrajectoryConstPtr &msg)
bool rotateSelectedPosesCallback(ram_modify_trajectory::RotateSelectedPoses::Request &req, ram_modify_trajectory::RotateSelectedPoses::Response &)
bool reflectSelectedPosesCallback(ram_modify_trajectory::ReflectSelectedPoses::Request &req, ram_modify_trajectory::ReflectSelectedPoses::Response &)
static Time now()
static uuid_msgs::UniqueID toMsg(boost::uuids::uuid const &uu)
ram_msgs::AdditiveManufacturingTrajectory trajectory
#define ROS_ERROR_STREAM(args)
ram_msgs::AdditiveManufacturingTrajectory layers
std::mutex layers_mutex
bool verifyPolygonLimits(ram_msgs::AdditiveManufacturingTrajectory trajectory)
ros::Publisher trajectory_pub
ROSCPP_DECL void waitForShutdown()


ram_modify_trajectory
Author(s): Andres Campos - Institut Maupertuis
autogenerated on Mon Jun 10 2019 14:50:00