00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <moveit/kinematic_constraints/kinematic_constraint.h>
00038 #include <geometric_shapes/body_operations.h>
00039 #include <geometric_shapes/shape_operations.h>
00040 #include <moveit/robot_state/conversions.h>
00041 #include <moveit/collision_detection_fcl/collision_robot_fcl.h>
00042 #include <moveit/collision_detection_fcl/collision_world_fcl.h>
00043 #include <boost/scoped_ptr.hpp>
00044 #include <boost/math/constants/constants.hpp>
00045 #include <eigen_conversions/eigen_msg.h>
00046 #include <boost/bind.hpp>
00047 #include <limits>
00048
00049 namespace kinematic_constraints
00050 {
00051 static double normalizeAngle(double angle)
00052 {
00053 double v = fmod(angle, 2.0 * boost::math::constants::pi<double>());
00054 if (v < -boost::math::constants::pi<double>())
00055 v += 2.0 * boost::math::constants::pi<double>();
00056 else
00057 if (v > boost::math::constants::pi<double>())
00058 v -= 2.0 * boost::math::constants::pi<double>();
00059 return v;
00060 }
00061 }
00062
00063 kinematic_constraints::KinematicConstraint::KinematicConstraint(const robot_model::RobotModelConstPtr &model) :
00064 type_(UNKNOWN_CONSTRAINT), robot_model_(model), constraint_weight_(std::numeric_limits<double>::epsilon())
00065 {
00066 }
00067
00068 kinematic_constraints::KinematicConstraint::~KinematicConstraint()
00069 {
00070 }
00071
00072 bool kinematic_constraints::JointConstraint::configure(const moveit_msgs::JointConstraint &jc)
00073 {
00074
00075 clear();
00076
00077
00078 if (jc.tolerance_above < 0.0 || jc.tolerance_below < 0.0)
00079 {
00080 logWarn("JointConstraint tolerance values must be positive.");
00081 joint_model_ = NULL;
00082 return false;
00083 }
00084
00085 joint_variable_name_ = jc.joint_name;
00086 local_variable_name_.clear();
00087 if (robot_model_->hasJointModel(joint_variable_name_))
00088 joint_model_ = robot_model_->getJointModel(joint_variable_name_);
00089 else
00090 {
00091 std::size_t pos = jc.joint_name.find_last_of("/");
00092 if (pos != std::string::npos)
00093 {
00094 joint_model_ = robot_model_->getJointModel(jc.joint_name.substr(0, pos));
00095 if (pos + 1 < jc.joint_name.length())
00096 local_variable_name_ = jc.joint_name.substr(pos + 1);
00097 }
00098 else
00099 joint_model_ = robot_model_->getJointModel(jc.joint_name);
00100 }
00101
00102 if (joint_model_)
00103 {
00104 if (local_variable_name_.empty())
00105 {
00106
00107 if (joint_model_->getVariableCount() == 0)
00108 {
00109 logError("Joint '%s' has no parameters to constrain", jc.joint_name.c_str());
00110 joint_model_ = NULL;
00111 }
00112 else
00113 if (joint_model_->getVariableCount() > 1)
00114 {
00115 logError("Joint '%s' has more than one parameter to constrain. This type of constraint is not supported.", jc.joint_name.c_str());
00116 joint_model_ = NULL;
00117 }
00118 }
00119 else
00120 {
00121 int found = -1;
00122 const std::vector<std::string> &local_var_names = joint_model_->getLocalVariableNames();
00123 for (std::size_t i = 0 ; i < local_var_names.size() ; ++i)
00124 if (local_var_names[i] == local_variable_name_)
00125 {
00126 found = i;
00127 break;
00128 }
00129 if (found < 0)
00130 {
00131 logError("Local variable name '%s' is not known to joint '%s'", local_variable_name_.c_str(), joint_model_->getName().c_str());
00132 joint_model_ = NULL;
00133 }
00134 }
00135 }
00136
00137
00138 if (joint_model_)
00139 {
00140 joint_is_continuous_ = false;
00141 joint_tolerance_above_ = jc.tolerance_above;
00142 joint_tolerance_below_ = jc.tolerance_below;
00143
00144
00145 joint_is_continuous_ = false;
00146 if (joint_model_->getType() == robot_model::JointModel::REVOLUTE)
00147 {
00148 const robot_model::RevoluteJointModel *rjoint = static_cast<const robot_model::RevoluteJointModel*>(joint_model_);
00149 if (rjoint->isContinuous())
00150 joint_is_continuous_ = true;
00151 }
00152 else
00153 if (joint_model_->getType() == robot_model::JointModel::PLANAR)
00154 {
00155 if (local_variable_name_ == "theta")
00156 joint_is_continuous_ = true;
00157 }
00158
00159 if (joint_is_continuous_)
00160 {
00161 joint_position_ = normalizeAngle(jc.position);
00162 }
00163 else
00164 {
00165 joint_position_ = jc.position;
00166
00167 std::pair<double, double> bounds;
00168 joint_model_->getVariableBounds(joint_variable_name_, bounds);
00169
00170 if (bounds.first > joint_position_ + joint_tolerance_above_)
00171 {
00172 joint_position_ = bounds.first;
00173 joint_tolerance_above_ = std::numeric_limits<double>::epsilon();
00174 logWarn("Joint %s is constrained to be below the minimum bounds. Assuming minimum bounds instead.", jc.joint_name.c_str());
00175 }
00176 else
00177 if (bounds.second < joint_position_ - joint_tolerance_below_)
00178 {
00179 joint_position_ = bounds.second;
00180 joint_tolerance_below_ = std::numeric_limits<double>::epsilon();
00181 logWarn("Joint %s is constrained to be above the maximum bounds. Assuming maximum bounds instead.", jc.joint_name.c_str());
00182 }
00183 }
00184
00185 if (jc.weight <= std::numeric_limits<double>::epsilon())
00186 {
00187 logWarn("The weight on constraint for joint '%s' is very near zero. Setting to 1.0.", jc.joint_name.c_str());
00188 constraint_weight_ = 1.0;
00189 }
00190 else
00191 constraint_weight_ = jc.weight;
00192 }
00193 return joint_model_ != NULL;
00194 }
00195
00196 bool kinematic_constraints::JointConstraint::equal(const KinematicConstraint &other, double margin) const
00197 {
00198 if (other.getType() != type_)
00199 return false;
00200 const JointConstraint &o = static_cast<const JointConstraint&>(other);
00201 if (o.joint_model_ == joint_model_ && o.local_variable_name_ == local_variable_name_)
00202 return fabs(joint_position_ - o.joint_position_) <= margin &&
00203 fabs(joint_tolerance_above_ - o.joint_tolerance_above_) <= margin &&
00204 fabs(joint_tolerance_below_ - o.joint_tolerance_below_) <= margin;
00205 return false;
00206 }
00207
00208 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::JointConstraint::decide(const robot_state::RobotState &state, bool verbose) const
00209 {
00210 if (!joint_model_)
00211 return ConstraintEvaluationResult(true, 0.0);
00212
00213 const robot_state::JointState *joint = state.getJointState(joint_model_->getName());
00214
00215 if (!joint)
00216 {
00217 logWarn("No joint in state with name '%s'", joint_model_->getName().c_str());
00218 return ConstraintEvaluationResult(true, 0.0);
00219 }
00220
00221 double current_joint_position = joint->getVariableValues()[0];
00222 if (!local_variable_name_.empty())
00223 {
00224 const std::map<std::string, unsigned int> &index_map = joint->getVariableIndexMap();
00225 std::map<std::string, unsigned int>::const_iterator it = index_map.find(joint_variable_name_);
00226 if (it == index_map.end())
00227 {
00228 logWarn("Local name '%s' is not known to joint state with name '%s'", local_variable_name_.c_str(), joint_model_->getName().c_str());
00229 return ConstraintEvaluationResult(true, 0.0);
00230 }
00231 else
00232 current_joint_position = joint->getVariableValues()[it->second];
00233 }
00234
00235 double dif = 0.0;
00236
00237
00238 if (joint_is_continuous_)
00239 {
00240 dif = normalizeAngle(current_joint_position) - joint_position_;
00241
00242 if (dif > boost::math::constants::pi<double>())
00243 dif = 2.0*boost::math::constants::pi<double>() - dif;
00244 else
00245 if (dif < -boost::math::constants::pi<double>())
00246 dif += 2.0*boost::math::constants::pi<double>();
00247 }
00248 else
00249 dif = current_joint_position - joint_position_;
00250
00251
00252 bool result = dif <= (joint_tolerance_above_+2*std::numeric_limits<double>::epsilon()) && dif >= (-joint_tolerance_below_-2*std::numeric_limits<double>::epsilon());
00253 if (verbose)
00254 logInform("Constraint %s:: Joint name: '%s', actual value: %f, desired value: %f, tolerance_above: %f, tolerance_below: %f",
00255 result ? "satisfied" : "violated", joint_variable_name_.c_str(),
00256 current_joint_position, joint_position_, joint_tolerance_above_, joint_tolerance_below_);
00257 return ConstraintEvaluationResult(result, constraint_weight_ * fabs(dif));
00258 }
00259
00260 bool kinematic_constraints::JointConstraint::enabled() const
00261 {
00262 return joint_model_;
00263 }
00264
00265 void kinematic_constraints::JointConstraint::clear()
00266 {
00267 joint_model_ = NULL;
00268 joint_is_continuous_ = false;
00269 local_variable_name_ = "";
00270 joint_variable_name_ = "";
00271 joint_position_ = joint_tolerance_below_ = joint_tolerance_above_ = 0.0;
00272 }
00273
00274 void kinematic_constraints::JointConstraint::print(std::ostream &out) const
00275 {
00276 if (joint_model_)
00277 {
00278 out << "Joint constraint for joint " << joint_variable_name_ << ": " << std::endl;
00279 out << " value = ";
00280 out << joint_position_ << "; ";
00281 out << " tolerance below = ";
00282 out << joint_tolerance_below_ << "; ";
00283 out << " tolerance above = ";
00284 out << joint_tolerance_above_ << "; ";
00285 out << std::endl;
00286 }
00287 else
00288 out << "No constraint" << std::endl;
00289 }
00290
00291 bool kinematic_constraints::PositionConstraint::configure(const moveit_msgs::PositionConstraint &pc, const robot_state::Transforms &tf)
00292 {
00293
00294 clear();
00295
00296 link_model_ = robot_model_->getLinkModel(pc.link_name);
00297 if (link_model_ == NULL)
00298 {
00299 logWarn("Position constraint link model %s not found in kinematic model. Constraint invalid.", pc.link_name.c_str());
00300 return false;
00301 }
00302
00303 if (pc.header.frame_id.empty())
00304 {
00305 logWarn("No frame specified for position constraint on link '%s'!", pc.link_name.c_str());
00306 return false;
00307 }
00308
00309 offset_ = Eigen::Vector3d(pc.target_point_offset.x, pc.target_point_offset.y, pc.target_point_offset.z);
00310 has_offset_ = offset_.squaredNorm() > std::numeric_limits<double>::epsilon();
00311
00312 if (tf.isFixedFrame(pc.header.frame_id))
00313 {
00314 constraint_frame_id_ = tf.getTargetFrame();
00315 mobile_frame_ = false;
00316 }
00317 else
00318 {
00319 constraint_frame_id_ = pc.header.frame_id;
00320 mobile_frame_ = true;
00321 }
00322
00323
00324 for (std::size_t i = 0 ; i < pc.constraint_region.primitives.size() ; ++i)
00325 {
00326 boost::scoped_ptr<shapes::Shape> shape(shapes::constructShapeFromMsg(pc.constraint_region.primitives[i]));
00327 if (shape)
00328 {
00329 if (pc.constraint_region.primitive_poses.size() <= i)
00330 {
00331 logWarn("Constraint region message does not contain enough primitive poses");
00332 continue;
00333 }
00334 constraint_region_.push_back(bodies::BodyPtr(bodies::createBodyFromShape(shape.get())));
00335 Eigen::Affine3d t;
00336 tf::poseMsgToEigen(pc.constraint_region.primitive_poses[i], t);
00337 constraint_region_pose_.push_back(t);
00338 if (mobile_frame_)
00339 constraint_region_.back()->setPose(constraint_region_pose_.back());
00340 else
00341 {
00342 tf.transformPose(pc.header.frame_id, constraint_region_pose_.back(), constraint_region_pose_.back());
00343 constraint_region_.back()->setPose(constraint_region_pose_.back());
00344 }
00345 }
00346 else
00347 logWarn("Could not construct primitive shape %d", i);
00348 }
00349
00350
00351 for (std::size_t i = 0 ; i < pc.constraint_region.meshes.size() ; ++i)
00352 {
00353 boost::scoped_ptr<shapes::Shape> shape(shapes::constructShapeFromMsg(pc.constraint_region.meshes[i]));
00354 if (shape)
00355 {
00356 if (pc.constraint_region.mesh_poses.size() <= i)
00357 {
00358 logWarn("Constraint region message does not contain enough primitive poses");
00359 continue;
00360 }
00361 constraint_region_.push_back(bodies::BodyPtr(bodies::createBodyFromShape(shape.get())));
00362 Eigen::Affine3d t;
00363 tf::poseMsgToEigen(pc.constraint_region.mesh_poses[i], t);
00364 constraint_region_pose_.push_back(t);
00365 if (mobile_frame_)
00366 constraint_region_.back()->setPose(constraint_region_pose_.back());
00367 else
00368 {
00369 tf.transformPose(pc.header.frame_id, constraint_region_pose_.back(), constraint_region_pose_.back());
00370 constraint_region_.back()->setPose(constraint_region_pose_.back());
00371 }
00372 }
00373 else
00374 {
00375 logWarn("Could not construct mesh shape %d",i);
00376 }
00377 }
00378
00379 if (pc.weight <= std::numeric_limits<double>::epsilon())
00380 {
00381 logWarn("The weight on position constraint for link '%s' is near zero. Setting to 1.0.", pc.link_name.c_str());
00382 constraint_weight_ = 1.0;
00383 }
00384 else
00385 constraint_weight_ = pc.weight;
00386
00387 return !constraint_region_.empty();
00388 }
00389
00390 bool kinematic_constraints::PositionConstraint::equal(const KinematicConstraint &other, double margin) const
00391 {
00392 if (other.getType() != type_)
00393 return false;
00394 const PositionConstraint &o = static_cast<const PositionConstraint&>(other);
00395
00396 if (link_model_ == o.link_model_ && robot_state::Transforms::sameFrame(constraint_frame_id_, o.constraint_frame_id_))
00397 {
00398 if ((offset_ - o.offset_).norm() > margin)
00399 return false;
00400 std::vector<bool> other_region_matches_this(constraint_region_.size(), false);
00401 for (std::size_t i = 0 ; i < constraint_region_.size() ; ++i)
00402 {
00403 bool some_match = false;
00404
00405 for(std::size_t j = 0 ; j < o.constraint_region_.size() ; ++j)
00406 {
00407 Eigen::Affine3d diff = constraint_region_pose_[i].inverse() * o.constraint_region_pose_[j];
00408 if (diff.translation().norm() < margin
00409 && diff.rotation().isIdentity(margin)
00410 && constraint_region_[i]->getType() == o.constraint_region_[j]->getType()
00411 && fabs(constraint_region_[i]->computeVolume() - o.constraint_region_[j]->computeVolume()) < margin)
00412 {
00413 some_match = true;
00414
00415 other_region_matches_this[j] = true;
00416 }
00417 }
00418 if (!some_match)
00419 return false;
00420 }
00421 for (std::size_t i = 0 ; i < o.constraint_region_.size() ; ++i)
00422 if (!other_region_matches_this[i])
00423 return false;
00424 return true;
00425 }
00426 return false;
00427 }
00428
00429 namespace kinematic_constraints
00430 {
00431
00432 static inline
00433 kinematic_constraints::ConstraintEvaluationResult finishPositionConstraintDecision(const Eigen::Vector3d &pt, const Eigen::Vector3d &desired, const std::string &name,
00434 double weight, bool result, bool verbose)
00435 {
00436 double dx = desired.x() - pt.x();
00437 double dy = desired.y() - pt.y();
00438 double dz = desired.z() - pt.z();
00439 if (verbose)
00440 {
00441 logInform("Position constraint %s on link '%s'. Desired: %f, %f, %f, current: %f, %f, %f",
00442 result ? "satisfied" : "violated", name.c_str(), desired.x(), desired.y(), desired.z(), pt.x(), pt.y(), pt.z());
00443 logInform("Differences %g %g %g",dx,dy, dz);
00444 }
00445 return ConstraintEvaluationResult(result, weight * sqrt(dx * dx + dy * dy + dz * dz));
00446 }
00447 }
00448
00449 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::PositionConstraint::decide(const robot_state::RobotState &state, bool verbose) const
00450 {
00451 if (!link_model_ || constraint_region_.empty())
00452 return ConstraintEvaluationResult(true, 0.0);
00453
00454 const robot_state::LinkState *link_state = state.getLinkState(link_model_->getName());
00455
00456 if (!link_state)
00457 {
00458 logWarn("No link in state with name '%s'", link_model_->getName().c_str());
00459 return ConstraintEvaluationResult(false, 0.0);
00460 }
00461
00462 Eigen::Vector3d pt = link_state->getGlobalLinkTransform() * offset_;
00463 if (mobile_frame_)
00464 {
00465 for (std::size_t i = 0 ; i < constraint_region_.size() ; ++i)
00466 {
00467 Eigen::Affine3d tmp = state.getFrameTransform(constraint_frame_id_) * constraint_region_pose_[i];
00468 bool result = constraint_region_[i]->cloneAt(tmp)->containsPoint(pt, verbose);
00469 if (result || (i + 1 == constraint_region_pose_.size()))
00470 return finishPositionConstraintDecision(pt, tmp.translation(), link_model_->getName(), constraint_weight_, result, verbose);
00471 else
00472 finishPositionConstraintDecision(pt, tmp.translation(), link_model_->getName(), constraint_weight_, result, verbose);
00473 }
00474 }
00475 else
00476 {
00477 for (std::size_t i = 0 ; i < constraint_region_.size() ; ++i)
00478 {
00479 bool result = constraint_region_[i]->containsPoint(pt, true);
00480 if (result || (i + 1 == constraint_region_.size()))
00481 return finishPositionConstraintDecision(pt, constraint_region_[i]->getPose().translation(), link_model_->getName(), constraint_weight_, result, verbose);
00482 else
00483 finishPositionConstraintDecision(pt, constraint_region_[i]->getPose().translation(), link_model_->getName(), constraint_weight_, result, verbose);
00484 }
00485 }
00486 return ConstraintEvaluationResult(false, 0.0);
00487 }
00488
00489 void kinematic_constraints::PositionConstraint::print(std::ostream &out) const
00490 {
00491 if (enabled())
00492 out << "Position constraint on link '" << link_model_->getName() << "'" << std::endl;
00493 else
00494 out << "No constraint" << std::endl;
00495 }
00496
00497 void kinematic_constraints::PositionConstraint::clear()
00498 {
00499 offset_ = Eigen::Vector3d(0.0,0.0,0.0);
00500 has_offset_ = false;
00501 constraint_region_.clear();
00502 constraint_region_pose_.clear();
00503 mobile_frame_ = false;
00504 constraint_frame_id_ = "";
00505 link_model_ = NULL;
00506 }
00507
00508 bool kinematic_constraints::PositionConstraint::enabled() const
00509 {
00510 return link_model_ && !constraint_region_.empty();
00511 }
00512
00513 bool kinematic_constraints::OrientationConstraint::configure(const moveit_msgs::OrientationConstraint &oc, const robot_state::Transforms &tf)
00514 {
00515
00516 clear();
00517
00518 link_model_ = robot_model_->getLinkModel(oc.link_name);
00519 if(!link_model_)
00520 {
00521 logWarn("Could not find link model for link name %s", oc.link_name.c_str());
00522 return false;
00523 }
00524 Eigen::Quaterniond q;
00525 tf::quaternionMsgToEigen(oc.orientation, q);
00526 if (fabs(q.norm() - 1.0) > 1e-3)
00527 {
00528 logWarn("Orientation constraint for link '%s' is probably incorrect: %f, %f, %f, %f. Assuming identity instead.", oc.link_name.c_str(),
00529 oc.orientation.x, oc.orientation.y, oc.orientation.z, oc.orientation.w);
00530 q = Eigen::Quaterniond(1.0, 0.0, 0.0, 0.0);
00531 }
00532
00533 if (oc.header.frame_id.empty())
00534 logWarn("No frame specified for position constraint on link '%s'!", oc.link_name.c_str());
00535
00536 if (tf.isFixedFrame(oc.header.frame_id))
00537 {
00538 tf.transformQuaternion(oc.header.frame_id, q, q);
00539 desired_rotation_frame_id_ = tf.getTargetFrame();
00540 desired_rotation_matrix_ = Eigen::Matrix3d(q);
00541 desired_rotation_matrix_inv_ = desired_rotation_matrix_.inverse();
00542 mobile_frame_ = false;
00543 }
00544 else
00545 {
00546 desired_rotation_frame_id_ = oc.header.frame_id;
00547 desired_rotation_matrix_ = Eigen::Matrix3d(q);
00548 mobile_frame_ = true;
00549 }
00550 std::stringstream matrix_str;
00551 matrix_str << desired_rotation_matrix_;
00552 logDebug("The desired rotation matrix for link '%s' in frame %s is:\n%s", oc.link_name.c_str(), desired_rotation_frame_id_.c_str(), matrix_str.str().c_str());
00553
00554 if (oc.weight <= std::numeric_limits<double>::epsilon())
00555 {
00556 logWarn("The weight on position constraint for link '%s' is near zero. Setting to 1.0.", oc.link_name.c_str());
00557 constraint_weight_ = 1.0;
00558 }
00559 else
00560 constraint_weight_ = oc.weight;
00561 absolute_x_axis_tolerance_ = fabs(oc.absolute_x_axis_tolerance);
00562 if (absolute_x_axis_tolerance_ < std::numeric_limits<double>::epsilon())
00563 logWarn("Near-zero value for absolute_x_axis_tolerance");
00564 absolute_y_axis_tolerance_ = fabs(oc.absolute_y_axis_tolerance);
00565 if (absolute_y_axis_tolerance_ < std::numeric_limits<double>::epsilon())
00566 logWarn("Near-zero value for absolute_y_axis_tolerance");
00567 absolute_z_axis_tolerance_ = fabs(oc.absolute_z_axis_tolerance);
00568 if (absolute_z_axis_tolerance_ < std::numeric_limits<double>::epsilon())
00569 logWarn("Near-zero value for absolute_z_axis_tolerance");
00570
00571 return link_model_ != NULL;
00572 }
00573
00574 bool kinematic_constraints::OrientationConstraint::equal(const KinematicConstraint &other, double margin) const
00575 {
00576 if (other.getType() != type_)
00577 return false;
00578 const OrientationConstraint &o = static_cast<const OrientationConstraint&>(other);
00579
00580 if (o.link_model_ == link_model_ && robot_state::Transforms::sameFrame(desired_rotation_frame_id_, o.desired_rotation_frame_id_))
00581 {
00582 Eigen::Matrix3d diff = desired_rotation_matrix_.inverse() * o.desired_rotation_matrix_;
00583 if (!diff.isIdentity(margin))
00584 return false;
00585 return fabs(absolute_x_axis_tolerance_ - o.absolute_x_axis_tolerance_) <= margin &&
00586 fabs(absolute_y_axis_tolerance_ - o.absolute_y_axis_tolerance_) <= margin &&
00587 fabs(absolute_z_axis_tolerance_ - o.absolute_z_axis_tolerance_) <= margin;
00588 }
00589 return false;
00590 }
00591
00592 void kinematic_constraints::OrientationConstraint::clear()
00593 {
00594 link_model_ = NULL;
00595 desired_rotation_matrix_ = Eigen::Matrix3d::Identity();
00596 desired_rotation_matrix_inv_ = Eigen::Matrix3d::Identity();
00597 desired_rotation_frame_id_ = "";
00598 mobile_frame_ = false;
00599 absolute_z_axis_tolerance_ = absolute_y_axis_tolerance_ = absolute_x_axis_tolerance_ = 0.0;
00600 }
00601
00602 bool kinematic_constraints::OrientationConstraint::enabled() const
00603 {
00604 return link_model_;
00605 }
00606
00607 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::OrientationConstraint::decide(const robot_state::RobotState &state, bool verbose) const
00608 {
00609 if (!link_model_)
00610 return ConstraintEvaluationResult(true, 0.0);
00611
00612 const robot_state::LinkState *link_state = state.getLinkState(link_model_->getName());
00613
00614 if (!link_state)
00615 {
00616 logWarn("No link in state with name '%s'", link_model_->getName().c_str());
00617 return ConstraintEvaluationResult(false, 0.0);
00618 }
00619
00620 Eigen::Vector3d xyz;
00621 if (mobile_frame_)
00622 {
00623 Eigen::Matrix3d tmp = state.getFrameTransform(desired_rotation_frame_id_).rotation() * desired_rotation_matrix_;
00624 Eigen::Affine3d diff(tmp.inverse() * link_state->getGlobalLinkTransform().rotation());
00625 xyz = diff.rotation().eulerAngles(0, 1, 2);
00626
00627 }
00628 else
00629 {
00630 Eigen::Affine3d diff(desired_rotation_matrix_inv_ * link_state->getGlobalLinkTransform().rotation());
00631 xyz = diff.rotation().eulerAngles(0, 1, 2);
00632 }
00633
00634 xyz(0) = std::min(fabs(xyz(0)), boost::math::constants::pi<double>() - fabs(xyz(0)));
00635 xyz(1) = std::min(fabs(xyz(1)), boost::math::constants::pi<double>() - fabs(xyz(1)));
00636 xyz(2) = std::min(fabs(xyz(2)), boost::math::constants::pi<double>() - fabs(xyz(2)));
00637 bool result = xyz(2) < absolute_z_axis_tolerance_+std::numeric_limits<double>::epsilon()
00638 && xyz(1) < absolute_y_axis_tolerance_+std::numeric_limits<double>::epsilon()
00639 && xyz(0) < absolute_x_axis_tolerance_+std::numeric_limits<double>::epsilon();
00640
00641 if (verbose)
00642 {
00643 Eigen::Quaterniond q_act(link_state->getGlobalLinkTransform().rotation());
00644 Eigen::Quaterniond q_des(desired_rotation_matrix_);
00645 logInform("Orientation constraint %s for link '%s'. Quaternion desired: %f %f %f %f, quaternion actual: %f %f %f %f, error: x=%f, y=%f, z=%f, tolerance: x=%f, y=%f, z=%f",
00646 result ? "satisfied" : "violated", link_model_->getName().c_str(),
00647 q_des.x(), q_des.y(), q_des.z(), q_des.w(),
00648 q_act.x(), q_act.y(), q_act.z(), q_act.w(), xyz(0), xyz(1), xyz(2),
00649 absolute_x_axis_tolerance_, absolute_y_axis_tolerance_, absolute_z_axis_tolerance_);
00650 }
00651
00652 return ConstraintEvaluationResult(result, constraint_weight_ * (xyz(0) + xyz(1) + xyz(2)));
00653 }
00654
00655 void kinematic_constraints::OrientationConstraint::print(std::ostream &out) const
00656 {
00657 if (link_model_)
00658 {
00659 out << "Orientation constraint on link '" << link_model_->getName() << "'" << std::endl;
00660 Eigen::Quaterniond q_des(desired_rotation_matrix_);
00661 out << "Desired orientation:" << q_des.x() << "," << q_des.y() << "," << q_des.z() << "," << q_des.w() << std::endl;
00662 }
00663 else
00664 out << "No constraint" << std::endl;
00665 }
00666
00667 kinematic_constraints::VisibilityConstraint::VisibilityConstraint(const robot_model::RobotModelConstPtr &model) :
00668 KinematicConstraint(model), collision_robot_(new collision_detection::CollisionRobotFCL(model))
00669 {
00670 type_ = VISIBILITY_CONSTRAINT;
00671 }
00672
00673 void kinematic_constraints::VisibilityConstraint::clear()
00674 {
00675 mobile_sensor_frame_ = false;
00676 mobile_target_frame_ = false;
00677 target_frame_id_ = "";
00678 sensor_frame_id_ = "";
00679 sensor_pose_ = Eigen::Affine3d::Identity();
00680 sensor_view_direction_ = 0;
00681 target_pose_ = Eigen::Affine3d::Identity();
00682 cone_sides_ = 0;
00683 points_.clear();
00684 target_radius_ = -1.0;
00685 max_view_angle_ = 0.0;
00686 max_range_angle_ = 0.0;
00687 }
00688
00689 bool kinematic_constraints::VisibilityConstraint::configure(const moveit_msgs::VisibilityConstraint &vc, const robot_state::Transforms &tf)
00690 {
00691 clear();
00692 target_radius_ = fabs(vc.target_radius);
00693
00694 if (vc.target_radius <= std::numeric_limits<double>::epsilon())
00695 logWarn("The radius of the target disc that must be visible should be strictly positive");
00696
00697 if (vc.cone_sides < 3)
00698 {
00699 logWarn("The number of sides for the visibility region must be 3 or more. Assuming 3 sides instead of the specified %d", vc.cone_sides);
00700 cone_sides_ = 3;
00701 }
00702 else
00703 cone_sides_ = vc.cone_sides;
00704
00705
00706 points_.clear();
00707 double delta = 2.0 * boost::math::constants::pi<double>() / (double)cone_sides_;
00708 double a = 0.0;
00709 for (unsigned int i = 0 ; i < cone_sides_ ; ++i, a += delta)
00710 {
00711 double x = sin(a) * target_radius_;
00712 double y = cos(a) * target_radius_;
00713 points_.push_back(Eigen::Vector3d(x, y, 0.0));
00714 }
00715
00716 tf::poseMsgToEigen(vc.target_pose.pose, target_pose_);
00717
00718 if (tf.isFixedFrame(vc.target_pose.header.frame_id))
00719 {
00720 tf.transformPose(vc.target_pose.header.frame_id, target_pose_, target_pose_);
00721 target_frame_id_ = tf.getTargetFrame();
00722 mobile_target_frame_ = false;
00723
00724 for (std::size_t i = 0 ; i < points_.size() ; ++i)
00725 points_[i] = target_pose_*points_[i];
00726 }
00727 else
00728 {
00729 target_frame_id_ = vc.target_pose.header.frame_id;
00730 mobile_target_frame_ = true;
00731 }
00732
00733 tf::poseMsgToEigen(vc.sensor_pose.pose, sensor_pose_);
00734
00735 if (tf.isFixedFrame(vc.sensor_pose.header.frame_id))
00736 {
00737 tf.transformPose(vc.sensor_pose.header.frame_id, sensor_pose_, sensor_pose_);
00738 sensor_frame_id_ = tf.getTargetFrame();
00739 mobile_sensor_frame_ = false;
00740 }
00741 else
00742 {
00743 sensor_frame_id_ = vc.sensor_pose.header.frame_id;
00744 mobile_sensor_frame_ = true;
00745 }
00746
00747 if (vc.weight <= std::numeric_limits<double>::epsilon())
00748 {
00749 logWarn("The weight of visibility constraint is near zero. Setting to 1.0.");
00750 constraint_weight_ = 1.0;
00751 }
00752 else
00753 constraint_weight_ = vc.weight;
00754
00755 max_view_angle_ = vc.max_view_angle;
00756 max_range_angle_ = vc.max_range_angle;
00757 sensor_view_direction_ = vc.sensor_view_direction;
00758
00759 return target_radius_ > std::numeric_limits<double>::epsilon();
00760 }
00761
00762 bool kinematic_constraints::VisibilityConstraint::equal(const KinematicConstraint &other, double margin) const
00763 {
00764 if (other.getType() != type_)
00765 return false;
00766 const VisibilityConstraint &o = static_cast<const VisibilityConstraint&>(other);
00767
00768 if (robot_state::Transforms::sameFrame(target_frame_id_, o.target_frame_id_) &&
00769 robot_state::Transforms::sameFrame(sensor_frame_id_, o.sensor_frame_id_) &&
00770 cone_sides_ == o.cone_sides_ && sensor_view_direction_ == o.sensor_view_direction_)
00771 {
00772 if (fabs(max_view_angle_ - o.max_view_angle_) > margin ||
00773 fabs(target_radius_ - o.target_radius_) > margin)
00774 return false;
00775 Eigen::Affine3d diff = sensor_pose_.inverse() * o.sensor_pose_;
00776 if (diff.translation().norm() > margin)
00777 return false;
00778 if (!diff.rotation().isIdentity(margin))
00779 return false;
00780 diff = target_pose_.inverse() * o.target_pose_;
00781 if (diff.translation().norm() > margin)
00782 return false;
00783 if (!diff.rotation().isIdentity(margin))
00784 return false;
00785 return true;
00786 }
00787 return false;
00788 }
00789
00790 bool kinematic_constraints::VisibilityConstraint::enabled() const
00791 {
00792 return target_radius_ > std::numeric_limits<double>::epsilon();
00793 }
00794
00795 shapes::Mesh* kinematic_constraints::VisibilityConstraint::getVisibilityCone(const robot_state::RobotState &state) const
00796 {
00797
00798
00799 const Eigen::Affine3d &sp = mobile_sensor_frame_ ? state.getFrameTransform(sensor_frame_id_) * sensor_pose_ : sensor_pose_;
00800 const Eigen::Affine3d &tp = mobile_target_frame_ ? state.getFrameTransform(target_frame_id_) * target_pose_ : target_pose_;
00801
00802
00803 const EigenSTL::vector_Vector3d *points = &points_;
00804 boost::scoped_ptr<EigenSTL::vector_Vector3d> tempPoints;
00805 if (mobile_target_frame_)
00806 {
00807 tempPoints.reset(new EigenSTL::vector_Vector3d(points_.size()));
00808 for (std::size_t i = 0 ; i < points_.size() ; ++i)
00809 tempPoints->at(i) = tp*points_[i];
00810 points = tempPoints.get();
00811 }
00812
00813
00814 shapes::Mesh *m = new shapes::Mesh();
00815 m->vertex_count = cone_sides_ + 2;
00816 m->vertices = new double[m->vertex_count * 3];
00817 m->triangle_count = cone_sides_ * 2;
00818 m->triangles = new unsigned int[m->triangle_count * 3];
00819
00820
00821
00822 m->vertices[0] = sp.translation().x();
00823 m->vertices[1] = sp.translation().y();
00824 m->vertices[2] = sp.translation().z();
00825
00826
00827 m->vertices[3] = tp.translation().x();
00828 m->vertices[4] = tp.translation().y();
00829 m->vertices[5] = tp.translation().z();
00830
00831
00832 for (std::size_t i = 0 ; i < points->size() ; ++i)
00833 {
00834 m->vertices[i*3 + 6] = points->at(i).x();
00835 m->vertices[i*3 + 7] = points->at(i).y();
00836 m->vertices[i*3 + 8] = points->at(i).z();
00837 }
00838
00839
00840 std::size_t p3 = points->size() * 3;
00841 for (std::size_t i = 1 ; i < points->size() ; ++i)
00842 {
00843
00844 std::size_t i3 = (i - 1) * 3;
00845 m->triangles[i3] = i + 1;
00846 m->triangles[i3 + 1] = 0;
00847 m->triangles[i3 + 2] = i + 2;
00848
00849 std::size_t i6 = p3 + i3;
00850 m->triangles[i6] = i + 1;
00851 m->triangles[i6 + 1] = 1;
00852 m->triangles[i6 + 2] = i + 2;
00853 }
00854
00855
00856 m->triangles[p3 - 3] = points->size() + 1;
00857 m->triangles[p3 - 2] = 0;
00858 m->triangles[p3 - 1] = 2;
00859 p3 *= 2;
00860 m->triangles[p3 - 3] = points->size() + 1;
00861 m->triangles[p3 - 2] = 1;
00862 m->triangles[p3 - 1] = 2;
00863
00864 return m;
00865 }
00866
00867 void kinematic_constraints::VisibilityConstraint::getMarkers(const robot_state::RobotState &state, visualization_msgs::MarkerArray &markers) const
00868 {
00869 shapes::Mesh *m = getVisibilityCone(state);
00870 visualization_msgs::Marker mk;
00871 shapes::constructMarkerFromShape(m, mk);
00872 delete m;
00873 mk.header.frame_id = robot_model_->getModelFrame();
00874 mk.header.stamp = ros::Time::now();
00875 mk.ns = "constraints";
00876 mk.id = 1;
00877 mk.action = visualization_msgs::Marker::ADD;
00878 mk.pose.position.x = 0;
00879 mk.pose.position.y = 0;
00880 mk.pose.position.z = 0;
00881 mk.pose.orientation.x = 0;
00882 mk.pose.orientation.y = 0;
00883 mk.pose.orientation.z = 0;
00884 mk.pose.orientation.w = 1;
00885 mk.lifetime = ros::Duration(60);
00886
00887 mk.scale.x = .01;
00888 mk.color.a = 1.0;
00889 mk.color.r = 1.0;
00890 mk.color.g = 0.0;
00891 mk.color.b = 0.0;
00892
00893 markers.markers.push_back(mk);
00894
00895 const Eigen::Affine3d &sp = mobile_sensor_frame_ ? state.getFrameTransform(sensor_frame_id_) * sensor_pose_ : sensor_pose_;
00896 const Eigen::Affine3d &tp = mobile_target_frame_ ? state.getFrameTransform(target_frame_id_) * target_pose_ : target_pose_;
00897
00898 visualization_msgs::Marker mka;
00899 mka.type = visualization_msgs::Marker::ARROW;
00900 mka.action = visualization_msgs::Marker::ADD;
00901 mka.color = mk.color;
00902 mka.pose = mk.pose;
00903
00904 mka.header = mk.header;
00905 mka.ns = mk.ns;
00906 mka.id = 2;
00907 mka.lifetime = mk.lifetime;
00908 mka.scale.x = 0.05;
00909 mka.scale.y = .15;
00910 mka.scale.z = 0.0;
00911 mka.points.resize(2);
00912 Eigen::Vector3d d = tp.translation() + tp.rotation().col(2) * 0.5;
00913 mka.points[0].x = tp.translation().x();
00914 mka.points[0].y = tp.translation().y();
00915 mka.points[0].z = tp.translation().z();
00916 mka.points[1].x = d.x();
00917 mka.points[1].y = d.y();
00918 mka.points[1].z = d.z();
00919 markers.markers.push_back(mka);
00920
00921 mka.id = 3;
00922 mka.color.b = 1.0;
00923 mka.color.r = 0.0;
00924
00925 d = sp.translation() + sp.rotation().col(2-sensor_view_direction_) * 0.5;
00926 mka.points[0].x = sp.translation().x();
00927 mka.points[0].y = sp.translation().y();
00928 mka.points[0].z = sp.translation().z();
00929 mka.points[1].x = d.x();
00930 mka.points[1].y = d.y();
00931 mka.points[1].z = d.z();
00932
00933 markers.markers.push_back(mka);
00934 }
00935
00936 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::VisibilityConstraint::decide(const robot_state::RobotState &state, bool verbose) const
00937 {
00938 if (target_radius_ <= std::numeric_limits<double>::epsilon())
00939 return ConstraintEvaluationResult(true, 0.0);
00940
00941 if (max_view_angle_ > 0.0 || max_range_angle_ > 0.0)
00942 {
00943 const Eigen::Affine3d &sp = mobile_sensor_frame_ ? state.getFrameTransform(sensor_frame_id_) * sensor_pose_ : sensor_pose_;
00944 const Eigen::Affine3d &tp = mobile_target_frame_ ? state.getFrameTransform(target_frame_id_) * target_pose_ : target_pose_;
00945
00946
00947 const Eigen::Vector3d &normal2 = sp.rotation().col(2-sensor_view_direction_);
00948
00949 if (max_view_angle_ > 0.0)
00950 {
00951 const Eigen::Vector3d &normal1 = tp.rotation().col(2)*-1.0;
00952 double dp = normal2.dot(normal1);
00953 double ang = acos(dp);
00954 if (dp < 0.0)
00955 {
00956 if (verbose)
00957 logInform("Visibility constraint is violated because the sensor is looking at the wrong side");
00958 return ConstraintEvaluationResult(false, 0.0);
00959 }
00960 if (max_view_angle_ < ang)
00961 {
00962 if (verbose)
00963 logInform("Visibility constraint is violated because the view angle is %lf (above the maximum allowed of %lf)", ang, max_view_angle_);
00964 return ConstraintEvaluationResult(false, 0.0);
00965 }
00966 }
00967 if (max_range_angle_ > 0.0)
00968 {
00969 const Eigen::Vector3d &dir = (tp.translation() - sp.translation()).normalized();
00970 double dp = normal2.dot(dir);
00971 if (dp < 0.0)
00972 {
00973 if (verbose)
00974 logInform("Visibility constraint is violated because the sensor is looking at the wrong side");
00975 return ConstraintEvaluationResult(false, 0.0);
00976 }
00977
00978 double ang = acos(dp);
00979 if (max_range_angle_ < ang)
00980 {
00981 if (verbose)
00982 logInform("Visibility constraint is violated because the range angle is %lf (above the maximum allowed of %lf)", ang, max_range_angle_);
00983 return ConstraintEvaluationResult(false, 0.0);
00984 }
00985 }
00986 }
00987
00988 shapes::Mesh *m = getVisibilityCone(state);
00989 if (!m)
00990 return ConstraintEvaluationResult(false, 0.0);
00991
00992
00993 collision_detection::CollisionWorldFCL collision_world;
00994 collision_world.getWorld()->addToObject("cone", shapes::ShapeConstPtr(m), Eigen::Affine3d::Identity());
00995
00996
00997 collision_detection::CollisionRequest req;
00998 collision_detection::CollisionResult res;
00999 collision_detection::AllowedCollisionMatrix acm;
01000 acm.setDefaultEntry("cone", boost::bind(&VisibilityConstraint::decideContact, this, _1));
01001 req.contacts = true;
01002 req.verbose = verbose;
01003 req.max_contacts = 1;
01004 collision_world.checkRobotCollision(req, res, *collision_robot_, state, acm);
01005
01006 if (verbose)
01007 {
01008 std::stringstream ss;
01009 m->print(ss);
01010 logInform("Visibility constraint %ssatisfied. Visibility cone approximation:\n %s", res.collision ? "not " : "", ss.str().c_str());
01011 }
01012
01013 return ConstraintEvaluationResult(!res.collision, res.collision ? res.contacts.begin()->second.front().depth : 0.0);
01014 }
01015
01016 bool kinematic_constraints::VisibilityConstraint::decideContact(const collision_detection::Contact &contact) const
01017 {
01018 if (contact.body_type_1 == collision_detection::BodyTypes::ROBOT_ATTACHED ||
01019 contact.body_type_2 == collision_detection::BodyTypes::ROBOT_ATTACHED)
01020 return true;
01021 if (contact.body_type_1 == collision_detection::BodyTypes::ROBOT_LINK &&
01022 contact.body_type_2 == collision_detection::BodyTypes::WORLD_OBJECT &&
01023 (robot_state::Transforms::sameFrame(contact.body_name_1, sensor_frame_id_) ||
01024 robot_state::Transforms::sameFrame(contact.body_name_1, target_frame_id_)))
01025 {
01026 logDebug("Accepted collision with either sensor or target");
01027 return true;
01028 }
01029 if (contact.body_type_2 == collision_detection::BodyTypes::ROBOT_LINK &&
01030 contact.body_type_1 == collision_detection::BodyTypes::WORLD_OBJECT &&
01031 (robot_state::Transforms::sameFrame(contact.body_name_2, sensor_frame_id_) ||
01032 robot_state::Transforms::sameFrame(contact.body_name_2, target_frame_id_)))
01033 {
01034 logDebug("Accepted collision with either sensor or target");
01035 return true;
01036 }
01037 return false;
01038 }
01039
01040 void kinematic_constraints::VisibilityConstraint::print(std::ostream &out) const
01041 {
01042 if (enabled())
01043 {
01044 out << "Visibility constraint for sensor in frame '" << sensor_frame_id_ << "' using target in frame '" << target_frame_id_ << "'" << std::endl;
01045 out << "Target radius: " << target_radius_ << ", using " << cone_sides_ << " sides." << std::endl;
01046 }
01047 else
01048 out << "No constraint" << std::endl;
01049 }
01050
01051 void kinematic_constraints::KinematicConstraintSet::clear()
01052 {
01053 all_constraints_ = moveit_msgs::Constraints();
01054 kinematic_constraints_.clear();
01055 joint_constraints_.clear();
01056 position_constraints_.clear();
01057 orientation_constraints_.clear();
01058 visibility_constraints_.clear();
01059 }
01060
01061 bool kinematic_constraints::KinematicConstraintSet::add(const std::vector<moveit_msgs::JointConstraint> &jc)
01062 {
01063 bool result = true;
01064 for (unsigned int i = 0 ; i < jc.size() ; ++i)
01065 {
01066 JointConstraint *ev = new JointConstraint(robot_model_);
01067 bool u = ev->configure(jc[i]);
01068 result = result && u;
01069 kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
01070 joint_constraints_.push_back(jc[i]);
01071 all_constraints_.joint_constraints.push_back(jc[i]);
01072 }
01073 return result;
01074 }
01075
01076 bool kinematic_constraints::KinematicConstraintSet::add(const std::vector<moveit_msgs::PositionConstraint> &pc, const robot_state::Transforms &tf)
01077 {
01078 bool result = true;
01079 for (unsigned int i = 0 ; i < pc.size() ; ++i)
01080 {
01081 PositionConstraint *ev = new PositionConstraint(robot_model_);
01082 bool u = ev->configure(pc[i], tf);
01083 result = result && u;
01084 kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
01085 position_constraints_.push_back(pc[i]);
01086 all_constraints_.position_constraints.push_back(pc[i]);
01087 }
01088 return result;
01089 }
01090
01091 bool kinematic_constraints::KinematicConstraintSet::add(const std::vector<moveit_msgs::OrientationConstraint> &oc, const robot_state::Transforms &tf)
01092 {
01093 bool result = true;
01094 for (unsigned int i = 0 ; i < oc.size() ; ++i)
01095 {
01096 OrientationConstraint *ev = new OrientationConstraint(robot_model_);
01097 bool u = ev->configure(oc[i], tf);
01098 result = result && u;
01099 kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
01100 orientation_constraints_.push_back(oc[i]);
01101 all_constraints_.orientation_constraints.push_back(oc[i]);
01102 }
01103 return result;
01104 }
01105
01106 bool kinematic_constraints::KinematicConstraintSet::add(const std::vector<moveit_msgs::VisibilityConstraint> &vc, const robot_state::Transforms &tf)
01107 {
01108 bool result = true;
01109 for (unsigned int i = 0 ; i < vc.size() ; ++i)
01110 {
01111 VisibilityConstraint *ev = new VisibilityConstraint(robot_model_);
01112 bool u = ev->configure(vc[i], tf);
01113 result = result && u;
01114 kinematic_constraints_.push_back(KinematicConstraintPtr(ev));
01115 visibility_constraints_.push_back(vc[i]);
01116 all_constraints_.visibility_constraints.push_back(vc[i]);
01117 }
01118 return result;
01119 }
01120
01121 bool kinematic_constraints::KinematicConstraintSet::add(const moveit_msgs::Constraints &c, const robot_state::Transforms &tf)
01122 {
01123 bool j = add(c.joint_constraints);
01124 bool p = add(c.position_constraints, tf);
01125 bool o = add(c.orientation_constraints, tf);
01126 bool v = add(c.visibility_constraints, tf);
01127 return j && p && o && v;
01128 }
01129
01130 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::KinematicConstraintSet::decide(const robot_state::RobotState &state, bool verbose) const
01131 {
01132 ConstraintEvaluationResult res(true, 0.0);
01133 for (unsigned int i = 0 ; i < kinematic_constraints_.size() ; ++i)
01134 {
01135 ConstraintEvaluationResult r = kinematic_constraints_[i]->decide(state, verbose);
01136 if (!r.satisfied)
01137 res.satisfied = false;
01138 res.distance += r.distance;
01139 }
01140 return res;
01141 }
01142
01143 kinematic_constraints::ConstraintEvaluationResult kinematic_constraints::KinematicConstraintSet::decide(const robot_state::RobotState &state,
01144 std::vector<ConstraintEvaluationResult> &results,
01145 bool verbose) const
01146 {
01147 ConstraintEvaluationResult result(true, 0.0);
01148 results.resize(joint_constraints_.size());
01149 for (std::size_t i = 0 ; i < joint_constraints_.size() ; ++i)
01150 {
01151 results[i] = kinematic_constraints_[i]->decide(state, verbose);
01152 result.satisfied = result.satisfied && results[i].satisfied;
01153 result.distance += results[i].distance;
01154 }
01155
01156 return result;
01157 }
01158
01159 void kinematic_constraints::KinematicConstraintSet::print(std::ostream &out) const
01160 {
01161 out << kinematic_constraints_.size() << " kinematic constraints" << std::endl;
01162 for (unsigned int i = 0 ; i < kinematic_constraints_.size() ; ++i)
01163 kinematic_constraints_[i]->print(out);
01164 }
01165
01166 bool kinematic_constraints::KinematicConstraintSet::equal(const KinematicConstraintSet &other, double margin) const
01167 {
01168
01169 for (unsigned int i = 0 ; i < kinematic_constraints_.size() ; ++i)
01170 {
01171 bool found = false;
01172 for (unsigned int j = 0 ; !found && j < other.kinematic_constraints_.size() ; ++j)
01173 found = kinematic_constraints_[i]->equal(*other.kinematic_constraints_[j], margin);
01174 if (!found)
01175 return false;
01176 }
01177
01178 for (unsigned int i = 0 ; i < other.kinematic_constraints_.size() ; ++i)
01179 {
01180 bool found = false;
01181 for (unsigned int j = 0 ; !found && j < kinematic_constraints_.size() ; ++j)
01182 found = other.kinematic_constraints_[i]->equal(*kinematic_constraints_[j], margin);
01183 if (!found)
01184 return false;
01185 }
01186 return true;
01187 }