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