moveit2
The MoveIt Motion Planning Framework for ROS 2.
utils.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
37 #include <algorithm>
38 
39 #include <geometric_shapes/solid_primitive_dims.h>
42 #include <rclcpp/logger.hpp>
43 #include <rclcpp/logging.hpp>
44 #include <rclcpp/node.hpp>
45 #include <rclcpp/parameter_value.hpp>
46 
47 #include <rclcpp/node.hpp>
48 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
49 #include <tf2_eigen/tf2_eigen.hpp>
50 
51 using namespace moveit::core;
52 
53 namespace kinematic_constraints
54 {
55 // Logger
56 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_kinematic_constraints.utils");
57 
58 moveit_msgs::msg::Constraints mergeConstraints(const moveit_msgs::msg::Constraints& first,
59  const moveit_msgs::msg::Constraints& second)
60 {
61  moveit_msgs::msg::Constraints r;
62 
63  // add all joint constraints that are in first but not in second
64  // and merge joint constraints that are for the same joint
65  for (const moveit_msgs::msg::JointConstraint& jc_first : first.joint_constraints)
66  {
67  bool add = true;
68  for (const moveit_msgs::msg::JointConstraint& jc_second : second.joint_constraints)
69  {
70  if (jc_second.joint_name == jc_first.joint_name)
71  {
72  add = false;
73  // now we merge
74  moveit_msgs::msg::JointConstraint m;
75  const moveit_msgs::msg::JointConstraint& a = jc_first;
76  const moveit_msgs::msg::JointConstraint& b = jc_second;
77  double low = std::max(a.position - a.tolerance_below, b.position - b.tolerance_below);
78  double high = std::min(a.position + a.tolerance_above, b.position + b.tolerance_above);
79  if (low > high)
80  {
81  RCLCPP_ERROR(LOGGER, "Attempted to merge incompatible constraints for joint '%s'. Discarding constraint.",
82  a.joint_name.c_str());
83  }
84  else
85  {
86  m.joint_name = a.joint_name;
87  m.position =
88  std::max(low, std::min((a.position * a.weight + b.position * b.weight) / (a.weight + b.weight), high));
89  m.weight = (a.weight + b.weight) / 2.0;
90  m.tolerance_above = std::max(0.0, high - m.position);
91  m.tolerance_below = std::max(0.0, m.position - low);
92  r.joint_constraints.push_back(m);
93  }
94  break;
95  }
96  }
97  if (add)
98  r.joint_constraints.push_back(jc_first);
99  }
100 
101  // add all joint constraints that are in second but not in first
102  for (const moveit_msgs::msg::JointConstraint& jc_second : second.joint_constraints)
103  {
104  bool add = true;
105  for (const moveit_msgs::msg::JointConstraint& jc_first : first.joint_constraints)
106  {
107  if (jc_second.joint_name == jc_first.joint_name)
108  {
109  add = false;
110  break;
111  }
112  }
113  if (add)
114  r.joint_constraints.push_back(jc_second);
115  }
116 
117  // merge rest of constraints
118  r.position_constraints = first.position_constraints;
119  for (const moveit_msgs::msg::PositionConstraint& position_constraint : second.position_constraints)
120  r.position_constraints.push_back(position_constraint);
121 
122  r.orientation_constraints = first.orientation_constraints;
123  for (const moveit_msgs::msg::OrientationConstraint& orientation_constraint : second.orientation_constraints)
124  r.orientation_constraints.push_back(orientation_constraint);
125 
126  r.visibility_constraints = first.visibility_constraints;
127  for (const moveit_msgs::msg::VisibilityConstraint& visibility_constraint : second.visibility_constraints)
128  r.visibility_constraints.push_back(visibility_constraint);
129 
130  return r;
131 }
132 
133 std::size_t countIndividualConstraints(const moveit_msgs::msg::Constraints& constr)
134 {
135  return constr.position_constraints.size() + constr.orientation_constraints.size() +
136  constr.visibility_constraints.size() + constr.joint_constraints.size();
137 }
138 
139 moveit_msgs::msg::Constraints constructGoalConstraints(const moveit::core::RobotState& state,
140  const moveit::core::JointModelGroup* jmg, double tolerance)
141 {
142  return constructGoalConstraints(state, jmg, tolerance, tolerance);
143 }
144 
145 moveit_msgs::msg::Constraints constructGoalConstraints(const moveit::core::RobotState& state,
146  const moveit::core::JointModelGroup* jmg, double tolerance_below,
147  double tolerance_above)
148 {
149  moveit_msgs::msg::Constraints goal;
150  std::vector<double> vals;
151  state.copyJointGroupPositions(jmg, vals);
152  goal.joint_constraints.resize(vals.size());
153  for (std::size_t i = 0; i < vals.size(); ++i)
154  {
155  goal.joint_constraints[i].joint_name = jmg->getVariableNames()[i];
156  goal.joint_constraints[i].position = vals[i];
157  goal.joint_constraints[i].tolerance_above = tolerance_above;
158  goal.joint_constraints[i].tolerance_below = tolerance_below;
159  goal.joint_constraints[i].weight = 1.0;
160  }
161 
162  return goal;
163 }
164 
165 bool updateJointConstraints(moveit_msgs::msg::Constraints& constraints, const moveit::core::RobotState& state,
167 {
168  const std::vector<std::string>& jmg_active_joints = jmg->getActiveJointModelNames();
169 
170  // For each constraint, update it if the joint is found within jmg
171  for (auto& constraint : constraints.joint_constraints)
172  {
173  const auto itr = find(jmg_active_joints.begin(), jmg_active_joints.end(), constraint.joint_name);
174  if (itr != jmg_active_joints.end())
175  {
176  constraint.position = state.getVariablePosition(constraint.joint_name);
177  }
178  // The joint was not found within jmg
179  else
180  {
181  return false;
182  }
183  }
184  return true;
185 }
186 
187 moveit_msgs::msg::Constraints constructGoalConstraints(const std::string& link_name,
188  const geometry_msgs::msg::PoseStamped& pose,
189  double tolerance_pos, double tolerance_angle)
190 {
191  moveit_msgs::msg::Constraints goal;
192 
193  goal.position_constraints.resize(1);
194  moveit_msgs::msg::PositionConstraint& pcm = goal.position_constraints[0];
195  pcm.link_name = link_name;
196  pcm.target_point_offset.x = 0;
197  pcm.target_point_offset.y = 0;
198  pcm.target_point_offset.z = 0;
199  pcm.constraint_region.primitives.resize(1);
200  shape_msgs::msg::SolidPrimitive& bv = pcm.constraint_region.primitives[0];
201  bv.type = shape_msgs::msg::SolidPrimitive::SPHERE;
202  bv.dimensions.resize(geometric_shapes::solidPrimitiveDimCount<shape_msgs::msg::SolidPrimitive::SPHERE>());
203  bv.dimensions[shape_msgs::msg::SolidPrimitive::SPHERE_RADIUS] = tolerance_pos;
204 
205  pcm.header = pose.header;
206  pcm.constraint_region.primitive_poses.resize(1);
207  // orientation of constraint region does not affect anything, since it is a sphere
208  pcm.constraint_region.primitive_poses[0].position = pose.pose.position;
209  pcm.weight = 1.0;
210 
211  goal.orientation_constraints.resize(1);
212  moveit_msgs::msg::OrientationConstraint& ocm = goal.orientation_constraints[0];
213  ocm.link_name = link_name;
214  ocm.header = pose.header;
215  ocm.orientation = pose.pose.orientation;
216  ocm.absolute_x_axis_tolerance = tolerance_angle;
217  ocm.absolute_y_axis_tolerance = tolerance_angle;
218  ocm.absolute_z_axis_tolerance = tolerance_angle;
219  ocm.weight = 1.0;
220 
221  return goal;
222 }
223 
224 moveit_msgs::msg::Constraints constructGoalConstraints(const std::string& link_name,
225  const geometry_msgs::msg::PoseStamped& pose,
226  const std::vector<double>& tolerance_pos,
227  const std::vector<double>& tolerance_angle)
228 {
229  moveit_msgs::msg::Constraints goal = constructGoalConstraints(link_name, pose);
230  if (tolerance_pos.size() == 3)
231  {
232  shape_msgs::msg::SolidPrimitive& bv = goal.position_constraints[0].constraint_region.primitives[0];
233  bv.type = shape_msgs::msg::SolidPrimitive::BOX;
234  bv.dimensions.resize(geometric_shapes::solidPrimitiveDimCount<shape_msgs::msg::SolidPrimitive::BOX>());
235  bv.dimensions[shape_msgs::msg::SolidPrimitive::BOX_X] = tolerance_pos[0];
236  bv.dimensions[shape_msgs::msg::SolidPrimitive::BOX_Y] = tolerance_pos[1];
237  bv.dimensions[shape_msgs::msg::SolidPrimitive::BOX_Z] = tolerance_pos[2];
238  }
239  if (tolerance_angle.size() == 3)
240  {
241  moveit_msgs::msg::OrientationConstraint& ocm = goal.orientation_constraints[0];
242  ocm.absolute_x_axis_tolerance = tolerance_angle[0];
243  ocm.absolute_y_axis_tolerance = tolerance_angle[1];
244  ocm.absolute_z_axis_tolerance = tolerance_angle[2];
245  }
246  return goal;
247 }
248 
249 bool updatePoseConstraint(moveit_msgs::msg::Constraints& constraints, const std::string& link_name,
250  const geometry_msgs::msg::PoseStamped& pose)
251 {
252  // Convert message types so the existing functions can be used
253  geometry_msgs::msg::PointStamped point;
254  point.header = pose.header;
255  point.point.x = pose.pose.position.x;
256  point.point.y = pose.pose.position.y;
257  point.point.z = pose.pose.position.z;
258 
259  geometry_msgs::msg::QuaternionStamped quat_stamped;
260  quat_stamped.header = pose.header;
261  quat_stamped.quaternion = pose.pose.orientation;
262 
263  return updatePositionConstraint(constraints, link_name, point) &&
264  updateOrientationConstraint(constraints, link_name, quat_stamped);
265 }
266 
267 moveit_msgs::msg::Constraints constructGoalConstraints(const std::string& link_name,
268  const geometry_msgs::msg::QuaternionStamped& quat,
269  double tolerance)
270 {
271  moveit_msgs::msg::Constraints goal;
272  goal.orientation_constraints.resize(1);
273  moveit_msgs::msg::OrientationConstraint& ocm = goal.orientation_constraints[0];
274  ocm.link_name = link_name;
275  ocm.header = quat.header;
276  ocm.orientation = quat.quaternion;
277  ocm.absolute_x_axis_tolerance = tolerance;
278  ocm.absolute_y_axis_tolerance = tolerance;
279  ocm.absolute_z_axis_tolerance = tolerance;
280  ocm.weight = 1.0;
281  return goal;
282 }
283 
284 bool updateOrientationConstraint(moveit_msgs::msg::Constraints& constraints, const std::string& link_name,
285  const geometry_msgs::msg::QuaternionStamped& quat)
286 {
287  for (auto& constraint : constraints.orientation_constraints)
288  {
289  if (constraint.link_name == link_name)
290  {
291  if (quat.header.frame_id.empty())
292  {
293  RCLCPP_ERROR(LOGGER, "Cannot update orientation constraint, frame_id in the header is empty");
294  return false;
295  }
296  constraint.header = quat.header;
297  constraint.orientation = quat.quaternion;
298  return true;
299  }
300  }
301  return false;
302 }
303 
304 moveit_msgs::msg::Constraints constructGoalConstraints(const std::string& link_name,
305  const geometry_msgs::msg::PointStamped& goal_point,
306  double tolerance)
307 {
308  geometry_msgs::msg::Point p;
309  p.x = 0;
310  p.y = 0;
311  p.z = 0;
312  return constructGoalConstraints(link_name, p, goal_point, tolerance);
313 }
314 
315 bool updatePositionConstraint(moveit_msgs::msg::Constraints& constraints, const std::string& link_name,
316  const geometry_msgs::msg::PointStamped& goal_point)
317 {
318  for (auto& constraint : constraints.position_constraints)
319  {
320  if (constraint.link_name == link_name)
321  {
322  if (goal_point.header.frame_id.empty())
323  {
324  RCLCPP_ERROR(LOGGER, "Cannot update position constraint, frame_id in the header is empty");
325  return false;
326  }
327  constraint.header = goal_point.header;
328  constraint.constraint_region.primitive_poses.at(0).position.x = goal_point.point.x;
329  constraint.constraint_region.primitive_poses.at(0).position.y = goal_point.point.y;
330  constraint.constraint_region.primitive_poses.at(0).position.z = goal_point.point.z;
331  return true;
332  }
333  }
334  return false;
335 }
336 
337 moveit_msgs::msg::Constraints constructGoalConstraints(const std::string& link_name,
338  const geometry_msgs::msg::Point& reference_point,
339  const geometry_msgs::msg::PointStamped& goal_point,
340  double tolerance)
341 {
342  moveit_msgs::msg::Constraints goal;
343  goal.position_constraints.resize(1);
344  moveit_msgs::msg::PositionConstraint& pcm = goal.position_constraints[0];
345  pcm.link_name = link_name;
346  pcm.target_point_offset.x = reference_point.x;
347  pcm.target_point_offset.y = reference_point.y;
348  pcm.target_point_offset.z = reference_point.z;
349  pcm.constraint_region.primitives.resize(1);
350  pcm.constraint_region.primitives[0].type = shape_msgs::msg::SolidPrimitive::SPHERE;
351  pcm.constraint_region.primitives[0].dimensions.resize(
352  geometric_shapes::solidPrimitiveDimCount<shape_msgs::msg::SolidPrimitive::SPHERE>());
353  pcm.constraint_region.primitives[0].dimensions[shape_msgs::msg::SolidPrimitive::SPHERE_RADIUS] = tolerance;
354 
355  pcm.header = goal_point.header;
356  pcm.constraint_region.primitive_poses.resize(1);
357  pcm.constraint_region.primitive_poses[0].position = goal_point.point;
358 
359  // orientation of constraint region does not affect anything, since it is a sphere
360  pcm.constraint_region.primitive_poses[0].orientation.x = 0.0;
361  pcm.constraint_region.primitive_poses[0].orientation.y = 0.0;
362  pcm.constraint_region.primitive_poses[0].orientation.z = 0.0;
363  pcm.constraint_region.primitive_poses[0].orientation.w = 1.0;
364  pcm.weight = 1.0;
365 
366  return goal;
367 }
368 
369 // Initialize a PoseStamped message from node parameters specified at pose_param.
370 static bool constructPoseStamped(const rclcpp::Node::SharedPtr& node, const std::string& pose_param,
371  geometry_msgs::msg::PoseStamped& pose)
372 {
373  if (!node->get_parameter(pose_param + ".frame_id", pose.header.frame_id))
374  return false;
375 
376  std::vector<double> orientation;
377  if (!node->get_parameter(pose_param + ".orientation", orientation) || orientation.size() != 3)
378  return false;
379 
380  tf2::Quaternion q;
381  q.setRPY(orientation[0], orientation[1], orientation[2]);
382  pose.pose.orientation = toMsg(q);
383 
384  std::vector<double> position;
385  if (!node->get_parameter(pose_param + ".position", position) || position.size() != 3)
386  return false;
387 
388  pose.pose.position.x = position[0];
389  pose.pose.position.y = position[1];
390  pose.pose.position.z = position[2];
391 
392  return true;
393 }
394 
395 // Initialize a JointConstraint message from node parameters specified at constraint_param.
396 static bool constructConstraint(const rclcpp::Node::SharedPtr& node, const std::string& constraint_param,
397  moveit_msgs::msg::JointConstraint& constraint)
398 {
399  node->get_parameter(constraint_param + ".weight", constraint.weight);
400  node->get_parameter(constraint_param + ".joint_name", constraint.joint_name);
401  node->get_parameter(constraint_param + ".position", constraint.position);
402 
403  double tolerance;
404  if (node->get_parameter(constraint_param + ".tolerance", tolerance))
405  {
406  constraint.tolerance_below = tolerance;
407  constraint.tolerance_above = tolerance;
408  }
409  else if (node->has_parameter(constraint_param + ".tolerances"))
410  {
411  std::vector<double> tolerances;
412  node->get_parameter(constraint_param + ".tolerances", tolerances);
413  if (tolerances.size() != 2)
414  return false;
415 
416  constraint.tolerance_below = tolerances[0];
417  constraint.tolerance_above = tolerances[1];
418  }
419  else if (node->has_parameter(constraint_param + ".bounds"))
420  {
421  std::vector<double> bounds;
422  node->get_parameter(constraint_param + ".bounds", bounds);
423  if (bounds.size() != 2)
424  return false;
425 
426  const double lower_bound = bounds[0];
427  const double upper_bound = bounds[1];
428 
429  constraint.position = (lower_bound + upper_bound) / 2;
430  constraint.tolerance_below = constraint.position - lower_bound;
431  constraint.tolerance_above = upper_bound - constraint.position;
432  }
433 
434  return true;
435 }
436 
437 // Initialize a PositionConstraint message from node parameters specified at constraint_param.
438 static bool constructConstraint(const rclcpp::Node::SharedPtr& node, const std::string& constraint_param,
439  moveit_msgs::msg::PositionConstraint& constraint)
440 {
441  node->get_parameter(constraint_param + ".frame_id", constraint.header.frame_id);
442  node->get_parameter(constraint_param + ".weight", constraint.weight);
443  node->get_parameter(constraint_param + ".link_name", constraint.link_name);
444 
445  std::vector<double> target_offset;
446  if (node->get_parameter(constraint_param + ".target_offset", target_offset))
447  {
448  if (target_offset.size() != 3)
449  return false;
450 
451  constraint.target_point_offset.x = target_offset[0];
452  constraint.target_point_offset.y = target_offset[1];
453  constraint.target_point_offset.z = target_offset[2];
454  }
455  if (!node->list_parameters({ constraint_param + ".region" }, 1).names.empty()) // TODO(henningkayser): specify depth
456  {
457  geometry_msgs::msg::Pose region_pose;
458  region_pose.orientation.w = 1.0;
459 
460  shape_msgs::msg::SolidPrimitive region_primitive;
461  region_primitive.type = shape_msgs::msg::SolidPrimitive::BOX;
462  region_primitive.dimensions.resize(3);
463 
464  const auto parse_dimension = [&](const std::string& dimension_param, double& center, double& dimension) -> bool {
465  std::vector<double> dimension_limits;
466  if (!node->get_parameter(constraint_param + ".region." + dimension_param, dimension_limits) ||
467  dimension_limits.size() != 2)
468  return false;
469 
470  center = (dimension_limits[0] + dimension_limits[1]) / 2;
471  dimension = dimension_limits[1] - dimension_limits[2];
472  return true;
473  };
474 
475  if (!parse_dimension("x", region_pose.position.x,
476  region_primitive.dimensions[shape_msgs::msg::SolidPrimitive::BOX_X]) ||
477  !parse_dimension("y", region_pose.position.y,
478  region_primitive.dimensions[shape_msgs::msg::SolidPrimitive::BOX_Y]) ||
479  !parse_dimension("z", region_pose.position.z,
480  region_primitive.dimensions[shape_msgs::msg::SolidPrimitive::BOX_Z]))
481  return false;
482 
483  constraint.constraint_region.primitive_poses.push_back(region_pose);
484  constraint.constraint_region.primitives.emplace_back(region_primitive);
485  }
486 
487  return true;
488 }
489 
490 // Initialize an OrientationConstraint message from node parameters specified at constraint_param.
491 static bool constructConstraint(const rclcpp::Node::SharedPtr& node, const std::string& constraint_param,
492  moveit_msgs::msg::OrientationConstraint& constraint)
493 {
494  node->get_parameter(constraint_param + ".frame_id", constraint.header.frame_id);
495  node->get_parameter(constraint_param + ".weight", constraint.weight);
496  node->get_parameter(constraint_param + ".link_name", constraint.link_name);
497 
498  std::vector<double> orientation;
499  if (node->get_parameter(constraint_param + ".orientation", orientation))
500  {
501  if (orientation.size() != 3)
502  return false;
503 
504  tf2::Quaternion q;
505  q.setRPY(orientation[0], orientation[1], orientation[2]);
506  constraint.orientation = toMsg(q);
507  }
508 
509  std::vector<double> tolerances;
510  if (node->get_parameter(constraint_param + ".tolerances", tolerances))
511  {
512  if (tolerances.size() != 3)
513  return false;
514 
515  constraint.absolute_x_axis_tolerance = tolerances[0];
516  constraint.absolute_y_axis_tolerance = tolerances[1];
517  constraint.absolute_z_axis_tolerance = tolerances[2];
518  }
519 
520  return true;
521 }
522 
523 // Initialize a VisibilityConstraint message from node parameters specified at constraint_param.
524 static bool constructConstraint(const rclcpp::Node::SharedPtr& node, const std::string& constraint_param,
525  moveit_msgs::msg::VisibilityConstraint& constraint)
526 {
527  node->get_parameter(constraint_param + ".weight", constraint.weight);
528  node->get_parameter(constraint_param + ".target_radius", constraint.target_radius);
529  node->get_parameter(constraint_param + ".cone_sides", constraint.cone_sides);
530  node->get_parameter(constraint_param + ".max_view_angle", constraint.max_view_angle);
531  node->get_parameter(constraint_param + ".max_range_angle", constraint.max_range_angle);
532 
533  // TODO(henningkayser): specify depth
534  if (!node->list_parameters({ constraint_param + ".target_pose" }, 1).names.empty())
535  {
536  if (!constructPoseStamped(node, constraint_param + ".target_pose", constraint.target_pose))
537  return false;
538  }
539  // TODO(henningkayser): specify depth
540  if (!node->list_parameters({ constraint_param + ".sensor_pose" }, 1).names.empty())
541  {
542  if (!constructPoseStamped(node, constraint_param + ".sensor_pose", constraint.sensor_pose))
543  return false;
544  }
545 
546  constraint.sensor_view_direction = moveit_msgs::msg::VisibilityConstraint::SENSOR_X;
547 
548  return true;
549 }
550 
551 // Initialize a Constraints message containing constraints specified by node parameters under constraint_ids.
552 static bool collectConstraints(const rclcpp::Node::SharedPtr& node, const std::vector<std::string>& constraint_ids,
553  moveit_msgs::msg::Constraints& constraints)
554 {
555  for (const auto& constraint_id : constraint_ids)
556  {
557  const auto constraint_param = "constraints." + constraint_id;
558  if (!node->has_parameter(constraint_param + ".type"))
559  {
560  RCLCPP_ERROR(LOGGER, "constraint parameter \"%s\" does not specify its type", constraint_param.c_str());
561  return false;
562  }
563  std::string constraint_type;
564  node->get_parameter(constraint_param + ".type", constraint_type);
565  if (constraint_type == "joint")
566  {
567  constraints.joint_constraints.emplace_back();
568  if (!constructConstraint(node, constraint_param, constraints.joint_constraints.back()))
569  return false;
570  }
571  else if (constraint_type == "position")
572  {
573  constraints.position_constraints.emplace_back();
574  if (!constructConstraint(node, constraint_param, constraints.position_constraints.back()))
575  return false;
576  }
577  else if (constraint_type == "orientation")
578  {
579  constraints.orientation_constraints.emplace_back();
580  if (!constructConstraint(node, constraint_param, constraints.orientation_constraints.back()))
581  return false;
582  }
583  else if (constraint_type == "visibility")
584  {
585  constraints.visibility_constraints.emplace_back();
586  if (!constructConstraint(node, constraint_param, constraints.visibility_constraints.back()))
587  return false;
588  }
589  else
590  {
591  RCLCPP_ERROR_STREAM(LOGGER, "Unable to process unknown constraint type: " << constraint_type);
592  return false;
593  }
594  }
595 
596  return true;
597 }
598 
599 bool constructConstraints(const rclcpp::Node::SharedPtr& node, const std::string& constraints_param,
600  moveit_msgs::msg::Constraints& constraints)
601 {
602  if (!node->get_parameter(constraints_param + ".name", constraints.name))
603  return false;
604 
605  std::vector<std::string> constraint_ids;
606  if (!node->get_parameter(constraints_param + ".constraint_ids", constraint_ids))
607  return false;
608 
609  for (auto& constraint_id : constraint_ids)
610  constraint_id.insert(0, constraints_param + std::string("."));
611 
612  return collectConstraints(node, constraint_ids, constraints);
613 }
614 
615 bool resolveConstraintFrames(const moveit::core::RobotState& state, moveit_msgs::msg::Constraints& constraints)
616 {
617  for (auto& c : constraints.position_constraints)
618  {
619  bool frame_found;
620  const moveit::core::LinkModel* robot_link;
621  const Eigen::Isometry3d& transform = state.getFrameInfo(c.link_name, robot_link, frame_found);
622  if (!frame_found)
623  return false;
624 
625  // If the frame of the constraint is not part of the robot link model (but an attached body or subframe),
626  // the constraint needs to be expressed in the frame of a robot link.
627  if (c.link_name != robot_link->getName())
628  {
629  Eigen::Isometry3d robot_link_to_link_name = state.getGlobalLinkTransform(robot_link).inverse() * transform;
630  Eigen::Vector3d offset_link_name(c.target_point_offset.x, c.target_point_offset.y, c.target_point_offset.z);
631  Eigen::Vector3d offset_robot_link = robot_link_to_link_name * offset_link_name;
632 
633  c.link_name = robot_link->getName();
634  tf2::toMsg(offset_robot_link, c.target_point_offset);
635  }
636  }
637 
638  for (auto& c : constraints.orientation_constraints)
639  {
640  bool frame_found;
641  const moveit::core::LinkModel* robot_link;
642  // getFrameInfo() returns a valid isometry by contract
643  const Eigen::Isometry3d& transform = state.getFrameInfo(c.link_name, robot_link, frame_found);
644  if (!frame_found)
645  return false;
646 
647  // If the frame of the constraint is not part of the robot link model (but an attached body or subframe),
648  // the constraint needs to be expressed in the frame of a robot link.
649  if (c.link_name != robot_link->getName())
650  {
651  c.link_name = robot_link->getName();
652  Eigen::Quaterniond link_name_to_robot_link(transform.linear().transpose() *
653  state.getGlobalLinkTransform(robot_link).linear());
654  Eigen::Quaterniond quat_target;
655  tf2::fromMsg(c.orientation, quat_target);
656  c.orientation = tf2::toMsg(quat_target * link_name_to_robot_link);
657  }
658  }
659  return true;
660 }
661 } // namespace kinematic_constraints
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up the joints included in this group. The number of returned...
const std::vector< std::string > & getActiveJointModelNames() const
Get the names of the active joints in this group. These are the names of the joints returned by getJo...
A link from the robot. Contains the constant transform applied to the link and its geometry.
Definition: link_model.h:72
const std::string & getName() const
The name of this link.
Definition: link_model.h:86
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
const Eigen::Isometry3d & getGlobalLinkTransform(const std::string &link_name)
Get the link transform w.r.t. the root link (model frame) of the RobotModel. This is typically the ro...
Definition: robot_state.h:1271
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
Definition: robot_state.h:691
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Definition: robot_state.h:207
const Eigen::Isometry3d & getFrameInfo(const std::string &frame_id, const LinkModel *&robot_link, bool &frame_found) const
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
Representation and evaluation of kinematic constraints.
bool updateOrientationConstraint(moveit_msgs::msg::Constraints &constraints, const std::string &link_name, const geometry_msgs::msg::QuaternionStamped &quat)
Update an orientation constraint for one link with a new quaternion.
Definition: utils.cpp:284
std::size_t countIndividualConstraints(const moveit_msgs::msg::Constraints &constr)
Definition: utils.cpp:133
bool updatePositionConstraint(moveit_msgs::msg::Constraints &constraints, const std::string &link_name, const geometry_msgs::msg::PointStamped &goal_point)
Update a position constraint for one link with a new position.
Definition: utils.cpp:315
moveit_msgs::msg::Constraints constructGoalConstraints(const moveit::core::RobotState &state, const moveit::core::JointModelGroup *jmg, double tolerance_below, double tolerance_above)
Generates a constraint message intended to be used as a goal constraint for a joint group....
Definition: utils.cpp:145
bool updateJointConstraints(moveit_msgs::msg::Constraints &constraints, const moveit::core::RobotState &state, const moveit::core::JointModelGroup *jmg)
Update joint constraints with a new JointModelGroup state.
Definition: utils.cpp:165
bool resolveConstraintFrames(const moveit::core::RobotState &state, moveit_msgs::msg::Constraints &constraints)
Resolves frames used in constraints to links in the robot model.
Definition: utils.cpp:615
bool constructConstraints(const rclcpp::Node::SharedPtr &node, const std::string &constraints_param, moveit_msgs::msg::Constraints &constraints)
extract constraint message from node parameters.
Definition: utils.cpp:599
bool updatePoseConstraint(moveit_msgs::msg::Constraints &constraints, const std::string &link_name, const geometry_msgs::msg::PoseStamped &pose)
Update a pose constraint for one link with a new pose.
Definition: utils.cpp:249
moveit_msgs::msg::Constraints mergeConstraints(const moveit_msgs::msg::Constraints &first, const moveit_msgs::msg::Constraints &second)
Merge two sets of constraints into one.
Definition: utils.cpp:58
Core components of MoveIt.