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