moveit2
The MoveIt Motion Planning Framework for ROS 2.
kinematic_constraint.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 
38 #include <geometric_shapes/body_operations.h>
39 #include <geometric_shapes/shape_operations.h>
42 #include <geometric_shapes/check_isometry.h>
43 #include <rclcpp/logger.hpp>
44 #include <rclcpp/logging.hpp>
45 #include <rclcpp/time.hpp>
46 #include <tf2_eigen/tf2_eigen.hpp>
47 #include <functional>
48 #include <limits>
49 #include <math.h>
50 #include <memory>
51 #include <typeinfo>
52 
53 #include <rclcpp/clock.hpp>
54 #include <rclcpp/duration.hpp>
55 
56 namespace kinematic_constraints
57 {
58 // Logger
59 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_kinematic_constraints.kinematic_constraints");
60 
61 static double normalizeAngle(double angle)
62 {
63  double v = fmod(angle, 2.0 * M_PI);
64  if (v < -M_PI)
65  {
66  v += 2.0 * M_PI;
67  }
68  else if (v > M_PI)
69  {
70  v -= 2.0 * M_PI;
71  }
72  return v;
73 }
74 
75 // Normalizes an angle to the interval [-pi, +pi] and then take the absolute value
76 // The returned values will be in the following range [0, +pi]
77 static double normalizeAbsoluteAngle(const double angle)
78 {
79  const double normalized_angle = std::fmod(std::abs(angle), 2 * M_PI);
80  return std::min(2 * M_PI - normalized_angle, normalized_angle);
81 }
82 
90 template <typename Derived>
91 std::tuple<Eigen::Matrix<typename Eigen::MatrixBase<Derived>::Scalar, 3, 1>, bool>
92 calcEulerAngles(const Eigen::MatrixBase<Derived>& R)
93 {
94  using std::atan2;
95  using std::sqrt;
96  EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived, 3, 3)
97  using Index = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
98  using Scalar = typename Eigen::MatrixBase<Derived>::Scalar;
99  const Index i = 0;
100  const Index j = 1;
101  const Index k = 2;
102  Eigen::Matrix<Scalar, 3, 1> res;
103  const Scalar rsum = sqrt((R(i, i) * R(i, i) + R(i, j) * R(i, j) + R(j, k) * R(j, k) + R(k, k) * R(k, k)) / 2);
104  res[1] = atan2(R(i, k), rsum);
105  // There is a singularity when cos(beta) == 0
106  if (rsum > 4 * Eigen::NumTraits<Scalar>::epsilon())
107  { // cos(beta) != 0
108  res[0] = atan2(-R(j, k), R(k, k));
109  res[2] = atan2(-R(i, j), R(i, i));
110  return { res, true };
111  }
112  else if (R(i, k) > 0)
113  { // cos(beta) == 0 and sin(beta) == 1
114  const Scalar spos = R(j, i) + R(k, j); // 2*sin(alpha + gamma)
115  const Scalar cpos = R(j, j) - R(k, i); // 2*cos(alpha + gamma)
116  res[0] = atan2(spos, cpos);
117  res[2] = 0;
118  return { res, false };
119  } // cos(beta) == 0 and sin(beta) == -1
120  const Scalar sneg = R(k, j) - R(j, i); // 2*sin(alpha + gamma)
121  const Scalar cneg = R(j, j) + R(k, i); // 2*cos(alpha + gamma)
122  res[0] = atan2(sneg, cneg);
123  res[2] = 0;
124  return { res, false };
125 }
126 
127 KinematicConstraint::KinematicConstraint(const moveit::core::RobotModelConstPtr& model)
128  : type_(UNKNOWN_CONSTRAINT), robot_model_(model), constraint_weight_(std::numeric_limits<double>::epsilon())
129 {
130 }
131 
133 
134 bool JointConstraint::configure(const moveit_msgs::msg::JointConstraint& jc)
135 {
136  // clearing before we configure to get rid of any old data
137  clear();
138 
139  // testing tolerances first
140  if (jc.tolerance_above < 0.0 || jc.tolerance_below < 0.0)
141  {
142  RCLCPP_WARN(LOGGER, "JointConstraint tolerance values must be positive.");
143  joint_model_ = nullptr;
144  return false;
145  }
146 
147  joint_variable_name_ = jc.joint_name;
148  local_variable_name_.clear();
149  if (robot_model_->hasJointModel(joint_variable_name_))
150  {
152  }
153  else
154  {
155  std::size_t pos = jc.joint_name.find_last_of('/');
156  if (pos != std::string::npos)
157  {
158  joint_model_ = robot_model_->getJointModel(jc.joint_name.substr(0, pos));
159  if (pos + 1 < jc.joint_name.length())
160  local_variable_name_ = jc.joint_name.substr(pos + 1);
161  }
162  else
163  joint_model_ = robot_model_->getJointModel(jc.joint_name);
164  }
165 
166  if (joint_model_)
167  {
168  if (local_variable_name_.empty())
169  {
170  // check if the joint has 1 DOF (the only kind we can handle)
171  if (joint_model_->getVariableCount() == 0)
172  {
173  RCLCPP_ERROR(LOGGER, "Joint '%s' has no parameters to constrain", jc.joint_name.c_str());
174  joint_model_ = nullptr;
175  }
176  else if (joint_model_->getVariableCount() > 1)
177  {
178  RCLCPP_ERROR(LOGGER,
179  "Joint '%s' has more than one parameter to constrain. "
180  "This type of constraint is not supported.",
181  jc.joint_name.c_str());
182  joint_model_ = nullptr;
183  }
184  }
185  else
186  {
187  int found = -1;
188  const std::vector<std::string>& local_var_names = joint_model_->getLocalVariableNames();
189  for (std::size_t i = 0; i < local_var_names.size(); ++i)
190  {
191  if (local_var_names[i] == local_variable_name_)
192  {
193  found = i;
194  break;
195  }
196  }
197  if (found < 0)
198  {
199  RCLCPP_ERROR(LOGGER, "Local variable name '%s' is not known to joint '%s'", local_variable_name_.c_str(),
200  joint_model_->getName().c_str());
201  joint_model_ = nullptr;
202  }
203  }
204  }
205 
206  if (joint_model_)
207  {
208  joint_is_continuous_ = false;
209  joint_tolerance_above_ = jc.tolerance_above;
210  joint_tolerance_below_ = jc.tolerance_below;
212 
213  // check if we have to wrap angles when computing distances
214  joint_is_continuous_ = false;
216  {
217  const moveit::core::RevoluteJointModel* rjoint =
218  static_cast<const moveit::core::RevoluteJointModel*>(joint_model_);
219  if (rjoint->isContinuous())
220  joint_is_continuous_ = true;
221  }
223  {
224  if (local_variable_name_ == "theta")
225  joint_is_continuous_ = true;
226  }
227 
229  {
230  joint_position_ = normalizeAngle(jc.position);
231  }
232  else
233  {
234  joint_position_ = jc.position;
236 
238  {
240  joint_tolerance_above_ = std::numeric_limits<double>::epsilon();
241  RCLCPP_WARN(LOGGER,
242  "Joint %s is constrained to be below the minimum bounds. "
243  "Assuming minimum bounds instead.",
244  jc.joint_name.c_str());
245  }
247  {
249  joint_tolerance_below_ = std::numeric_limits<double>::epsilon();
250  RCLCPP_WARN(LOGGER,
251  "Joint %s is constrained to be above the maximum bounds. "
252  "Assuming maximum bounds instead.",
253  jc.joint_name.c_str());
254  }
255  }
256 
257  if (jc.weight <= std::numeric_limits<double>::epsilon())
258  {
259  RCLCPP_WARN(LOGGER, "The weight on constraint for joint '%s' is very near zero. Setting to 1.0.",
260  jc.joint_name.c_str());
261  constraint_weight_ = 1.0;
262  }
263  else
264  constraint_weight_ = jc.weight;
265  }
266  return joint_model_ != nullptr;
267 }
268 
269 bool JointConstraint::equal(const KinematicConstraint& other, double margin) const
270 {
271  if (other.getType() != type_)
272  return false;
273  const JointConstraint& o = static_cast<const JointConstraint&>(other);
275  {
276  return fabs(joint_position_ - o.joint_position_) <= margin &&
277  fabs(joint_tolerance_above_ - o.joint_tolerance_above_) <= margin &&
279  }
280  return false;
281 }
282 
284 {
285  if (!joint_model_)
286  return ConstraintEvaluationResult(true, 0.0);
287 
288  double current_joint_position = state.getVariablePosition(joint_variable_index_);
289  double dif = 0.0;
290 
291  // compute signed shortest distance for continuous joints
293  {
294  dif = normalizeAngle(current_joint_position) - joint_position_;
295 
296  if (dif > M_PI)
297  {
298  dif = 2.0 * M_PI - dif;
299  }
300  else if (dif < -M_PI)
301  {
302  dif += 2.0 * M_PI; // we include a sign change to have dif > 0
303  }
304  }
305  else
306  dif = current_joint_position - joint_position_;
307 
308  // check bounds
309  bool result = dif <= (joint_tolerance_above_ + 2.0 * std::numeric_limits<double>::epsilon()) &&
310  dif >= (-joint_tolerance_below_ - 2.0 * std::numeric_limits<double>::epsilon());
311  if (verbose)
312  {
313  RCLCPP_INFO(LOGGER,
314  "Constraint %s:: Joint name: '%s', actual value: %f, desired value: %f, "
315  "tolerance_above: %f, tolerance_below: %f",
316  result ? "satisfied" : "violated", joint_variable_name_.c_str(), current_joint_position,
318  }
319  return ConstraintEvaluationResult(result, constraint_weight_ * fabs(dif));
320 }
321 
323 {
324  return joint_model_;
325 }
326 
328 {
329  joint_model_ = nullptr;
331  joint_is_continuous_ = false;
335 }
336 
337 void JointConstraint::print(std::ostream& out) const
338 {
339  if (joint_model_)
340  {
341  out << "Joint constraint for joint " << joint_variable_name_ << ": \n";
342  out << " value = ";
343  out << joint_position_ << "; ";
344  out << " tolerance below = ";
345  out << joint_tolerance_below_ << "; ";
346  out << " tolerance above = ";
347  out << joint_tolerance_above_ << "; ";
348  out << '\n';
349  }
350  else
351  out << "No constraint" << '\n';
352 }
353 
354 bool PositionConstraint::configure(const moveit_msgs::msg::PositionConstraint& pc, const moveit::core::Transforms& tf)
355 {
356  // clearing before we configure to get rid of any old data
357  clear();
358 
359  link_model_ = robot_model_->getLinkModel(pc.link_name);
360  if (link_model_ == nullptr)
361  {
362  RCLCPP_WARN(LOGGER, "Position constraint link model %s not found in kinematic model. Constraint invalid.",
363  pc.link_name.c_str());
364  return false;
365  }
366 
367  if (pc.header.frame_id.empty())
368  {
369  RCLCPP_WARN(LOGGER, "No frame specified for position constraint on link '%s'!", pc.link_name.c_str());
370  return false;
371  }
372 
373  offset_ = Eigen::Vector3d(pc.target_point_offset.x, pc.target_point_offset.y, pc.target_point_offset.z);
374  has_offset_ = offset_.squaredNorm() > std::numeric_limits<double>::epsilon();
375 
376  if (tf.isFixedFrame(pc.header.frame_id))
377  {
379  mobile_frame_ = false;
380  }
381  else
382  {
383  constraint_frame_id_ = pc.header.frame_id;
384  mobile_frame_ = true;
385  }
386 
387  // load primitive shapes, first clearing any we already have
388  for (std::size_t i = 0; i < pc.constraint_region.primitives.size(); ++i)
389  {
390  std::unique_ptr<shapes::Shape> shape(shapes::constructShapeFromMsg(pc.constraint_region.primitives[i]));
391  if (shape)
392  {
393  if (pc.constraint_region.primitive_poses.size() <= i)
394  {
395  RCLCPP_WARN(LOGGER, "Constraint region message does not contain enough primitive poses");
396  continue;
397  }
398  Eigen::Isometry3d t;
399  tf2::fromMsg(pc.constraint_region.primitive_poses[i], t);
400  ASSERT_ISOMETRY(t) // unsanitized input, could contain a non-isometry
401  constraint_region_pose_.push_back(t);
402  if (!mobile_frame_)
403  tf.transformPose(pc.header.frame_id, constraint_region_pose_.back(), constraint_region_pose_.back());
404 
405  const bodies::BodyPtr body(bodies::createEmptyBodyFromShapeType(shape->type));
406  body->setDimensionsDirty(shape.get());
407  body->setPoseDirty(constraint_region_pose_.back());
408  body->updateInternalData();
409  constraint_region_.push_back(body);
410  }
411  else
412  RCLCPP_WARN(LOGGER, "Could not construct primitive shape %zu", i);
413  }
414 
415  // load meshes
416  for (std::size_t i = 0; i < pc.constraint_region.meshes.size(); ++i)
417  {
418  std::unique_ptr<shapes::Shape> shape(shapes::constructShapeFromMsg(pc.constraint_region.meshes[i]));
419  if (shape)
420  {
421  if (pc.constraint_region.mesh_poses.size() <= i)
422  {
423  RCLCPP_WARN(LOGGER, "Constraint region message does not contain enough primitive poses");
424  continue;
425  }
426  Eigen::Isometry3d t;
427  tf2::fromMsg(pc.constraint_region.mesh_poses[i], t);
428  ASSERT_ISOMETRY(t) // unsanitized input, could contain a non-isometry
429  constraint_region_pose_.push_back(t);
430  if (!mobile_frame_)
431  tf.transformPose(pc.header.frame_id, constraint_region_pose_.back(), constraint_region_pose_.back());
432  const bodies::BodyPtr body(bodies::createEmptyBodyFromShapeType(shape->type));
433  body->setDimensionsDirty(shape.get());
434  body->setPoseDirty(constraint_region_pose_.back());
435  body->updateInternalData();
436  constraint_region_.push_back(body);
437  }
438  else
439  {
440  RCLCPP_WARN(LOGGER, "Could not construct mesh shape %zu", i);
441  }
442  }
443 
444  if (pc.weight <= std::numeric_limits<double>::epsilon())
445  {
446  RCLCPP_WARN(LOGGER, "The weight on position constraint for link '%s' is near zero. Setting to 1.0.",
447  pc.link_name.c_str());
448  constraint_weight_ = 1.0;
449  }
450  else
451  constraint_weight_ = pc.weight;
452 
453  return !constraint_region_.empty();
454 }
455 
456 bool PositionConstraint::equal(const KinematicConstraint& other, double margin) const
457 {
458  if (other.getType() != type_)
459  return false;
460  const PositionConstraint& o = static_cast<const PositionConstraint&>(other);
461 
463  {
464  if ((offset_ - o.offset_).norm() > margin)
465  return false;
466  std::vector<bool> other_region_matches_this(constraint_region_.size(), false);
467  for (std::size_t i = 0; i < constraint_region_.size(); ++i)
468  {
469  bool some_match = false;
470  // need to check against all other regions
471  for (std::size_t j = 0; j < o.constraint_region_.size(); ++j)
472  {
473  // constraint_region_pose_ contain only valid isometries, so diff is also a valid isometry
474  Eigen::Isometry3d diff = constraint_region_pose_[i].inverse() * o.constraint_region_pose_[j];
475  if (diff.translation().norm() < margin && diff.linear().isIdentity(margin) &&
476  constraint_region_[i]->getType() == o.constraint_region_[j]->getType() &&
477  fabs(constraint_region_[i]->computeVolume() - o.constraint_region_[j]->computeVolume()) < margin)
478  {
479  some_match = true;
480  // can't break, as need to do matches the other way as well
481  other_region_matches_this[j] = true;
482  }
483  }
484  if (!some_match)
485  return false;
486  }
487  for (std::size_t i = 0; i < o.constraint_region_.size(); ++i)
488  {
489  if (!other_region_matches_this[i])
490  return false;
491  }
492  return true;
493  }
494  return false;
495 }
496 
497 // helper function to avoid code duplication
498 static inline ConstraintEvaluationResult finishPositionConstraintDecision(const Eigen::Vector3d& pt,
499  const Eigen::Vector3d& desired,
500  const std::string& name, double weight,
501  bool result, bool verbose)
502 {
503  double dx = desired.x() - pt.x();
504  double dy = desired.y() - pt.y();
505  double dz = desired.z() - pt.z();
506  if (verbose)
507  {
508  RCLCPP_INFO(LOGGER, "Position constraint %s on link '%s'. Desired: %f, %f, %f, current: %f, %f, %f",
509  result ? "satisfied" : "violated", name.c_str(), desired.x(), desired.y(), desired.z(), pt.x(), pt.y(),
510  pt.z());
511  RCLCPP_INFO(LOGGER, "Differences %g %g %g", dx, dy, dz);
512  }
513  return ConstraintEvaluationResult(result, weight * sqrt(dx * dx + dy * dy + dz * dz));
514 }
515 
517 {
518  if (!link_model_ || constraint_region_.empty())
519  return ConstraintEvaluationResult(true, 0.0);
520 
522  if (mobile_frame_)
523  {
524  for (std::size_t i = 0; i < constraint_region_.size(); ++i)
525  {
526  Eigen::Isometry3d tmp = state.getFrameTransform(constraint_frame_id_) * constraint_region_pose_[i];
527  bool result = constraint_region_[i]->cloneAt(tmp)->containsPoint(pt, verbose);
528  if (result || (i + 1 == constraint_region_pose_.size()))
529  {
530  return finishPositionConstraintDecision(pt, tmp.translation(), link_model_->getName(), constraint_weight_,
531  result, verbose);
532  }
533  else
534  {
535  finishPositionConstraintDecision(pt, tmp.translation(), link_model_->getName(), constraint_weight_, result,
536  verbose);
537  }
538  }
539  }
540  else
541  {
542  for (std::size_t i = 0; i < constraint_region_.size(); ++i)
543  {
544  bool result = constraint_region_[i]->containsPoint(pt, true);
545  if (result || (i + 1 == constraint_region_.size()))
546  {
547  return finishPositionConstraintDecision(pt, constraint_region_[i]->getPose().translation(),
548  link_model_->getName(), constraint_weight_, result, verbose);
549  }
550  else
551  {
552  finishPositionConstraintDecision(pt, constraint_region_[i]->getPose().translation(), link_model_->getName(),
553  constraint_weight_, result, verbose);
554  }
555  }
556  }
557  return ConstraintEvaluationResult(false, 0.0);
558 }
559 
560 void PositionConstraint::print(std::ostream& out) const
561 {
562  if (enabled())
563  {
564  out << "Position constraint on link '" << link_model_->getName() << '\'' << '\n';
565  }
566  else
567  {
568  out << "No constraint" << '\n';
569  }
570 }
571 
573 {
574  offset_ = Eigen::Vector3d(0.0, 0.0, 0.0);
575  has_offset_ = false;
576  constraint_region_.clear();
577  constraint_region_pose_.clear();
578  mobile_frame_ = false;
580  link_model_ = nullptr;
581 }
582 
584 {
585  return link_model_ && !constraint_region_.empty();
586 }
587 
588 bool OrientationConstraint::configure(const moveit_msgs::msg::OrientationConstraint& oc,
589  const moveit::core::Transforms& tf)
590 {
591  // clearing out any old data
592  clear();
593 
594  link_model_ = robot_model_->getLinkModel(oc.link_name);
595  if (!link_model_)
596  {
597  RCLCPP_WARN(LOGGER, "Could not find link model for link name %s", oc.link_name.c_str());
598  return false;
599  }
600  Eigen::Quaterniond q;
601  tf2::fromMsg(oc.orientation, q);
602  if (fabs(q.norm() - 1.0) > 1e-3)
603  {
604  RCLCPP_WARN(LOGGER,
605  "Orientation constraint for link '%s' is probably incorrect: %f, %f, %f, "
606  "%f. Assuming identity instead.",
607  oc.link_name.c_str(), oc.orientation.x, oc.orientation.y, oc.orientation.z, oc.orientation.w);
608  q = Eigen::Quaterniond(1.0, 0.0, 0.0, 0.0);
609  }
610 
611  if (oc.header.frame_id.empty())
612  RCLCPP_WARN(LOGGER, "No frame specified for position constraint on link '%s'!", oc.link_name.c_str());
613 
614  if (tf.isFixedFrame(oc.header.frame_id))
615  {
616  tf.transformQuaternion(oc.header.frame_id, q, q);
618  desired_rotation_matrix_ = Eigen::Matrix3d(q);
620  mobile_frame_ = false;
621  }
622  else
623  {
624  desired_rotation_frame_id_ = oc.header.frame_id;
625  desired_rotation_matrix_ = Eigen::Matrix3d(q);
626  mobile_frame_ = true;
627  }
628  std::stringstream matrix_str;
629  matrix_str << desired_rotation_matrix_;
630  RCLCPP_DEBUG(LOGGER, "The desired rotation matrix for link '%s' in frame %s is:\n%s", oc.link_name.c_str(),
631  desired_rotation_frame_id_.c_str(), matrix_str.str().c_str());
632 
633  if (oc.weight <= std::numeric_limits<double>::epsilon())
634  {
635  RCLCPP_WARN(LOGGER, "The weight on orientation constraint for link '%s' is near zero. Setting to 1.0.",
636  oc.link_name.c_str());
637  constraint_weight_ = 1.0;
638  }
639  else
640  {
641  constraint_weight_ = oc.weight;
642  }
643 
644  parameterization_type_ = oc.parameterization;
645  // validate the parameterization, set to default value if invalid
646  if (parameterization_type_ != moveit_msgs::msg::OrientationConstraint::XYZ_EULER_ANGLES &&
647  parameterization_type_ != moveit_msgs::msg::OrientationConstraint::ROTATION_VECTOR)
648  {
649  RCLCPP_WARN(LOGGER,
650  "Unknown parameterization for orientation constraint tolerance, using default (XYZ_EULER_ANGLES).");
651  parameterization_type_ = moveit_msgs::msg::OrientationConstraint::XYZ_EULER_ANGLES;
652  }
653 
654  absolute_x_axis_tolerance_ = fabs(oc.absolute_x_axis_tolerance);
655  if (absolute_x_axis_tolerance_ < std::numeric_limits<double>::epsilon())
656  RCLCPP_WARN(LOGGER, "Near-zero value for absolute_x_axis_tolerance");
657  absolute_y_axis_tolerance_ = fabs(oc.absolute_y_axis_tolerance);
658  if (absolute_y_axis_tolerance_ < std::numeric_limits<double>::epsilon())
659  RCLCPP_WARN(LOGGER, "Near-zero value for absolute_y_axis_tolerance");
660  absolute_z_axis_tolerance_ = fabs(oc.absolute_z_axis_tolerance);
661  if (absolute_z_axis_tolerance_ < std::numeric_limits<double>::epsilon())
662  RCLCPP_WARN(LOGGER, "Near-zero value for absolute_z_axis_tolerance");
663 
664  return link_model_ != nullptr;
665 }
666 
667 bool OrientationConstraint::equal(const KinematicConstraint& other, double margin) const
668 {
669  if (other.getType() != type_)
670  return false;
671  const OrientationConstraint& o = static_cast<const OrientationConstraint&>(other);
672 
673  if (o.link_model_ == link_model_ &&
675  {
677  return false;
678  return fabs(absolute_x_axis_tolerance_ - o.absolute_x_axis_tolerance_) <= margin &&
681  }
682  return false;
683 }
684 
686 {
687  link_model_ = nullptr;
688  desired_rotation_matrix_ = Eigen::Matrix3d::Identity();
689  desired_rotation_matrix_inv_ = Eigen::Matrix3d::Identity();
691  mobile_frame_ = false;
693 }
694 
696 {
697  return link_model_;
698 }
699 
701 {
702  if (!link_model_)
703  return ConstraintEvaluationResult(true, 0.0);
704 
705  Eigen::Isometry3d diff;
706  if (mobile_frame_)
707  {
708  // getFrameTransform() returns a valid isometry by contract
709  Eigen::Matrix3d tmp = state.getFrameTransform(desired_rotation_frame_id_).linear() * desired_rotation_matrix_;
710  // getGlobalLinkTransform() returns a valid isometry by contract
711  diff = Eigen::Isometry3d(tmp.transpose() * state.getGlobalLinkTransform(link_model_).linear()); // valid isometry
712  }
713  else
714  {
715  // diff is valid isometry by construction
716  diff = Eigen::Isometry3d(desired_rotation_matrix_inv_ * state.getGlobalLinkTransform(link_model_).linear());
717  }
718 
719  // This needs to live outside the if-block scope (as xyz_rotation points to its data).
720  std::tuple<Eigen::Vector3d, bool> euler_angles_error;
721  Eigen::Vector3d xyz_rotation;
722  if (parameterization_type_ == moveit_msgs::msg::OrientationConstraint::XYZ_EULER_ANGLES)
723  {
724  euler_angles_error = calcEulerAngles(diff.linear());
725  // Converting from a rotation matrix to intrinsic XYZ Euler angles has 2 singularities:
726  // pitch ~= pi/2 ==> roll + yaw = theta
727  // pitch ~= -pi/2 ==> roll - yaw = theta
728  // in those cases calcEulerAngles will set roll (xyz_rotation(0)) to theta and yaw (xyz_rotation(2)) to zero, so for
729  // us to be able to capture yaw tolerance violations we do the following: If theta violates the absolute yaw
730  // tolerance we think of it as a pure yaw rotation and set roll to zero.
731  xyz_rotation = std::get<Eigen::Vector3d>(euler_angles_error);
732  if (!std::get<bool>(euler_angles_error))
733  {
734  if (normalizeAbsoluteAngle(xyz_rotation(0)) > absolute_z_axis_tolerance_ + std::numeric_limits<double>::epsilon())
735  {
736  xyz_rotation(2) = xyz_rotation(0);
737  xyz_rotation(0) = 0;
738  }
739  }
740  // Account for angle wrapping
741  xyz_rotation = xyz_rotation.unaryExpr(&normalizeAbsoluteAngle);
742  }
743  else if (parameterization_type_ == moveit_msgs::msg::OrientationConstraint::ROTATION_VECTOR)
744  {
745  Eigen::AngleAxisd aa(diff.linear());
746  xyz_rotation = aa.axis() * aa.angle();
747  xyz_rotation(0) = fabs(xyz_rotation(0));
748  xyz_rotation(1) = fabs(xyz_rotation(1));
749  xyz_rotation(2) = fabs(xyz_rotation(2));
750  }
751  else
752  {
753  /* The parameterization type should be validated in configure, so this should never happen. */
754  RCLCPP_ERROR(LOGGER, "The parameterization type for the orientation constraints is invalid.");
755  }
756 
757  bool result = xyz_rotation(2) < absolute_z_axis_tolerance_ + std::numeric_limits<double>::epsilon() &&
758  xyz_rotation(1) < absolute_y_axis_tolerance_ + std::numeric_limits<double>::epsilon() &&
759  xyz_rotation(0) < absolute_x_axis_tolerance_ + std::numeric_limits<double>::epsilon();
760 
761  if (verbose)
762  {
763  Eigen::Quaterniond q_act(state.getGlobalLinkTransform(link_model_).linear());
764  Eigen::Quaterniond q_des(desired_rotation_matrix_);
765  RCLCPP_INFO(LOGGER,
766  "Orientation constraint %s for link '%s'. Quaternion desired: %f %f %f %f, quaternion "
767  "actual: %f %f %f %f, error: x=%f, y=%f, z=%f, tolerance: x=%f, y=%f, z=%f",
768  result ? "satisfied" : "violated", link_model_->getName().c_str(), q_des.x(), q_des.y(), q_des.z(),
769  q_des.w(), q_act.x(), q_act.y(), q_act.z(), q_act.w(), xyz_rotation(0), xyz_rotation(1),
771  }
772 
773  return ConstraintEvaluationResult(result, constraint_weight_ * (xyz_rotation(0) + xyz_rotation(1) + xyz_rotation(2)));
774 }
775 
776 void OrientationConstraint::print(std::ostream& out) const
777 {
778  if (link_model_)
779  {
780  out << "Orientation constraint on link '" << link_model_->getName() << '\'' << '\n';
781  Eigen::Quaterniond q_des(desired_rotation_matrix_);
782  out << "Desired orientation:" << q_des.x() << ',' << q_des.y() << ',' << q_des.z() << ',' << q_des.w() << '\n';
783  }
784  else
785  out << "No constraint" << '\n';
786 }
787 
788 VisibilityConstraint::VisibilityConstraint(const moveit::core::RobotModelConstPtr& model)
789  : KinematicConstraint(model), robot_model_{ model }
790 {
792 }
793 
795 {
796  target_frame_id_ = "";
797  sensor_frame_id_ = "";
798  sensor_pose_ = Eigen::Isometry3d::Identity();
800  target_pose_ = Eigen::Isometry3d::Identity();
801  cone_sides_ = 0;
802  points_.clear();
803  target_radius_ = -1.0;
804  max_view_angle_ = 0.0;
805  max_range_angle_ = 0.0;
806 }
807 
808 bool VisibilityConstraint::configure(const moveit_msgs::msg::VisibilityConstraint& vc,
809  const moveit::core::Transforms& tf)
810 {
811  clear();
812  target_radius_ = fabs(vc.target_radius);
813 
814  if (vc.target_radius <= std::numeric_limits<double>::epsilon())
815  RCLCPP_WARN(LOGGER, "The radius of the target disc that must be visible should be strictly positive");
816 
817  if (vc.cone_sides < 3)
818  {
819  RCLCPP_WARN(LOGGER,
820  "The number of sides for the visibility region must be 3 or more. "
821  "Assuming 3 sides instead of the specified %d",
822  vc.cone_sides);
823  cone_sides_ = 3;
824  }
825  else
826  cone_sides_ = vc.cone_sides;
827 
828  // compute the points on the base circle of the cone that make up the cone sides
829  points_.clear();
830  double delta = 2.0 * M_PI / static_cast<double>(cone_sides_);
831  double a = 0.0;
832  for (unsigned int i = 0; i < cone_sides_; ++i, a += delta)
833  {
834  double x = sin(a) * target_radius_;
835  double y = cos(a) * target_radius_;
836  points_.push_back(Eigen::Vector3d(x, y, 0.0));
837  }
838 
839  tf2::fromMsg(vc.target_pose.pose, target_pose_);
840  ASSERT_ISOMETRY(target_pose_) // unsanitized input, could contain a non-isometry
841 
842  if (tf.isFixedFrame(vc.target_pose.header.frame_id))
843  {
844  tf.transformPose(vc.target_pose.header.frame_id, target_pose_, target_pose_);
846  }
847  else
848  {
849  target_frame_id_ = vc.target_pose.header.frame_id;
850  }
851 
852  tf2::fromMsg(vc.sensor_pose.pose, sensor_pose_);
853  ASSERT_ISOMETRY(sensor_pose_) // unsanitized input, could contain a non-isometry
854 
855  if (tf.isFixedFrame(vc.sensor_pose.header.frame_id))
856  {
857  tf.transformPose(vc.sensor_pose.header.frame_id, sensor_pose_, sensor_pose_);
859  }
860  else
861  {
862  sensor_frame_id_ = vc.sensor_pose.header.frame_id;
863  }
864 
865  if (vc.weight <= std::numeric_limits<double>::epsilon())
866  {
867  RCLCPP_WARN(LOGGER, "The weight of visibility constraint is near zero. Setting to 1.0.");
868  constraint_weight_ = 1.0;
869  }
870  else
871  constraint_weight_ = vc.weight;
872 
873  max_view_angle_ = vc.max_view_angle;
874  max_range_angle_ = vc.max_range_angle;
875  sensor_view_direction_ = vc.sensor_view_direction;
876 
877  return enabled();
878 }
879 
880 bool VisibilityConstraint::equal(const KinematicConstraint& other, double margin) const
881 {
882  if (other.getType() != type_)
883  return false;
884  const VisibilityConstraint& o = static_cast<const VisibilityConstraint&>(other);
885 
889  {
890  if (fabs(max_view_angle_ - o.max_view_angle_) > margin || fabs(target_radius_ - o.target_radius_) > margin)
891  return false;
892  // sensor_pose_ is valid isometry, checked in configure()
893  Eigen::Isometry3d diff = sensor_pose_.inverse() * o.sensor_pose_; // valid isometry
894  if (diff.translation().norm() > margin)
895  return false;
896  if (!diff.linear().isIdentity(margin))
897  return false;
898  // target_pose_ is valid isometry, checked in configure()
899  diff = target_pose_.inverse() * o.target_pose_; // valid isometry
900  if (diff.translation().norm() > margin)
901  return false;
902  if (!diff.linear().isIdentity(margin))
903  return false;
904  return true;
905  }
906  return false;
907 }
908 
910 {
911  return (target_radius_ > std::numeric_limits<double>::epsilon()) ||
912  (max_view_angle_ > std::numeric_limits<double>::epsilon()) ||
913  (max_range_angle_ > std::numeric_limits<double>::epsilon());
914 }
915 
916 shapes::Mesh* VisibilityConstraint::getVisibilityCone(const Eigen::Isometry3d& tform_world_to_sensor,
917  const Eigen::Isometry3d& tform_world_to_target) const
918 {
919  // the current pose of the sensor
920  const Eigen::Isometry3d& sp = tform_world_to_sensor;
921 
922  // the current pose of the target
923  const Eigen::Isometry3d& tp = tform_world_to_target;
924 
925  // transform the points on the disc to the desired target frame
926  const EigenSTL::vector_Vector3d* points = &points_;
927  std::unique_ptr<EigenSTL::vector_Vector3d> temp_points;
928 
929  temp_points = std::make_unique<EigenSTL::vector_Vector3d>(points_.size());
930  for (std::size_t i = 0; i < points_.size(); ++i)
931  {
932  temp_points->at(i) = tp * points_[i];
933  }
934  points = temp_points.get();
935 
936  // allocate memory for a mesh to represent the visibility cone
937  shapes::Mesh* m = new shapes::Mesh();
938  m->vertex_count = cone_sides_ + 2;
939  m->vertices = new double[m->vertex_count * 3];
940  m->triangle_count = cone_sides_ * 2;
941  m->triangles = new unsigned int[m->triangle_count * 3];
942  // we do NOT allocate normals because we do not compute them
943 
944  // the sensor origin
945  m->vertices[0] = sp.translation().x();
946  m->vertices[1] = sp.translation().y();
947  m->vertices[2] = sp.translation().z();
948 
949  // the center of the base of the cone approximation
950  m->vertices[3] = tp.translation().x();
951  m->vertices[4] = tp.translation().y();
952  m->vertices[5] = tp.translation().z();
953 
954  // the points that approximate the base disc
955  for (std::size_t i = 0; i < points->size(); ++i)
956  {
957  m->vertices[i * 3 + 6] = points->at(i).x();
958  m->vertices[i * 3 + 7] = points->at(i).y();
959  m->vertices[i * 3 + 8] = points->at(i).z();
960  }
961 
962  // add the triangles
963  std::size_t p3 = points->size() * 3;
964  for (std::size_t i = 1; i < points->size(); ++i)
965  {
966  // triangle forming a side of the cone, using the sensor origin
967  std::size_t i3 = (i - 1) * 3;
968  m->triangles[i3] = i + 1;
969  m->triangles[i3 + 1] = 0;
970  m->triangles[i3 + 2] = i + 2;
971  // triangle forming a part of the base of the cone, using the center of the base
972  std::size_t i6 = p3 + i3;
973  m->triangles[i6] = i + 1;
974  m->triangles[i6 + 1] = 1;
975  m->triangles[i6 + 2] = i + 2;
976  }
977 
978  // last triangles
979  m->triangles[p3 - 3] = points->size() + 1;
980  m->triangles[p3 - 2] = 0;
981  m->triangles[p3 - 1] = 2;
982  p3 *= 2;
983  m->triangles[p3 - 3] = points->size() + 1;
984  m->triangles[p3 - 2] = 1;
985  m->triangles[p3 - 1] = 2;
986 
987  return m;
988 }
989 
991  visualization_msgs::msg::MarkerArray& markers) const
992 {
993  // getFrameTransform() returns a valid isometry by contract
994  // sensor_pose_ is valid isometry (checked in configure())
995  const Eigen::Isometry3d& sp = state.getFrameTransform(sensor_frame_id_) * sensor_pose_;
996  // target_pose_ is valid isometry (checked in configure())
997  const Eigen::Isometry3d& tp = state.getFrameTransform(target_frame_id_) * target_pose_;
998 
999  shapes::Mesh* m = getVisibilityCone(sp, tp);
1000  visualization_msgs::msg::Marker mk;
1001  shapes::constructMarkerFromShape(m, mk);
1002  delete m;
1003  mk.header.frame_id = robot_model_->getModelFrame();
1004  mk.header.stamp = rclcpp::Clock().now();
1005  mk.ns = "constraints";
1006  mk.id = 1;
1007  mk.action = visualization_msgs::msg::Marker::ADD;
1008  mk.pose.position.x = 0;
1009  mk.pose.position.y = 0;
1010  mk.pose.position.z = 0;
1011  mk.pose.orientation.x = 0;
1012  mk.pose.orientation.y = 0;
1013  mk.pose.orientation.z = 0;
1014  mk.pose.orientation.w = 1;
1015  mk.lifetime = rclcpp::Duration::from_seconds(60);
1016  // this scale necessary to make results look reasonable
1017  mk.scale.x = .01;
1018  mk.color.a = 1.0;
1019  mk.color.r = 1.0;
1020  mk.color.g = 0.0;
1021  mk.color.b = 0.0;
1022 
1023  markers.markers.push_back(mk);
1024 
1025  visualization_msgs::msg::Marker mka;
1026  mka.type = visualization_msgs::msg::Marker::ARROW;
1027  mka.action = visualization_msgs::msg::Marker::ADD;
1028  mka.color = mk.color;
1029  mka.pose = mk.pose;
1030 
1031  mka.header = mk.header;
1032  mka.ns = mk.ns;
1033  mka.id = 2;
1034  mka.lifetime = mk.lifetime;
1035  mka.scale.x = 0.05;
1036  mka.scale.y = .15;
1037  mka.scale.z = 0.0;
1038  mka.points.resize(2);
1039  Eigen::Vector3d d = tp.translation() + tp.linear().col(2) * 0.5;
1040  mka.points[0].x = tp.translation().x();
1041  mka.points[0].y = tp.translation().y();
1042  mka.points[0].z = tp.translation().z();
1043  mka.points[1].x = d.x();
1044  mka.points[1].y = d.y();
1045  mka.points[1].z = d.z();
1046  markers.markers.push_back(mka);
1047 
1048  mka.id = 3;
1049  mka.color.b = 1.0;
1050  mka.color.r = 0.0;
1051 
1052  d = sp.translation() + sp.linear().col(2 - sensor_view_direction_) * 0.5;
1053  mka.points[0].x = sp.translation().x();
1054  mka.points[0].y = sp.translation().y();
1055  mka.points[0].z = sp.translation().z();
1056  mka.points[1].x = d.x();
1057  mka.points[1].y = d.y();
1058  mka.points[1].z = d.z();
1059 
1060  markers.markers.push_back(mka);
1061 }
1062 
1064 {
1065  // getFrameTransform() returns a valid isometry by contract
1066  // sensor_pose_ is valid isometry (checked in configure())
1067  const Eigen::Isometry3d& tform_world_to_sensor = state.getFrameTransform(sensor_frame_id_) * sensor_pose_;
1068  // target_pose_ is valid isometry (checked in configure())
1069  const Eigen::Isometry3d& tform_world_to_target = state.getFrameTransform(target_frame_id_) * target_pose_;
1070 
1071  // necessary to do subtraction as SENSOR_Z is 0 and SENSOR_X is 2
1072  const Eigen::Vector3d& sensor_view_axis = tform_world_to_sensor.linear().col(2 - sensor_view_direction_);
1073 
1074  // Check view angle constraint
1075  if (max_view_angle_ > std::numeric_limits<double>::epsilon())
1076  {
1077  const Eigen::Vector3d& normal1 = tform_world_to_target.linear().col(2) * -1.0; // along Z axis and inverted
1078  double dp = sensor_view_axis.dot(normal1);
1079  double ang = acos(dp);
1080  if (dp < 0.0)
1081  {
1082  if (verbose)
1083  {
1084  RCLCPP_INFO(LOGGER, "Visibility constraint is violated because the sensor is looking at "
1085  "the wrong side");
1086  }
1087  return ConstraintEvaluationResult(false, 0.0);
1088  }
1089  if (max_view_angle_ < ang)
1090  {
1091  if (verbose)
1092  {
1093  RCLCPP_INFO(LOGGER,
1094  "Visibility constraint is violated because the view angle is %lf "
1095  "(above the maximum allowed of %lf)",
1096  ang, max_view_angle_);
1097  }
1098  return ConstraintEvaluationResult(false, 0.0);
1099  }
1100  }
1101 
1102  // Check range angle constraint
1103  if (max_range_angle_ > std::numeric_limits<double>::epsilon())
1104  {
1105  const Eigen::Vector3d& dir =
1106  (tform_world_to_target.translation() - tform_world_to_sensor.translation()).normalized();
1107  double dp = sensor_view_axis.dot(dir);
1108  if (dp < 0.0)
1109  {
1110  if (verbose)
1111  {
1112  RCLCPP_INFO(LOGGER, "Visibility constraint is violated because the sensor is looking at "
1113  "the wrong side");
1114  }
1115  return ConstraintEvaluationResult(false, 0.0);
1116  }
1117 
1118  double ang = acos(dp);
1119  if (max_range_angle_ < ang)
1120  {
1121  if (verbose)
1122  {
1123  RCLCPP_INFO(LOGGER,
1124  "Visibility constraint is violated because the range angle is %lf "
1125  "(above the maximum allowed of %lf)",
1126  ang, max_range_angle_);
1127  }
1128  return ConstraintEvaluationResult(false, 0.0);
1129  }
1130  }
1131 
1132  // Check visibility cone collision constraint
1133  if (target_radius_ > std::numeric_limits<double>::epsilon())
1134  {
1135  shapes::Mesh* m = getVisibilityCone(tform_world_to_sensor, tform_world_to_target);
1136  if (!m)
1137  {
1138  RCLCPP_ERROR(LOGGER, "Visibility constraint is violated because we could not create the visibility cone mesh.");
1139  return ConstraintEvaluationResult(false, 0.0);
1140  }
1141 
1142  // add the visibility cone as an object
1143  const auto collision_env_local = std::make_shared<collision_detection::CollisionEnvFCL>(robot_model_);
1144  collision_env_local->getWorld()->addToObject("cone", shapes::ShapeConstPtr(m), Eigen::Isometry3d::Identity());
1145 
1146  // check for collisions between the robot and the cone
1149  return decideContact(contact);
1150  };
1151  acm.setDefaultEntry(std::string("cone"), fn);
1152 
1154  req.contacts = true;
1155  req.verbose = verbose;
1156  req.max_contacts = 1;
1157 
1159  collision_env_local->checkRobotCollision(req, res, state, acm);
1160 
1161  if (verbose)
1162  {
1163  std::stringstream ss;
1164  m->print(ss);
1165  RCLCPP_INFO(LOGGER, "Visibility constraint %ssatisfied. Visibility cone approximation:\n %s",
1166  res.collision ? "not " : "", ss.str().c_str());
1167  }
1168 
1169  collision_env_local->getWorld()->removeObject("cone");
1170 
1171  return ConstraintEvaluationResult(!res.collision, res.collision ? res.contacts.begin()->second.front().depth : 0.0);
1172  }
1173 
1174  // Constraint evaluation succeeded if we made it here
1175  return ConstraintEvaluationResult(true, 0.0);
1176 }
1177 
1179 {
1182  return true;
1187  {
1188  RCLCPP_DEBUG(LOGGER, "Accepted collision with either sensor or target");
1189  return true;
1190  }
1195  {
1196  RCLCPP_DEBUG(LOGGER, "Accepted collision with either sensor or target");
1197  return true;
1198  }
1199  return false;
1200 }
1201 
1202 void VisibilityConstraint::print(std::ostream& out) const
1203 {
1204  if (enabled())
1205  {
1206  out << "Visibility constraint for sensor in frame '" << sensor_frame_id_ << "' using target in frame '"
1207  << target_frame_id_ << '\'' << '\n';
1208  out << "Target radius: " << target_radius_ << ", using " << cone_sides_ << " sides." << '\n';
1209  }
1210  else
1211  out << "No constraint" << '\n';
1212 }
1213 
1215 {
1216  all_constraints_ = moveit_msgs::msg::Constraints();
1217  kinematic_constraints_.clear();
1218  joint_constraints_.clear();
1219  position_constraints_.clear();
1220  orientation_constraints_.clear();
1221  visibility_constraints_.clear();
1222 }
1223 
1224 bool KinematicConstraintSet::add(const std::vector<moveit_msgs::msg::JointConstraint>& jc)
1225 {
1226  bool result = true;
1227  for (const moveit_msgs::msg::JointConstraint& joint_constraint : jc)
1228  {
1230  bool u = ev->configure(joint_constraint);
1231  result = result && u;
1232  kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
1233  joint_constraints_.push_back(joint_constraint);
1234  all_constraints_.joint_constraints.push_back(joint_constraint);
1235  }
1236  return result;
1237 }
1238 
1239 bool KinematicConstraintSet::add(const std::vector<moveit_msgs::msg::PositionConstraint>& pc,
1240  const moveit::core::Transforms& tf)
1241 {
1242  bool result = true;
1243  for (const moveit_msgs::msg::PositionConstraint& position_constraint : pc)
1244  {
1246  bool u = ev->configure(position_constraint, tf);
1247  result = result && u;
1248  kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
1249  position_constraints_.push_back(position_constraint);
1250  all_constraints_.position_constraints.push_back(position_constraint);
1251  }
1252  return result;
1253 }
1254 
1255 bool KinematicConstraintSet::add(const std::vector<moveit_msgs::msg::OrientationConstraint>& oc,
1256  const moveit::core::Transforms& tf)
1257 {
1258  bool result = true;
1259  for (const moveit_msgs::msg::OrientationConstraint& orientation_constraint : oc)
1260  {
1262  bool u = ev->configure(orientation_constraint, tf);
1263  result = result && u;
1264  kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
1265  orientation_constraints_.push_back(orientation_constraint);
1266  all_constraints_.orientation_constraints.push_back(orientation_constraint);
1267  }
1268  return result;
1269 }
1270 
1271 bool KinematicConstraintSet::add(const std::vector<moveit_msgs::msg::VisibilityConstraint>& vc,
1272  const moveit::core::Transforms& tf)
1273 {
1274  bool result = true;
1275  for (const moveit_msgs::msg::VisibilityConstraint& visibility_constraint : vc)
1276  {
1278  bool u = ev->configure(visibility_constraint, tf);
1279  result = result && u;
1280  kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
1281  visibility_constraints_.push_back(visibility_constraint);
1282  all_constraints_.visibility_constraints.push_back(visibility_constraint);
1283  }
1284  return result;
1285 }
1286 
1287 bool KinematicConstraintSet::add(const moveit_msgs::msg::Constraints& c, const moveit::core::Transforms& tf)
1288 {
1289  bool j = add(c.joint_constraints);
1290  bool p = add(c.position_constraints, tf);
1291  bool o = add(c.orientation_constraints, tf);
1292  bool v = add(c.visibility_constraints, tf);
1293  return j && p && o && v;
1294 }
1295 
1297 {
1298  ConstraintEvaluationResult res(true, 0.0);
1299  for (const KinematicConstraintPtr& kinematic_constraint : kinematic_constraints_)
1300  {
1301  ConstraintEvaluationResult r = kinematic_constraint->decide(state, verbose);
1302  if (!r.satisfied)
1303  res.satisfied = false;
1304  res.distance += r.distance;
1305  }
1306  return res;
1307 }
1308 
1310  std::vector<ConstraintEvaluationResult>& results,
1311  bool verbose) const
1312 {
1313  ConstraintEvaluationResult result(true, 0.0);
1314  results.resize(kinematic_constraints_.size());
1315  for (std::size_t i = 0; i < kinematic_constraints_.size(); ++i)
1316  {
1317  results[i] = kinematic_constraints_[i]->decide(state, verbose);
1318  result.satisfied = result.satisfied && results[i].satisfied;
1319  result.distance += results[i].distance;
1320  }
1321 
1322  return result;
1323 }
1324 
1325 void KinematicConstraintSet::print(std::ostream& out) const
1326 {
1327  out << kinematic_constraints_.size() << " kinematic constraints" << '\n';
1328  for (const KinematicConstraintPtr& kinematic_constraint : kinematic_constraints_)
1329  kinematic_constraint->print(out);
1330 }
1331 
1332 bool KinematicConstraintSet::equal(const KinematicConstraintSet& other, double margin) const
1333 {
1334  // each constraint in this matches some in the other
1335  for (const KinematicConstraintPtr& kinematic_constraint : kinematic_constraints_)
1336  {
1337  bool found = false;
1338  for (unsigned int j = 0; !found && j < other.kinematic_constraints_.size(); ++j)
1339  found = kinematic_constraint->equal(*other.kinematic_constraints_[j], margin);
1340  if (!found)
1341  return false;
1342  }
1343  // each constraint in the other matches some constraint in this
1344  for (const KinematicConstraintPtr& kinematic_constraint : other.kinematic_constraints_)
1345  {
1346  bool found = false;
1347  for (unsigned int j = 0; !found && j < kinematic_constraints_.size(); ++j)
1348  found = kinematic_constraint->equal(*kinematic_constraints_[j], margin);
1349  if (!found)
1350  return false;
1351  }
1352  return true;
1353 }
1354 
1355 } // end of namespace kinematic_constraints
Definition of a structure for the allowed collision matrix. All elements in the collision world are r...
void setDefaultEntry(const std::string &name, bool allowed)
Set the default value for entries that include name but are not set explicitly with setEntry().
Class for handling single DOF joint constraints.
double joint_tolerance_below_
Position and tolerance values.
std::string joint_variable_name_
The joint variable name.
bool equal(const KinematicConstraint &other, double margin) const override
Check if two joint constraints are the same.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const override
Decide whether the constraint is satisfied in the indicated state.
int joint_variable_index_
The index of the joint variable name in the full robot state.
bool joint_is_continuous_
Whether or not the joint is continuous.
void clear() override
Clear the stored constraint.
bool configure(const moveit_msgs::msg::JointConstraint &jc)
Configure the constraint based on a moveit_msgs::msg::JointConstraint.
const moveit::core::JointModel * joint_model_
The joint from the kinematic model for this constraint.
bool enabled() const override
This function returns true if this constraint is configured and able to decide whether states do meet...
void print(std::ostream &out=std::cout) const override
Print the constraint data.
std::string local_variable_name_
The local variable name for a multi DOF joint, if any.
A class that contains many different constraints, and can check RobotState *versus the full set....
void print(std::ostream &out=std::cout) const
Print the constraint data.
bool equal(const KinematicConstraintSet &other, double margin) const
Whether or not another KinematicConstraintSet is equal to this one.
std::vector< moveit_msgs::msg::VisibilityConstraint > visibility_constraints_
Messages corresponding to all internal visibility constraints.
std::vector< moveit_msgs::msg::OrientationConstraint > orientation_constraints_
Messages corresponding to all internal orientation constraints.
moveit::core::RobotModelConstPtr robot_model_
The kinematic model used for by the Set.
bool add(const moveit_msgs::msg::Constraints &c, const moveit::core::Transforms &tf)
Add all known constraints.
moveit_msgs::msg::Constraints all_constraints_
Messages corresponding to all internal constraints.
std::vector< moveit_msgs::msg::PositionConstraint > position_constraints_
Messages corresponding to all internal position constraints.
std::vector< KinematicConstraintPtr > kinematic_constraints_
Shared pointers to all the member constraints.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const
Determines whether all constraints are satisfied by state, returning a single evaluation result.
std::vector< moveit_msgs::msg::JointConstraint > joint_constraints_
Messages corresponding to all internal joint constraints.
Base class for representing a kinematic constraint.
double constraint_weight_
The weight of a constraint is a multiplicative factor associated to the distance computed by the deci...
ConstraintType type_
The type of the constraint.
ConstraintType getType() const
Get the type of constraint.
KinematicConstraint(const moveit::core::RobotModelConstPtr &model)
Constructor.
moveit::core::RobotModelConstPtr robot_model_
The kinematic model associated with this constraint.
Class for constraints on the orientation of a link.
bool mobile_frame_
Whether or not the header frame is mobile or fixed.
void clear() override
Clear the stored constraint.
bool equal(const KinematicConstraint &other, double margin) const override
Check if two orientation constraints are the same.
void print(std::ostream &out=std::cout) const override
Print the constraint data.
std::string desired_rotation_frame_id_
The target frame of the transform tree.
bool configure(const moveit_msgs::msg::OrientationConstraint &oc, const moveit::core::Transforms &tf)
Configure the constraint based on a moveit_msgs::msg::OrientationConstraint.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const override
Decide whether the constraint is satisfied in the indicated state.
double absolute_z_axis_tolerance_
Storage for the tolerances.
Eigen::Matrix3d desired_rotation_matrix_inv_
The inverse of the desired rotation matrix, precomputed for efficiency. Guaranteed to be valid rotati...
bool enabled() const override
This function returns true if this constraint is configured and able to decide whether states do meet...
Eigen::Matrix3d desired_rotation_matrix_
The desired rotation matrix in the tf frame. Guaranteed to be valid rotation matrix.
const moveit::core::LinkModel * link_model_
The target link model.
int parameterization_type_
Parameterization type for orientation tolerance.
Class for constraints on the XYZ position of a link.
void print(std::ostream &out=std::cout) const override
Print the constraint data.
bool enabled() const override
This function returns true if this constraint is configured and able to decide whether states do meet...
std::string constraint_frame_id_
The constraint frame id.
void clear() override
Clear the stored constraint.
bool configure(const moveit_msgs::msg::PositionConstraint &pc, const moveit::core::Transforms &tf)
Configure the constraint based on a moveit_msgs::msg::PositionConstraint.
std::vector< bodies::BodyPtr > constraint_region_
The constraint region vector.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const override
Decide whether the constraint is satisfied in the indicated state.
bool equal(const KinematicConstraint &other, double margin) const override
Check if two constraints are the same. For position constraints this means that:
const moveit::core::LinkModel * link_model_
The link model constraint subject.
bool has_offset_
Whether the offset is substantially different than 0.0.
Eigen::Vector3d offset_
The target offset.
EigenSTL::vector_Isometry3d constraint_region_pose_
The constraint region pose vector. All isometries are guaranteed to be valid.
bool mobile_frame_
Whether or not a mobile frame is employed.
Class for constraints on the visibility relationship between a sensor and a target.
moveit::core::RobotModelConstPtr robot_model_
A copy of the robot model used to create collision environments to check the cone against robot links...
shapes::Mesh * getVisibilityCone(const Eigen::Isometry3d &tform_world_to_sensor, const Eigen::Isometry3d &tform_world_to_target) const
Gets a trimesh shape representing the visibility cone.
Eigen::Isometry3d target_pose_
The target pose transformed into the transform frame.
void clear() override
Clear the stored constraint.
bool equal(const KinematicConstraint &other, double margin) const override
Check if two constraints are the same.
Eigen::Isometry3d sensor_pose_
The sensor pose transformed into the transform frame.
void print(std::ostream &out=std::cout) const override
Print the constraint data.
bool enabled() const override
This function returns true if this constraint is configured and able to decide whether states do meet...
VisibilityConstraint(const moveit::core::RobotModelConstPtr &model)
Constructor.
std::string target_frame_id_
The target frame id.
double max_range_angle_
Storage for the max range angle.
std::string sensor_frame_id_
The sensor frame id.
double max_view_angle_
Storage for the max view angle.
double target_radius_
Storage for the target radius.
ConstraintEvaluationResult decide(const moveit::core::RobotState &state, bool verbose=false) const override
Decide whether the constraint is satisfied in the indicated state.
void getMarkers(const moveit::core::RobotState &state, visualization_msgs::msg::MarkerArray &markers) const
Adds markers associated with the visibility cone, sensor and target to the visualization array.
bool configure(const moveit_msgs::msg::VisibilityConstraint &vc, const moveit::core::Transforms &tf)
Configure the constraint based on a moveit_msgs::msg::VisibilityConstraint.
EigenSTL::vector_Vector3d points_
A set of points along the base of the circle.
int sensor_view_direction_
Storage for the sensor view direction.
unsigned int cone_sides_
Storage for the cone sides
bool decideContact(const collision_detection::Contact &contact) const
Function that gets passed into collision checking to allow some collisions.
const std::vector< std::string > & getLocalVariableNames() const
Get the local names of the variable that make up the joint (suffixes that are attached to joint names...
Definition: joint_model.h:198
std::size_t getVariableCount() const
Get the number of variables that describe this joint.
Definition: joint_model.h:210
const std::string & getName() const
Get the name of the joint.
Definition: joint_model.h:145
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
JointType getType() const
Get the type of joint.
Definition: joint_model.h:151
const std::string & getName() const
The name of this link.
Definition: link_model.h:86
bool isContinuous() const
Check if this joint wraps around.
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
const Eigen::Isometry3d & getFrameTransform(const std::string &frame_id, bool *frame_found=nullptr)
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
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
Provides an implementation of a snapshot of a transform tree that can be easily queried for transform...
Definition: transforms.h:59
const std::string & getTargetFrame() const
Get the planning frame corresponding to this set of transforms.
Definition: transforms.cpp:73
static bool sameFrame(const std::string &frame1, const std::string &frame2)
Check if two frames end up being the same once the missing / are added as prefix (if they are missing...
Definition: transforms.cpp:64
void transformPose(const std::string &from_frame, const Eigen::Isometry3d &t_in, Eigen::Isometry3d &t_out) const
Transform a pose in from_frame to the target_frame.
Definition: transforms.h:184
void transformQuaternion(const std::string &from_frame, const Eigen::Quaterniond &q_in, Eigen::Quaterniond &q_out) const
Transform a quaternion in from_frame to the target_frame.
Definition: transforms.h:159
virtual bool isFixedFrame(const std::string &frame) const
Check whether a frame stays constant as the state of the robot model changes. This is true for any tr...
Definition: transforms.cpp:92
@ ROBOT_LINK
A link on the robot.
@ ROBOT_ATTACHED
A body attached to a robot link.
@ WORLD_OBJECT
A body in the environment.
std::function< bool(collision_detection::Contact &)> DecideContactFn
Signature of predicate that decides whether a contact is allowed or not (when AllowedCollision::Type ...
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
Representation and evaluation of kinematic constraints.
std::tuple< Eigen::Matrix< typename Eigen::MatrixBase< Derived >::Scalar, 3, 1 >, bool > calcEulerAngles(const Eigen::MatrixBase< Derived > &R)
geometry_msgs::msg::Pose getPose(const moveit::core::RobotState *self, const std::string &link_name)
Definition: robot_state.cpp:80
d
Definition: setup.py:4
name
Definition: setup.py:7
Representation of a collision checking request.
bool verbose
Flag indicating whether information about detected collisions should be reported.
bool contacts
If true, compute contacts. Otherwise only a binary collision yes/no is reported.
std::size_t max_contacts
Overall maximum number of contacts to compute.
Representation of a collision checking result.
ContactMap contacts
A map returning the pairs of body ids in contact, plus their contact details.
void print() const
Throttled warning printing the first collision pair, if any. All collisions are logged at DEBUG level...
bool collision
True if collision was found, false otherwise.
Definition of a contact point.
std::string body_name_2
The id of the second body involved in the contact.
std::string body_name_1
The id of the first body involved in the contact.
BodyType body_type_1
The type of the first body involved in the contact.
BodyType body_type_2
The type of the second body involved in the contact.
Struct for containing the results of constraint evaluation.
bool satisfied
Whether or not the constraint or constraints were satisfied.
double distance
The distance evaluation from the constraint or constraints.