33 static const std::string DEBUG_NS =
"stomp_moveit_kinematics";
38 for(
int i = 0; i < jarr.rows(); i++)
42 return std::move(jarr);
45 KDL::Chain createKDLChain(moveit::core::RobotModelConstPtr robot_model,std::string base_link,std::string tip_link)
50 tree.
getChain(base_link,tip_link,chain);
54 std::shared_ptr<TRAC_IK::TRAC_IK> createTRACIKSolver(moveit::core::RobotModelConstPtr robot_model,
const moveit::core::JointModelGroup* group,
double max_time = 0.01)
58 std::string base_link = group->
getJointModels().front()->getParentLinkModel()->getName();
62 ROS_DEBUG_NAMED(DEBUG_NS,
"Creating IK solver with base link '%s' and tip link '%s'",base_link.c_str(),tip_link.c_str());
65 KDL::Chain kdl_chain = createKDLChain(robot_model,base_link,tip_link);
69 std::vector<double> min_vals, max_vals;
70 for(
int i = 0; i < num_joints;i++)
75 max_vals.push_back(b.max_position_);
76 min_vals.push_back(b.min_position_);
81 num_joints = min_vals.size();
84 std::shared_ptr<TRAC_IK::TRAC_IK> solver(
new TRAC_IK::TRAC_IK(kdl_chain,jmin,jmax,max_time));
101 robot_model_(robot_state.getRobotModel()),
102 group_name_(group_name),
108 ik_solver_impl_ = createTRACIKSolver(robot_model_,robot_model_->getJointModelGroup(group_name),max_time);
111 IKSolver::~IKSolver()
118 (*robot_state_) = state;
119 robot_state_->update();
123 std::string base_link = group->
getJointModels().front()->getParentLinkModel()->getName();
124 Eigen::Affine3d root_to_base_tf = robot_state_->getFrameTransform(base_link);
125 tf_base_to_root_ = root_to_base_tf.inverse();
128 bool IKSolver::solve(
const Eigen::VectorXd& seed,
const Eigen::Affine3d& tool_pose,Eigen::VectorXd& solution,
131 using namespace Eigen;
132 std::vector<double> seed_(seed.size(),0);
133 std::vector<double> solution_;
134 std::vector<double> tol_(6,0);
137 VectorXd::Map(&seed_.front(),seed.size()) = seed;
138 VectorXd::Map(&tol_.front(),tol_.size()) = tol;
140 if(!
solve(seed_,tool_pose,solution_,tol_))
145 solution.resize(solution_.size());
146 solution = VectorXd::Map(solution_.data(),solution_.size());
150 bool IKSolver::solve(
const std::vector<double>& seed,
const Eigen::Affine3d& tool_pose,std::vector<double>& solution,
151 std::vector<double> tol)
154 using namespace Eigen;
155 JntArray seed_kdl = toKDLJntArray(seed);
161 for(
int i = 0; i < tol.size(); i++)
170 if(ik_solver_impl_->CartToJnt(seed_kdl,tool_pose_kdl,solution_kdl,tol_kdl) <= 0)
173 ROS_DEBUG_STREAM_NAMED(DEBUG_NS,
"Cartesian tolerance used :\n"<<tol_kdl[0]<<
" "<<tol_kdl[1]<<
" "<<tol_kdl[2]<<
" "<<tol_kdl[3]<<
" "<<tol_kdl[4]<<
" "<<tol_kdl[5]);
177 solution.resize(solution_kdl.
rows());
178 VectorXd::Map(&solution[0],solution.size()) = solution_kdl.
data;
182 bool IKSolver::solve(
const std::vector<double>& seed,
const moveit_msgs::Constraints& tool_constraints,std::vector<double>& solution)
184 Eigen::Affine3d tool_pose;
185 std::vector<double> tolerance;
191 return solve(seed,tool_pose,solution,tolerance);
194 bool IKSolver::solve(
const Eigen::VectorXd& seed,
const moveit_msgs::Constraints& tool_constraints,Eigen::VectorXd& solution)
196 Eigen::Affine3d tool_pose;
197 std::vector<double> tolerance;
203 Eigen::VectorXd tolerance_eigen = Eigen::VectorXd::Zero(6);
204 tolerance_eigen = Eigen::VectorXd::Map(tolerance.data(),tolerance.size());
205 return solve(seed,tool_pose,solution,tolerance_eigen);
210 std::string pos_frame_id, orient_frame_id;
211 bool found_cart =
false;
212 if(c.position_constraints.empty() && c.orientation_constraints.empty())
214 ROS_DEBUG(
"No cartesian constraints were found, failed validation");
218 if(!c.position_constraints.empty())
220 pos_frame_id = c.position_constraints.front().header.frame_id;
221 found_cart = !pos_frame_id.empty();
224 if(!c.orientation_constraints.empty())
226 orient_frame_id = c.orientation_constraints.front().header.frame_id;
227 found_cart = !orient_frame_id.empty();
230 if(!pos_frame_id.empty() && !orient_frame_id.empty() && (pos_frame_id != orient_frame_id))
232 ROS_ERROR(
"Position frame id '%s' differs from orientation frame id '%s', invalid Cartesian constraint",
233 pos_frame_id.c_str(), orient_frame_id.c_str());
241 double default_pos_tol ,
double default_rot_tol)
243 using namespace moveit_msgs;
245 moveit_msgs::Constraints full_constraint;
252 int num_pos_constraints = c.position_constraints.size();
253 int num_orient_constraints = c.orientation_constraints.size();
254 int num_entries = num_pos_constraints >= num_orient_constraints ? num_pos_constraints : num_orient_constraints;
255 std::string frame_id = !c.position_constraints.empty() ? c.position_constraints.front().header.frame_id : c.orientation_constraints.front().header.frame_id ;
259 PositionConstraint default_pos_constraint;
260 default_pos_constraint.header.frame_id = frame_id;
261 default_pos_constraint.constraint_region.primitive_poses.resize(1);
262 tf::poseEigenToMsg(Eigen::Affine3d::Identity(), default_pos_constraint.constraint_region.primitive_poses[0]);
263 default_pos_constraint.constraint_region.primitive_poses[0].position.x = ref_pose.translation().x();
264 default_pos_constraint.constraint_region.primitive_poses[0].position.y = ref_pose.translation().y();
265 default_pos_constraint.constraint_region.primitive_poses[0].position.z = ref_pose.translation().z();
266 shape_msgs::SolidPrimitive shape;
267 shape.type = shape.SPHERE;
268 shape.dimensions.push_back(default_pos_tol);
269 default_pos_constraint.constraint_region.primitives.push_back(shape);
272 OrientationConstraint default_orient_constraint;
273 default_orient_constraint.header.frame_id = frame_id;
274 default_orient_constraint.absolute_x_axis_tolerance = default_rot_tol;
275 default_orient_constraint.absolute_y_axis_tolerance = default_rot_tol;
276 default_orient_constraint.absolute_z_axis_tolerance = default_rot_tol;
277 default_orient_constraint.orientation.x = default_orient_constraint.orientation.y = default_orient_constraint.orientation.z = 0;
278 default_orient_constraint.orientation.w = 1;
281 full_constraint.position_constraints.resize(num_entries);
282 full_constraint.orientation_constraints.resize(num_entries);
283 for(
int i =0; i < num_entries; i++)
286 if(c.position_constraints.size() >= num_entries)
288 full_constraint.position_constraints[i] = c.position_constraints[i];
292 full_constraint.position_constraints[i] = default_pos_constraint;
296 if(c.orientation_constraints.size() >= num_entries)
298 full_constraint.orientation_constraints[i] = c.orientation_constraints[i];
302 full_constraint.orientation_constraints[i] = default_orient_constraint;
306 return full_constraint;
309 bool decodeCartesianConstraint(moveit::core::RobotModelConstPtr model,
const moveit_msgs::Constraints& constraints, Eigen::Affine3d& tool_pose,
310 Eigen::VectorXd& tolerance, std::string target_frame)
312 std::vector<double> tolerance_std;
318 tolerance = Eigen::VectorXd::Map(tolerance_std.data(),tolerance_std.size());
322 bool decodeCartesianConstraint(moveit::core::RobotModelConstPtr model,
const moveit_msgs::Constraints& constraints, Eigen::Affine3d& tool_pose,
323 std::vector<double>& tolerance, std::string target_frame)
325 using namespace Eigen;
328 tolerance.resize(6,0);
329 geometry_msgs::Point p;
330 Eigen::Quaterniond q = Quaterniond::Identity();
331 const std::vector<moveit_msgs::PositionConstraint>& pos_constraints = constraints.position_constraints;
332 const std::vector<moveit_msgs::OrientationConstraint>& orient_constraints = constraints.orientation_constraints;
334 int num_constraints = pos_constraints.size() > orient_constraints.size() ? pos_constraints.size() : orient_constraints.size();
335 if(num_constraints == 0)
337 ROS_ERROR(
"Constraints message is empty");
342 if(pos_constraints.empty())
344 ROS_ERROR(
"Position constraint is empty");
349 const moveit_msgs::PositionConstraint& pos_constraint = pos_constraints[0];
352 p = pos_constraint.constraint_region.primitive_poses[0].position;
355 const shape_msgs::SolidPrimitive& bv = pos_constraint.constraint_region.primitives[0];
356 bool valid_constraint =
true;
359 case shape_msgs::SolidPrimitive::BOX :
361 if(bv.dimensions.size() != 3)
363 ROS_WARN(
"Position constraint for BOX shape incorrectly defined, only 3 dimensions entries are needed");
364 valid_constraint =
false;
368 using SP = shape_msgs::SolidPrimitive;
369 tolerance[0] = bv.dimensions[SP::BOX_X];
370 tolerance[1] = bv.dimensions[SP::BOX_Y];
371 tolerance[2] = bv.dimensions[SP::BOX_Z];
375 case shape_msgs::SolidPrimitive::SPHERE:
377 if(bv.dimensions.size() != 1)
379 ROS_WARN(
"Position constraint for SPHERE shape has no valid dimensions");
380 valid_constraint =
false;
384 using SP = shape_msgs::SolidPrimitive;
385 tolerance[0] = bv.dimensions[SP::SPHERE_RADIUS];
386 tolerance[1] = bv.dimensions[SP::SPHERE_RADIUS];
387 tolerance[2] = bv.dimensions[SP::SPHERE_RADIUS];
393 ROS_WARN(
"The Position constraint shape %i isn't supported, defaulting position tolerance to zero",bv.type);
399 if(orient_constraints.size() == 0)
402 std::fill(tolerance.begin()+3,tolerance.end(),
M_PI);
406 const moveit_msgs::OrientationConstraint& orient_constraint = orient_constraints[0];
409 tolerance[3] = orient_constraint.absolute_x_axis_tolerance;
410 tolerance[4] = orient_constraint.absolute_y_axis_tolerance;
411 tolerance[5] = orient_constraint.absolute_z_axis_tolerance;
418 tool_pose = Affine3d::Identity()*Eigen::Translation3d(Eigen::Vector3d(p.x,p.y,p.z))*q;
421 if(target_frame.empty())
423 target_frame = model->getModelFrame();
426 const moveit_msgs::PositionConstraint& pos_constraint = pos_constraints[0];
427 std::string frame_id = pos_constraint.header.frame_id;
432 ROS_ERROR(
"Frame '%s' is not part of the model",frame_id.c_str());
437 ROS_ERROR(
"Frame '%s' is not part of the model",target_frame.c_str());
441 if(!frame_id.empty() && target_frame != frame_id)
445 tool_pose = (root_to_target.inverse()) * root_to_frame * tool_pose;
453 using namespace Eigen;
457 std::random_device rd;
458 std::mt19937 gen(rd());
459 auto sample_val_func = [&gen](
double min,
double max,
double intrv) ->
double 461 double length = max - min;
462 if(length <= intrv || length < 1e-6)
464 return 0.5*(max + min);
467 int num_intervals = std::ceil(length/intrv);
468 std::uniform_int_distribution<> dis(0, num_intervals);
470 double val = min + r*(intrv);
471 val = val > max ? max : val;
476 const std::vector<moveit_msgs::PositionConstraint>& pos_constraints = c.position_constraints;
477 const std::vector<moveit_msgs::OrientationConstraint>& orient_constraints = c.orientation_constraints;
478 for(std::size_t k = 0; k < pos_constraints.size(); k++)
481 const moveit_msgs::PositionConstraint& pos_constraint = pos_constraints[k];
482 const moveit_msgs::OrientationConstraint& orient_constraint = orient_constraints[k];
485 std::vector<double> tolerances(6);
486 const shape_msgs::SolidPrimitive& bv = pos_constraint.constraint_region.primitives[0];
487 bool valid_constraint =
true;
490 case shape_msgs::SolidPrimitive::BOX :
492 if(bv.dimensions.size() != 3)
494 ROS_WARN(
"Position constraint for BOX shape incorrectly defined, only 3 dimensions entries are needed");
495 valid_constraint =
false;
499 using SP = shape_msgs::SolidPrimitive;
500 tolerances[0] = bv.dimensions[SP::BOX_X];
501 tolerances[1] = bv.dimensions[SP::BOX_Y];
502 tolerances[2] = bv.dimensions[SP::BOX_Z];
506 case shape_msgs::SolidPrimitive::SPHERE:
508 if(bv.dimensions.size() != 1)
510 ROS_WARN(
"Position constraint for SPHERE shape has no valid dimensions");
511 valid_constraint =
false;
515 using SP = shape_msgs::SolidPrimitive;
516 tolerances[0] = bv.dimensions[SP::SPHERE_RADIUS];
517 tolerances[1] = bv.dimensions[SP::SPHERE_RADIUS];
518 tolerances[2] = bv.dimensions[SP::SPHERE_RADIUS];
524 ROS_ERROR(
"The Position constraint shape %i isn't supported",bv.type);
525 valid_constraint =
false;
529 if(!valid_constraint)
535 tolerances[3] = orient_constraint.absolute_x_axis_tolerance;
536 tolerances[4] = orient_constraint.absolute_y_axis_tolerance;
537 tolerances[5] = orient_constraint.absolute_z_axis_tolerance;
540 int total_num_samples = 1;
541 for(std::size_t i = 0; i < tolerances.size(); i++)
543 total_num_samples *= (std::floor((2*tolerances[i]/sampling_resolution[i]) + 1) );
545 total_num_samples = total_num_samples > max_samples ? max_samples : total_num_samples;
549 auto& p = pos_constraint.constraint_region.primitive_poses[0].position;
552 Eigen::Quaterniond q;
556 std::vector<double> vals(6);
557 Affine3d nominal_pos = Affine3d::Identity()*Eigen::Translation3d(Eigen::Vector3d(p.x,p.y,p.z));
558 Affine3d nominal_rot = Affine3d::Identity()*q;
559 for(
int i = 0; i < total_num_samples; i++)
561 for(
int j = 0; j < vals.size() ; j++)
563 vals[j] = sample_val_func(-0.5*tolerances[j],0.5*tolerances[j],sampling_resolution[j]);
566 Affine3d rot = nominal_rot * AngleAxisd(vals[3],Vector3d::UnitX()) * AngleAxisd(vals[4],Vector3d::UnitY())
567 * AngleAxisd(vals[5],Vector3d::UnitZ());
568 Affine3d pose = nominal_pos * Translation3d(Vector3d(vals[0],vals[1],vals[2])) * rot;
569 poses.push_back(pose);
572 if(poses.size()>= max_samples)
582 const Eigen::Affine3d& pf,
583 const Eigen::ArrayXi& nullity,Eigen::VectorXd& twist)
585 twist.resize(nullity.size());
586 twist.setConstant(0);
589 auto p0_inv = p0.inverse();
590 Eigen::Affine3d t = (p0_inv) * pf;
592 Eigen::Vector3d twist_pos = pf.translation() - p0.translation();
595 Eigen::AngleAxisd relative_rot(t.rotation());
596 double angle = relative_rot.angle();
597 Eigen::Vector3d axis = relative_rot.axis();
600 while( (angle >
M_PI) || (angle < -
M_PI))
602 angle = (angle >
M_PI) ? (angle - 2*
M_PI) : angle;
603 angle = (angle < -
M_PI )? (angle + 2*
M_PI) : angle;
607 Eigen::Vector3d twist_rot = axis.normalized() * angle;
610 twist.head(3) = twist_pos;
611 twist.tail(3) = twist_rot;
614 twist = (nullity == 0).select(0,twist);
618 const std::vector<int>& indices,Eigen::MatrixXd& jacb_reduced)
620 jacb_reduced.resize(indices.size(),jacb.cols());
621 for(
auto i = 0u; i < indices.size(); i++)
623 jacb_reduced.row(i) = jacb.row(indices[i]);
629 double eps,
double lambda)
631 using namespace Eigen;
636 Eigen::JacobiSVD<MatrixXd> svd(jacb, Eigen::ComputeThinU | Eigen::ComputeThinV);
637 const MatrixXd &U = svd.matrixU();
638 const VectorXd &Sv = svd.singularValues();
639 const MatrixXd &V = svd.matrixV();
643 size_t nSv = Sv.size();
644 VectorXd inv_Sv(nSv);
645 for(
size_t i=0; i< nSv; ++i)
647 if (fabs(Sv(i)) > eps)
653 inv_Sv(i) = Sv(i) / (Sv(i)*Sv(i) + lambda*lambda);
657 jacb_pseudo_inv = V * inv_Sv.asDiagonal() * U.transpose();
661 const Eigen::ArrayXi& constrained_dofs,
const Eigen::VectorXd& joint_pose,
662 Eigen::MatrixXd& jacb_nullspace)
664 using namespace Eigen;
669 state->setJointGroupPositions(joint_group,joint_pose);
670 Affine3d tool_pose = state->getGlobalLinkTransform(tool_link);
673 static MatrixXd jacb_transform(6,6);
674 MatrixXd jacb, jacb_reduced, jacb_pseudo_inv;
675 jacb_transform.setZero();
677 if(!state->getJacobian(joint_group,state->
getLinkModel(tool_link),Vector3d::Zero(),jacb))
679 ROS_ERROR(
"Failed to get Jacobian for link %s",tool_link.c_str());
684 auto rot = tool_pose.inverse().rotation();
685 jacb_transform.setZero();
686 jacb_transform.block(0,0,3,3) = rot;
687 jacb_transform.block(3,3,3,3) = rot;
688 jacb = jacb_transform*jacb;
691 std::vector<int> indices;
692 for(
auto i = 0u; i < constrained_dofs.size(); i++)
694 if(constrained_dofs(i) != 0)
696 indices.push_back(i);
702 int num_joints = joint_pose.size();
703 jacb_nullspace = MatrixXd::Identity(num_joints,num_joints) - jacb_pseudo_inv*jacb_reduced;
bool decodeCartesianConstraint(moveit::core::RobotModelConstPtr model, const moveit_msgs::Constraints &constraints, Eigen::Affine3d &tool_pose, std::vector< double > &tolerance, std::string target_frame="")
Extracts the cartesian data from the constraint message.
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::vector< Eigen::Affine3d, Eigen::aligned_allocator< Eigen::Affine3d > > vector_Affine3d
KDL_PARSER_PUBLIC bool treeFromUrdfModel(const urdf::ModelInterface &robot_model, KDL::Tree &tree)
unsigned int rows() const
bool knowsFrameTransform(const std::string &id) const
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
bool computeJacobianNullSpace(moveit::core::RobotStatePtr state, std::string group, std::string tool_link, const Eigen::ArrayXi &constrained_dofs, const Eigen::VectorXd &joint_pose, Eigen::MatrixXd &jacb_nullspace)
Convenience function to calculate the Jacobian's null space matrix for an under constrained tool cart...
const std::vector< std::string > & getLinkModelNames() const
const LinkModel * getLinkModel(const std::string &link) const
EigenSTL::vector_Affine3d sampleCartesianPoses(const moveit_msgs::Constraints &c, const std::vector< double > sampling_resolution={0.05, 0.05, 0.05, M_PI_2, M_PI_2, M_PI_2}, int max_samples=20)
Creates cartesian poses in accordance to the constraint and sampling resolution values.
const Eigen::Affine3d & getFrameTransform(const std::string &id)
void reduceJacobian(const Eigen::MatrixXd &jacb, const std::vector< int > &indices, Eigen::MatrixXd &jacb_reduced)
Convenience function to remove entire rows of the Jacobian matrix.
void transformEigenToKDL(const Eigen::Affine3d &e, KDL::Frame &k)
void computeTwist(const Eigen::Affine3d &p0, const Eigen::Affine3d &pf, const Eigen::ArrayXi &nullity, Eigen::VectorXd &twist)
Computes the twist vector [vx vy vz wx wy wz]' relative to the current tool coordinate system...
static const double EPSILON
Used in dampening the matrix pseudo inverse calculation.
#define ROS_DEBUG_NAMED(name,...)
boost::optional< moveit_msgs::Constraints > curateCartesianConstraints(const moveit_msgs::Constraints &c, const Eigen::Affine3d &ref_pose, double default_pos_tol=0.0005, double default_rot_tol=M_PI)
Populates the missing parts of a Cartesian constraints in order to provide a constraint that can be u...
void update(bool force=false)
static const double LAMBDA
Used in dampening the matrix pseudo inverse calculation.
std::vector< const JointModel::Bounds * > JointBoundsVector
const std::vector< std::string > & getActiveJointModelNames() const
This defines kinematic related utilities.
double min(double a, double b)
const std::vector< const JointModel * > & getJointModels() const
bool isCartesianConstraints(const moveit_msgs::Constraints &c)
Checks if the constraint structured contains valid data from which a proper cartesian constraint can ...
bool getChain(const std::string &chain_root, const std::string &chain_tip, Chain &chain) const
void quaternionMsgToEigen(const geometry_msgs::Quaternion &m, Eigen::Quaterniond &e)
bool solve(const Eigen::VectorXd &seed, const Eigen::Affine3d &tool_pose, Eigen::VectorXd &solution, Eigen::VectorXd tol=Eigen::VectorXd::Constant(6, 0.005))
Find the joint position that achieves the requested tool pose.
double max(double a, double b)
std::vector< VariableBounds > Bounds
void setKinematicState(const moveit::core::RobotState &state)
Should be called whenever the robot's kinematic state has changed.
const JointBoundsVector & getActiveJointModelsBounds() const
void calculateDampedPseudoInverse(const Eigen::MatrixXd &jacb, Eigen::MatrixXd &jacb_pseudo_inv, double eps=0.011, double lambda=0.01)
Calculates the damped pseudo inverse of a matrix using singular value decomposition.