kinematics.h
Go to the documentation of this file.
00001 
00026 #ifndef INDUSTRIAL_MOVEIT_STOMP_MOVEIT_INCLUDE_STOMP_MOVEIT_UTILS_KINEMATICS_H_
00027 #define INDUSTRIAL_MOVEIT_STOMP_MOVEIT_INCLUDE_STOMP_MOVEIT_UTILS_KINEMATICS_H_
00028 
00029 #include <ros/console.h>
00030 #include <Eigen/Geometry>
00031 #include <eigen_conversions/eigen_msg.h>
00032 #include <moveit/robot_state/robot_state.h>
00033 #include <moveit/robot_state/conversions.h>
00034 #include <pluginlib/class_list_macros.h>
00035 #include <XmlRpcException.h>
00036 #include <moveit_msgs/PositionConstraint.h>
00037 #include <moveit_msgs/OrientationConstraint.h>
00038 
00039 
00040 namespace stomp_moveit
00041 {
00042 namespace utils
00043 {
00044 
00049 namespace kinematics
00050 {
00051 
00052   const static double EPSILON = 0.011;  
00053   const static double LAMBDA = 0.01;    
00059   struct KinematicConfig
00060   {
00064     Eigen::Array<int,6,1> constrained_dofs = Eigen::Array<int,6,1>::Ones(); 
00066     Eigen::Affine3d tool_goal_pose = Eigen::Affine3d::Identity();           
00071     Eigen::ArrayXd joint_update_rates = Eigen::ArrayXd::Zero(1,1);          
00072     Eigen::Array<double,6,1> cartesian_convergence_thresholds = Eigen::Array<double,6,1>::Zero(); 
00073     Eigen::VectorXd init_joint_pose = Eigen::ArrayXd::Zero(1,1);            
00074     int max_iterations = 100;                                               
00079     Eigen::ArrayXd null_proj_weights = Eigen::ArrayXd::Zero(1,1);  
00080     Eigen::VectorXd null_space_vector = Eigen::VectorXd::Zero(1);  
00082   };
00083 
00093   static bool createKinematicConfig(const moveit::core::JointModelGroup* group,
00094                                                const moveit_msgs::PositionConstraint& pc,const moveit_msgs::OrientationConstraint& oc,
00095                                                const Eigen::VectorXd& init_joint_pose,KinematicConfig& kc)
00096   {
00097     int num_joints = group->getActiveJointModelNames().size();
00098     if(num_joints != init_joint_pose.size())
00099     {
00100       ROS_ERROR("Initial joint pose has an incorrect number of joints");
00101       return false;
00102     }
00103 
00104     // tool pose position
00105     kc.tool_goal_pose.setIdentity();
00106     auto& v = pc.constraint_region.primitive_poses[0].position;
00107     kc.tool_goal_pose.translation() = Eigen::Vector3d(v.x,v.y,v.z);
00108 
00109     // tool pose orientation
00110     Eigen::Quaterniond q;
00111     tf::quaternionMsgToEigen(oc.orientation,q);
00112     kc.tool_goal_pose.rotate(q);
00113 
00114     // defining constraints
00115     kc.constrained_dofs << 1, 1, 1, 1, 1, 1;
00116 
00117     // position tolerance
00118     const shape_msgs::SolidPrimitive& bv = pc.constraint_region.primitives[0];
00119     if(bv.type != shape_msgs::SolidPrimitive::BOX || bv.dimensions.size() != 3)
00120     {
00121       ROS_ERROR("Position constraint incorrectly defined, a BOX region is expected");
00122       return false;
00123     }
00124 
00125     using SP = shape_msgs::SolidPrimitive;
00126     kc.cartesian_convergence_thresholds[0] = bv.dimensions[SP::BOX_X];
00127     kc.cartesian_convergence_thresholds[1] = bv.dimensions[SP::BOX_Y];
00128     kc.cartesian_convergence_thresholds[2] = bv.dimensions[SP::BOX_Z];
00129 
00130     // orientation tolerance
00131     kc.cartesian_convergence_thresholds[3] = oc.absolute_x_axis_tolerance;
00132     kc.cartesian_convergence_thresholds[4] = oc.absolute_y_axis_tolerance;
00133     kc.cartesian_convergence_thresholds[5] = oc.absolute_z_axis_tolerance;
00134 
00135     // unconstraining orientation dofs that exceed 2pi
00136     for(std::size_t i = 3; i < kc.cartesian_convergence_thresholds.size(); i++)
00137     {
00138       auto v = kc.cartesian_convergence_thresholds[i];
00139       kc.constrained_dofs[i] = v >= 2*M_PI ? 0 : 1;
00140     }
00141 
00142     // additional variables
00143     kc.joint_update_rates = Eigen::ArrayXd::Constant(num_joints,0.5f);
00144     kc.init_joint_pose = init_joint_pose;
00145     kc.max_iterations = 100;
00146 
00147     return true;
00148   }
00149 
00159   static bool createKinematicConfig(const moveit::core::JointModelGroup* group,
00160                                                const moveit_msgs::PositionConstraint& pc,const moveit_msgs::OrientationConstraint& oc,
00161                                                const moveit_msgs::RobotState& start_state,KinematicConfig& kc)
00162   {
00163     const auto& joint_names= group->getActiveJointModelNames();
00164     const auto& jstate = start_state.joint_state;
00165     std::size_t ind = 0;
00166     Eigen::VectorXd joint_vals = Eigen::VectorXd::Zero(joint_names.size());
00167     for(std::size_t i = 0; i < joint_names.size();i ++)
00168     {
00169       auto pos = std::find(jstate.name.begin(),jstate.name.end(),joint_names[i]);
00170       if(pos == jstate.name.end())
00171       {
00172         return false;
00173       }
00174 
00175       ind = std::distance(jstate.name.begin(),pos);
00176       joint_vals(i) = jstate.position[ind];
00177     }
00178 
00179     return createKinematicConfig(group,pc,oc,joint_vals,kc);
00180   }
00181 
00191   static void computeTwist(const Eigen::Affine3d& p0,
00192                                           const Eigen::Affine3d& pf,
00193                                           const Eigen::ArrayXi& nullity,Eigen::VectorXd& twist)
00194   {
00195     twist.resize(nullity.size());
00196     twist.setConstant(0);
00197 
00198     // relative transform
00199     auto p0_inv = p0.inverse();
00200     Eigen::Affine3d t = (p0_inv) * pf;
00201 
00202     Eigen::Vector3d twist_pos = p0_inv.rotation()*(pf.translation() - p0.translation());
00203 
00204     // relative rotation -> R = inverse(R0) * Rf
00205     Eigen::AngleAxisd relative_rot(t.rotation());
00206     double angle = relative_rot.angle();
00207     Eigen::Vector3d axis = relative_rot.axis();
00208 
00209     // forcing angle to range [-pi , pi]
00210     while( (angle > M_PI) || (angle < -M_PI))
00211     {
00212       angle = (angle >  M_PI) ? (angle - 2*M_PI) : angle;
00213       angle = (angle < -M_PI )? (angle + 2*M_PI) : angle;
00214     }
00215 
00216     // creating twist rotation relative to tool
00217     Eigen::Vector3d twist_rot = axis.normalized() * angle;
00218 
00219     // assigning into full 6dof twist vector
00220     twist.head(3) = twist_pos;
00221     twist.tail(3) = twist_rot;
00222 
00223     // zeroing all underconstrained cartesian dofs
00224     twist = (nullity == 0).select(0,twist);
00225   }
00226 
00233   static void reduceJacobian(const Eigen::MatrixXd& jacb,
00234                                             const std::vector<int>& indices,Eigen::MatrixXd& jacb_reduced)
00235   {
00236     jacb_reduced.resize(indices.size(),jacb.cols());
00237     for(auto i = 0u; i < indices.size(); i++)
00238     {
00239       jacb_reduced.row(i) = jacb.row(indices[i]);
00240     }
00241   }
00242 
00250   static void calculateDampedPseudoInverse(const Eigen::MatrixXd &jacb, Eigen::MatrixXd &jacb_pseudo_inv,
00251                                            double eps = 0.011, double lambda = 0.01)
00252   {
00253     using namespace Eigen;
00254 
00255 
00256     //Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are real)
00257     //in order to solve Ax=b -> x*=A+ b
00258     Eigen::JacobiSVD<MatrixXd> svd(jacb, Eigen::ComputeThinU | Eigen::ComputeThinV);
00259     const MatrixXd &U = svd.matrixU();
00260     const VectorXd &Sv = svd.singularValues();
00261     const MatrixXd &V = svd.matrixV();
00262 
00263     // calculate the reciprocal of Singular-Values
00264     // damp inverse with lambda so that inverse doesn't oscillate near solution
00265     size_t nSv = Sv.size();
00266     VectorXd inv_Sv(nSv);
00267     for(size_t i=0; i< nSv; ++i)
00268     {
00269       if (fabs(Sv(i)) > eps)
00270       {
00271         inv_Sv(i) = 1/Sv(i);
00272       }
00273       else
00274       {
00275         inv_Sv(i) = Sv(i) / (Sv(i)*Sv(i) + lambda*lambda);
00276       }
00277     }
00278 
00279     jacb_pseudo_inv = V * inv_Sv.asDiagonal() * U.transpose();
00280   }
00281 
00299   static bool solveIK(moveit::core::RobotStatePtr robot_state, const std::string& group_name,
00300                       const Eigen::Array<int,6,1>& constrained_dofs,
00301                       const Eigen::ArrayXd& joint_update_rates,
00302                       const Eigen::Array<double,6,1>& cartesian_convergence_thresholds,
00303                       const Eigen::ArrayXd& null_proj_weights,
00304                       const Eigen::VectorXd& null_space_vector,
00305                       int max_iterations,
00306                       const Eigen::Affine3d& tool_goal_pose,
00307                       const Eigen::VectorXd& init_joint_pose,
00308                       Eigen::VectorXd& joint_pose)
00309   {
00310 
00311     using namespace Eigen;
00312     using namespace moveit::core;
00313 
00314     // joint variables
00315     VectorXd delta_j = VectorXd::Zero(init_joint_pose.size());
00316     joint_pose = init_joint_pose;
00317     const JointModelGroup* joint_group = robot_state->getJointModelGroup(group_name);
00318     robot_state->setJointGroupPositions(joint_group,joint_pose);
00319     const auto& joint_names = joint_group->getActiveJointModelNames();
00320     std::string tool_link = joint_group->getLinkModelNames().back();
00321     Affine3d tool_current_pose = robot_state->getGlobalLinkTransform(tool_link);
00322 
00323     auto harmonize_joints = [&joint_group,&joint_names](Eigen::VectorXd& joint_vals) -> bool
00324     {
00325       if(joint_names.size() != joint_vals.size())
00326       {
00327         return false;
00328       }
00329 
00330       const double incr = 2*M_PI;
00331       for(std::size_t i = 0; i < joint_names.size();i++)
00332       {
00333         if( joint_group->getJointModel(joint_names[i])->getType() != JointModel::REVOLUTE )
00334         {
00335           continue;
00336         }
00337 
00338         const JointModel::Bounds& bounds = joint_group->getJointModel(joint_names[i])->getVariableBounds();
00339 
00340         double j = joint_vals(i);
00341         for(const VariableBounds& b: bounds)
00342         {
00343 
00344           while(j > b.max_position_)
00345           {
00346             j-= incr;
00347           }
00348 
00349           while(j < b.min_position_)
00350           {
00351             j += incr;
00352           }
00353         }
00354 
00355         joint_vals(i) = j;
00356       }
00357 
00358       return true;
00359     };
00360 
00361     // tool twist variables
00362     VectorXd tool_twist, tool_twist_reduced;
00363     std::vector<int> indices;
00364     for(auto i = 0u; i < constrained_dofs.size(); i++)
00365     {
00366       if(constrained_dofs(i) != 0)
00367       {
00368         indices.push_back(i);
00369       }
00370     }
00371     tool_twist_reduced = VectorXd::Zero(indices.size());
00372 
00373     // jacobian calculation variables
00374     static MatrixXd jacb_transform(6,6);
00375     MatrixXd jacb, jacb_reduced, jacb_pseudo_inv;
00376     MatrixXd identity = MatrixXd::Identity(init_joint_pose.size(),init_joint_pose.size());
00377     VectorXd null_space_proj;
00378     bool project_into_nullspace = (null_proj_weights.size()> 0) &&  (null_proj_weights >1e-8).any();
00379 
00380     unsigned int iteration_count = 0;
00381     bool converged = false;
00382     while(iteration_count < max_iterations)
00383     {
00384       // computing twist vector
00385       computeTwist(tool_current_pose,tool_goal_pose,constrained_dofs,tool_twist);
00386 
00387       // check convergence
00388       if((tool_twist.cwiseAbs().array() <= cartesian_convergence_thresholds).all())
00389       {
00390         if(robot_state->satisfiesBounds(joint_group))
00391         {
00392           converged = true;
00393         }
00394         else
00395         {
00396           ROS_DEBUG("IK joint solution violates bounds");
00397         }
00398         break;
00399       }
00400 
00401       // updating reduced tool twist
00402       for(auto i = 0u; i < indices.size(); i++)
00403       {
00404         tool_twist_reduced(i) = tool_twist(indices[i]);
00405       }
00406 
00407       // computing jacobian
00408       if(!robot_state->getJacobian(joint_group,robot_state->getLinkModel(tool_link),Vector3d::Zero(),jacb))
00409       {
00410         ROS_ERROR("Failed to get Jacobian for link %s",tool_link.c_str());
00411         return false;
00412       }
00413 
00414       // transform jacobian to tool coordinates
00415       auto rot = tool_current_pose.inverse().rotation();
00416       jacb_transform.setZero();
00417       jacb_transform.block(0,0,3,3) = rot;
00418       jacb_transform.block(3,3,3,3) = rot;
00419       jacb = jacb_transform*jacb;
00420 
00421       // reduce jacobian and compute its pseudo inverse
00422       reduceJacobian(jacb,indices,jacb_reduced);
00423       calculateDampedPseudoInverse(jacb_reduced,jacb_pseudo_inv,EPSILON,LAMBDA);
00424 
00425       if(project_into_nullspace)
00426       {
00427         null_space_proj = (identity - jacb_pseudo_inv*jacb_reduced)*null_space_vector;
00428         null_space_proj = (null_space_proj.array() * null_proj_weights).matrix();
00429 
00430         // computing joint change
00431         delta_j = (jacb_pseudo_inv*tool_twist_reduced) + null_space_proj;
00432       }
00433       else
00434       {
00435         // computing joint change
00436         delta_j = (jacb_pseudo_inv*tool_twist_reduced);
00437       }
00438 
00439       // updating joint values
00440       joint_pose += (joint_update_rates* delta_j.array()).matrix();
00441       harmonize_joints(joint_pose);
00442 
00443       // updating tool pose
00444       robot_state->setJointGroupPositions(joint_group,joint_pose);
00445       robot_state->updateLinkTransforms();
00446       tool_current_pose = robot_state->getGlobalLinkTransform(tool_link);
00447 
00448       iteration_count++;
00449     }
00450 
00451     ROS_DEBUG_STREAM_COND(!converged,"Error tool twist "<<tool_twist.transpose());
00452 
00453     return converged;
00454   }
00455 
00466   static bool solveIK(moveit::core::RobotStatePtr robot_state, const std::string& group_name,const KinematicConfig& config, Eigen::VectorXd& joint_pose)
00467   {
00468 
00469     return solveIK(robot_state,
00470                    group_name,
00471                    config.constrained_dofs,
00472                    config.joint_update_rates,
00473                    config.cartesian_convergence_thresholds,
00474                    config.null_proj_weights,
00475                    config.null_space_vector,
00476                    config.max_iterations,
00477                    config.tool_goal_pose,
00478                    config.init_joint_pose,
00479                    joint_pose);
00480   }
00481 
00492   static bool computeJacobianNullSpace(moveit::core::RobotStatePtr state,std::string group,std::string tool_link,
00493                                        const Eigen::ArrayXi& constrained_dofs,const Eigen::VectorXd& joint_pose,
00494                                        Eigen::MatrixXd& jacb_nullspace)
00495   {
00496     using namespace Eigen;
00497     using namespace moveit::core;
00498 
00499     // robot state
00500     const JointModelGroup* joint_group = state->getJointModelGroup(group);
00501     state->setJointGroupPositions(joint_group,joint_pose);
00502     Affine3d tool_pose = state->getGlobalLinkTransform(tool_link);
00503 
00504     // jacobian calculations
00505     static MatrixXd jacb_transform(6,6);
00506     MatrixXd jacb, jacb_reduced, jacb_pseudo_inv;
00507     jacb_transform.setZero();
00508 
00509     if(!state->getJacobian(joint_group,state->getLinkModel(tool_link),Vector3d::Zero(),jacb))
00510     {
00511       ROS_ERROR("Failed to get Jacobian for link %s",tool_link.c_str());
00512       return false;
00513     }
00514 
00515     // transform jacobian rotational part to tool coordinates
00516     auto rot = tool_pose.inverse().rotation();
00517     jacb_transform.setZero();
00518     jacb_transform.block(0,0,3,3) = rot;
00519     jacb_transform.block(3,3,3,3) = rot;
00520     jacb = jacb_transform*jacb;
00521 
00522     // reduce jacobian and compute its pseudo inverse
00523     std::vector<int> indices;
00524     for(auto i = 0u; i < constrained_dofs.size(); i++)
00525     {
00526       if(constrained_dofs(i) != 0)
00527       {
00528         indices.push_back(i);
00529       }
00530     }
00531     reduceJacobian(jacb,indices,jacb_reduced);
00532     calculateDampedPseudoInverse(jacb_reduced,jacb_pseudo_inv,EPSILON,LAMBDA);
00533 
00534     int num_joints = joint_pose.size();
00535     jacb_nullspace = MatrixXd::Identity(num_joints,num_joints) - jacb_pseudo_inv*jacb_reduced;
00536 
00537     return true;
00538   }
00539 
00555   static bool solveIK(moveit::core::RobotStatePtr robot_state, const std::string& group_name, const Eigen::ArrayXi& constrained_dofs,
00556                const Eigen::ArrayXd& joint_update_rates,const Eigen::ArrayXd& cartesian_convergence_thresholds, int max_iterations,
00557                const Eigen::Affine3d& tool_goal_pose,const Eigen::VectorXd& init_joint_pose,
00558                Eigen::VectorXd& joint_pose)
00559   {
00560     using namespace Eigen;
00561     using namespace moveit::core;
00562 
00563     return solveIK(robot_state,group_name,constrained_dofs,joint_update_rates,cartesian_convergence_thresholds,
00564             ArrayXd::Zero(joint_update_rates.size()),VectorXd::Zero(joint_update_rates.size()),max_iterations,
00565             tool_goal_pose,init_joint_pose,joint_pose);
00566   }
00567 
00568 
00569 } // kinematics
00570 } // utils
00571 } // stomp_moveit
00572 
00573 
00574 
00575 #endif /* INDUSTRIAL_MOVEIT_STOMP_MOVEIT_INCLUDE_STOMP_MOVEIT_UTILS_KINEMATICS_H_ */


stomp_moveit
Author(s): Jorge Nicho
autogenerated on Sat Jun 8 2019 19:24:01