basic_kin.cpp
Go to the documentation of this file.
00001 
00028 #include "constrained_ik/basic_kin.h"
00029 #include <ros/ros.h>
00030 #include <eigen_conversions/eigen_kdl.h>
00031 #include <kdl_parser/kdl_parser.hpp>
00032 #include <moveit/robot_model/robot_model.h>
00033 #include <urdf/model.h>
00034 
00035 
00036 namespace constrained_ik
00037 {
00038 namespace basic_kin
00039 {
00040 
00041 using Eigen::MatrixXd;
00042 using Eigen::VectorXd;
00043 
00044 bool BasicKin::calcFwdKin(const Eigen::VectorXd &joint_angles, Eigen::Affine3d &pose) const
00045 {
00046 //  int n = joint_angles.size();
00047   KDL::JntArray kdl_joints;
00048 
00049   if (!checkInitialized()) return false;
00050   if (!checkJoints(joint_angles)) return false;
00051 
00052   EigenToKDL(joint_angles, kdl_joints);
00053 
00054   // run FK solver
00055   KDL::Frame kdl_pose;
00056   if (fk_solver_->JntToCart(kdl_joints, kdl_pose) < 0)
00057   {
00058     ROS_ERROR("Failed to calculate FK");
00059     return false;
00060   }
00061 
00062   KDLToEigen(kdl_pose, pose);
00063   return true;
00064 }
00065 
00066 bool BasicKin::calcFwdKin(const Eigen::VectorXd &joint_angles,
00067                           const std::string &base,
00068                           const std::string &tip,
00069                           KDL::Frame &pose) const
00070 {
00071   // note, because the base and tip are different, fk_solver gets updated
00072     KDL::Chain chain;
00073     if (!kdl_tree_.getChain(base, tip, chain))
00074     {
00075       ROS_ERROR_STREAM("Failed to initialize KDL between URDF links: '" <<
00076                        base << "' and '" << tip <<"'");
00077       return false;
00078     }
00079 
00080     if (joint_angles.size() != chain.getNrOfJoints())
00081     {
00082         ROS_ERROR_STREAM("Number of joint angles [" << joint_angles.size() <<
00083                             "] must match number of joints [" << chain.getNrOfJoints() << "].");
00084         return false;
00085     }
00086 
00087     KDL::ChainFkSolverPos_recursive subchain_fk_solver(chain);
00088 
00089     KDL::JntArray joints;
00090     joints.data = joint_angles;
00091     if (subchain_fk_solver.JntToCart(joints, pose) < 0)
00092         return false;
00093     return true;
00094 }
00095 
00096 bool BasicKin::calcJacobian(const VectorXd &joint_angles, MatrixXd &jacobian) const
00097 {
00098   KDL::JntArray kdl_joints;
00099 
00100   if (!checkInitialized()) return false;
00101   if (!checkJoints(joint_angles)) return false;
00102 
00103   EigenToKDL(joint_angles, kdl_joints);
00104 
00105   // compute jacobian
00106   KDL::Jacobian kdl_jacobian(joint_angles.size());
00107   jac_solver_->JntToJac(kdl_joints, kdl_jacobian);
00108 
00109   KDLToEigen(kdl_jacobian, jacobian);
00110   return true;
00111 }
00112 
00113 bool BasicKin::checkJoints(const VectorXd &vec) const
00114 {
00115   if (vec.size() != robot_chain_.getNrOfJoints())
00116   {
00117     ROS_ERROR("Number of joint angles (%d) don't match robot_model (%d)",
00118               (int)vec.size(), robot_chain_.getNrOfJoints());
00119     return false;
00120   }
00121 
00122   bool jnt_bounds_ok = true;
00123   for (int i=0; i<vec.size(); ++i)
00124     if ( (vec[i] < joint_limits_(i,0)) || (vec(i) > joint_limits_(i,1)) )
00125     {
00126       ROS_ERROR("Joint %d is out-of-range (%g < %g < %g)",
00127                 i, joint_limits_(i,0), vec(i), joint_limits_(i,1));
00128       jnt_bounds_ok = false;
00129     }
00130   if (jnt_bounds_ok == false) return false;
00131 
00132   return true;
00133 }
00134 
00135 bool BasicKin::getJointNames(std::vector<std::string> &names) const
00136 {
00137     if (!initialized_)
00138     {
00139         ROS_ERROR("Kinematics must be initialized before retrieving joint names");
00140         return false;
00141     }
00142     names = joint_list_;
00143     return true;
00144 }
00145 
00146 bool BasicKin::getLinkNames(std::vector<std::string> &names) const
00147 {
00148     if (!initialized_)
00149     {
00150         ROS_ERROR("Kinematics must be initialized before retrieving link names");
00151         return false;
00152     }
00153     names = link_list_;
00154     return true;
00155 }
00156 
00157 int BasicKin::getJointNum(const std::string &joint_name) const
00158 {
00159     std::vector<std::string>::const_iterator it = find(joint_list_.begin(), joint_list_.end(), joint_name);
00160     if (it != joint_list_.end())
00161     {
00162         return it-joint_list_.begin();
00163     }
00164     return it-joint_list_.begin()+1;
00165 }
00166 
00167 int BasicKin::getLinkNum(const std::string &link_name) const
00168 {
00169     std::vector<std::string>::const_iterator it = find(link_list_.begin(), link_list_.end(), link_name);
00170     if (it != link_list_.end())
00171     {
00172         return it-link_list_.begin();
00173     }
00174     return it-link_list_.begin()+1;
00175 }
00176 
00177 bool BasicKin::init(const moveit::core::JointModelGroup* group)
00178 {
00179   initialized_ = false;
00180 
00181   if(group == NULL)
00182   {
00183     ROS_ERROR_STREAM("Null pointer to JointModelGroup");
00184     return false;
00185   }
00186 
00187   const robot_model::RobotModel& r  = group->getParentModel();
00188   const boost::shared_ptr<const urdf::ModelInterface> urdf = group->getParentModel().getURDF();
00189   base_name_ = group->getLinkModels().front()->getParentLinkModel()->getName();
00190   tip_name_ = group->getLinkModels().back()->getName();
00191 
00192   if (!urdf->getRoot())
00193   {
00194     ROS_ERROR("Invalid URDF in BasicKin::init call");
00195     return false;
00196   }
00197 
00198   if (!kdl_parser::treeFromUrdfModel(*urdf, kdl_tree_))
00199   {
00200     ROS_ERROR("Failed to initialize KDL from URDF model");
00201     return false;
00202   }
00203 
00204   if (!kdl_tree_.getChain(base_name_, tip_name_, robot_chain_))
00205   {
00206     ROS_ERROR_STREAM("Failed to initialize KDL between URDF links: '" <<
00207                      base_name_ << "' and '" << tip_name_ <<"'");
00208     return false;
00209   }
00210 
00211   joint_list_.resize(robot_chain_.getNrOfJoints());
00212   joint_limits_.resize(robot_chain_.getNrOfJoints(), 2);
00213 
00214   link_list_ = group->getLinkModelNames();
00215 
00216   for (int i=0, j=0; i<robot_chain_.getNrOfSegments(); ++i)
00217   {
00218     const KDL::Segment &seg = robot_chain_.getSegment(i);
00219     const KDL::Joint   &jnt = seg.getJoint();
00220     if (jnt.getType() == KDL::Joint::None) continue;
00221 
00222     joint_list_[j] = jnt.getName();
00223     joint_limits_(j,0) = urdf->getJoint(jnt.getName())->limits->lower;
00224     joint_limits_(j,1) = urdf->getJoint(jnt.getName())->limits->upper;
00225     j++;
00226   }
00227 
00228   fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(robot_chain_));
00229   jac_solver_.reset(new KDL::ChainJntToJacSolver(robot_chain_));
00230 
00231   initialized_ = true;
00232   group_ = group;
00233 
00234   return true;
00235 }
00236 
00237 void BasicKin::KDLToEigen(const KDL::Frame &frame, Eigen::Affine3d &transform)
00238 {
00239   transform.setIdentity();
00240 
00241   // translation
00242   for (size_t i=0; i<3; ++i)
00243     transform(i,3) = frame.p[i];
00244 
00245   // rotation matrix
00246   for (size_t i=0; i<9; ++i)
00247     transform(i/3, i%3) = frame.M.data[i];
00248 }
00249 
00250 void BasicKin::KDLToEigen(const KDL::Jacobian &jacobian, Eigen::MatrixXd &matrix)
00251 {
00252   matrix.resize(jacobian.rows(), jacobian.columns());
00253 
00254   for (size_t i=0; i<jacobian.rows(); ++i)
00255     for (size_t j=0; j<jacobian.columns(); ++j)
00256       matrix(i,j) = jacobian(i,j);
00257 }
00258 
00259 bool BasicKin::getSubChain(const std::string link_name, KDL::Chain &chain) const
00260 {
00261   if (!kdl_tree_.getChain(base_name_, link_name, chain))
00262   {
00263     ROS_ERROR_STREAM("Failed to initialize KDL between URDF links: '" <<
00264                      base_name_ << "' and '" << link_name <<"'");
00265     return false;
00266   }
00267   else
00268   {
00269     return true;
00270   }
00271 }
00272 
00273 bool BasicKin::linkTransforms(const VectorXd &joint_angles,
00274                               std::vector<KDL::Frame> &poses,
00275                               const std::vector<std::string> &link_names) const
00276 {
00277   if (!checkInitialized())
00278   {
00279     ROS_ERROR("BasicKin not initialized in linkTransforms()");
00280     return false;
00281   }
00282   if (!checkJoints(joint_angles))
00283   {
00284     ROS_ERROR("BasicKin checkJoints failed in linkTransforms()");
00285     return false;
00286   }
00287 
00288     std::vector<std::string> links(link_names);
00289     size_t n = links.size();
00290     if (!n) /*if link_names is an empty vector, return transforms of all links*/
00291     {
00292         links = link_list_;
00293         n = links.size();
00294     }
00295 
00296     KDL::JntArray kdl_joints;
00297     EigenToKDL(joint_angles, kdl_joints);
00298 
00299     // run FK solver
00300     poses.resize(n);
00301     int link_num;
00302     for (size_t ii=0; ii<n; ++ii)
00303     {
00304         link_num = getLinkNum(links[ii]);
00305         if (fk_solver_->JntToCart(kdl_joints, poses[ii], link_num<0? -1:link_num+1) < 0) /*root=0, link1=1, therefore add +1 to link num*/
00306         {
00307             ROS_ERROR_STREAM("Failed to calculate FK for joint " << n);
00308             return false;
00309         }
00310     }
00311     return true;
00312 }
00313 
00314 BasicKin& BasicKin::operator=(const BasicKin& rhs)
00315 {
00316   initialized_  = rhs.initialized_;
00317   robot_chain_  = rhs.robot_chain_;
00318   kdl_tree_ = rhs.kdl_tree_;
00319   joint_limits_ = rhs.joint_limits_;
00320   joint_list_ = rhs.joint_list_;
00321   link_list_ = rhs.link_list_;
00322   fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(robot_chain_));
00323   jac_solver_.reset(new KDL::ChainJntToJacSolver(robot_chain_));
00324   group_ = rhs.group_;
00325   base_name_ = rhs.base_name_;
00326   tip_name_ = rhs.tip_name_;
00327 
00328   return *this;
00329 }
00330 
00331 bool BasicKin::solvePInv(const MatrixXd &A, const VectorXd &b, VectorXd &x) const
00332 {
00333   const double eps = 0.00001;  // TODO: Turn into class member var
00334   const double lambda = 0.01;  // TODO: Turn into class member var
00335 
00336   if ( (A.rows() == 0) || (A.cols() == 0) )
00337   {
00338     ROS_ERROR("Empty matrices not supported in solvePinv()");
00339     return false;
00340   }
00341 
00342   if ( A.rows() != b.size() )
00343   {
00344     ROS_ERROR("Matrix size mismatch: A(%ld,%ld), b(%ld)",
00345               A.rows(), A.cols(), b.size());
00346     return false;
00347   }
00348 
00349   //Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are real)
00350   //in order to solve Ax=b -> x*=A+ b
00351   Eigen::JacobiSVD<MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
00352   const MatrixXd &U = svd.matrixU();
00353   const VectorXd &Sv = svd.singularValues();
00354   const MatrixXd &V = svd.matrixV();
00355 
00356   // calculate the reciprocal of Singular-Values
00357   // damp inverse with lambda so that inverse doesn't oscillate near solution
00358   size_t nSv = Sv.size();
00359   VectorXd inv_Sv(nSv);
00360   for(size_t i=0; i<nSv; ++i)
00361   {
00362     if (fabs(Sv(i)) > eps)
00363       inv_Sv(i) = 1/Sv(i);
00364     else
00365       inv_Sv(i) = Sv(i) / (Sv(i)*Sv(i) + lambda*lambda);
00366   }
00367   x = V * inv_Sv.asDiagonal() * U.transpose() * b;
00368   return true;
00369 }
00370 
00371 bool BasicKin::dampedPInv(const MatrixXd &A, MatrixXd &P, const double eps, const double lambda)
00372 {
00373   if ( (A.rows() == 0) || (A.cols() == 0) )
00374   {
00375     ROS_ERROR("Empty matrices not supported in dampedPInv()");
00376     return false;
00377   }
00378 
00379   //Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are real)
00380   //in order to solve Ax=b -> x*=A+ b
00381   Eigen::JacobiSVD<MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
00382   const MatrixXd &U = svd.matrixU();
00383   const VectorXd &Sv = svd.singularValues();
00384   const MatrixXd &V = svd.matrixV();
00385 
00386   // calculate the reciprocal of Singular-Values
00387   // damp inverse with lambda so that inverse doesn't oscillate near solution
00388   size_t nSv = Sv.size();
00389   VectorXd inv_Sv(nSv);
00390   for(size_t i=0; i<nSv; ++i)
00391   {
00392     if (fabs(Sv(i)) > eps)
00393       inv_Sv(i) = 1/Sv(i);
00394     else
00395     {
00396       inv_Sv(i) = Sv(i) / (Sv(i)*Sv(i) + lambda*lambda);
00397     }
00398   }
00399   P = V * inv_Sv.asDiagonal() * U.transpose();
00400   return true;
00401 }
00402 
00403 } // namespace basic_kin
00404 } // namespace constrained_ik
00405 


constrained_ik
Author(s): Chris Lewis , Jeremy Zoss , Dan Solomon
autogenerated on Sat Jun 8 2019 19:23:45