basic_kin.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Apache License)
00003  *
00004  * Copyright (c) 2013, Southwest Research Institute
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *   http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 
00020 #include "constrained_ik/basic_kin.h"
00021 #include <ros/ros.h>
00022 #include <eigen_conversions/eigen_kdl.h>
00023 #include <kdl_parser/kdl_parser.hpp>
00024 
00025 
00026 namespace constrained_ik
00027 {
00028 namespace basic_kin
00029 {
00030 
00031 using Eigen::MatrixXd;
00032 using Eigen::VectorXd;
00033 
00034 bool BasicKin::calcFwdKin(const VectorXd &joint_angles, Eigen::Affine3d &pose) const
00035 {
00036 //  int n = joint_angles.size();
00037   KDL::JntArray kdl_joints;
00038 
00039   if (!checkInitialized()) return false;
00040   if (!checkJoints(joint_angles)) return false;
00041 
00042   EigenToKDL(joint_angles, kdl_joints);
00043 
00044   // run FK solver
00045   KDL::Frame kdl_pose;
00046   if (fk_solver_->JntToCart(kdl_joints, kdl_pose) < 0)
00047   {
00048     ROS_ERROR("Failed to calculate FK");
00049     return false;
00050   }
00051 
00052   KDLToEigen(kdl_pose, pose);
00053   return true;
00054 }
00055 
00056 bool BasicKin::calcFwdKin(const VectorXd &joint_angles,
00057                           const std::string &base,
00058                           const std::string &tip,
00059                           KDL::Frame &pose)
00060 {
00061     KDL::Chain chain;
00062     if (!kdl_tree_.getChain(base, tip, chain))
00063     {
00064       ROS_ERROR_STREAM("Failed to initialize KDL between URDF links: '" <<
00065                        base << "' and '" << tip <<"'");
00066       return false;
00067     }
00068 
00069     if (joint_angles.size() != chain.getNrOfJoints())
00070     {
00071         ROS_ERROR_STREAM("Number of joint angles [" << joint_angles.size() <<
00072                             "] must match number of joints [" << chain.getNrOfJoints() << "].");
00073         return false;
00074     }
00075 
00076     subchain_fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(chain));
00077 
00078     KDL::JntArray joints;
00079     joints.data = joint_angles;
00080     if (subchain_fk_solver_->JntToCart(joints, pose) < 0)
00081         return false;
00082     return true;
00083 }
00084 
00085 bool BasicKin::calcJacobian(const VectorXd &joint_angles, MatrixXd &jacobian) const
00086 {
00087   KDL::JntArray kdl_joints;
00088 
00089   if (!checkInitialized()) return false;
00090   if (!checkJoints(joint_angles)) return false;
00091 
00092   EigenToKDL(joint_angles, kdl_joints);
00093 
00094   // compute jacobian
00095   KDL::Jacobian kdl_jacobian(joint_angles.size());
00096   jac_solver_->JntToJac(kdl_joints, kdl_jacobian);
00097 
00098   KDLToEigen(kdl_jacobian, jacobian);
00099   return true;
00100 }
00101 
00102 bool BasicKin::checkJoints(const VectorXd &vec) const
00103 {
00104   if (vec.size() != robot_chain_.getNrOfJoints())
00105   {
00106     ROS_ERROR("Number of joint angles (%d) don't match robot_model (%d)",
00107               (int)vec.size(), robot_chain_.getNrOfJoints());
00108     return false;
00109   }
00110 
00111   bool jnt_bounds_ok = true;
00112   for (int i=0; i<vec.size(); ++i)
00113     if ( (vec[i] < joint_limits_(i,0)) || (vec(i) > joint_limits_(i,1)) )
00114     {
00115       ROS_ERROR("Joint %d is out-of-range (%g < %g < %g)",
00116                 i, joint_limits_(i,0), vec(i), joint_limits_(i,1));
00117       jnt_bounds_ok = false;
00118     }
00119   if (jnt_bounds_ok == false) return false;
00120 
00121   return true;
00122 }
00123 
00124 bool BasicKin::getJointNames(std::vector<std::string> &names) const
00125 {
00126     if (!initialized_)
00127     {
00128         ROS_ERROR("Kinematics must be initialized before retrieving joint names");
00129         return false;
00130     }
00131     names = joint_list_;
00132     return true;
00133 }
00134 
00135 //bool BasicKin::getJointNames(const KDL::Chain &chain, 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 //
00143 //    unsigned int n = chain.getNrOfJoints();
00144 //    names.resize(n);
00145 //
00146 //    KDL::Joint joint;
00147 //    for (unsigned int ii=0; ii<n; ++ii)
00148 //    {
00149 //        joint = chain.getSegment(ii).getJoint();
00150 //        if (joint.getType() != joint.None)
00151 //            names[ii] = joint.getName();
00152 //    }
00153 //    return true;
00154 //}
00155 
00156 bool BasicKin::getLinkNames(std::vector<std::string> &names) const
00157 {
00158     if (!initialized_)
00159     {
00160         ROS_ERROR("Kinematics must be initialized before retrieving link names");
00161         return false;
00162     }
00163     names = link_list_;
00164     return true;
00165 }
00166 
00167 //bool BasicKin::getLinkNames(const KDL::Chain &chain, std::vector<std::string> &names) const
00168 //{
00169 //    if (!initialized_)
00170 //    {
00171 //        ROS_ERROR("Kinematics must be initialized before retrieving link names");
00172 //        return false;
00173 //    }
00174 //
00175 //    unsigned int n = chain.getNrOfSegments();
00176 //    names.resize(n);
00177 //
00178 //    for (unsigned int ii=0; ii<n; ++ii)
00179 //    {
00180 //        names[ii] = robot_chain_.getSegment(ii).getName();
00181 //    }
00182 //    return true;
00183 //}
00184 
00185 int BasicKin::getJointNum(const std::string &joint_name) const
00186 {
00187     std::vector<std::string>::const_iterator it = find(joint_list_.begin(), joint_list_.end(), joint_name);
00188     if (it != joint_list_.end())
00189     {
00190         return it-joint_list_.begin();
00191     }
00192     return it-joint_list_.begin()+1;
00193 }
00194 
00195 int BasicKin::getLinkNum(const std::string &link_name) const
00196 {
00197     std::vector<std::string>::const_iterator it = find(link_list_.begin(), link_list_.end(), link_name);
00198     if (it != link_list_.end())
00199     {
00200         return it-link_list_.begin();
00201     }
00202     return it-link_list_.begin()+1;
00203 }
00204 
00205 bool BasicKin::init(const urdf::Model &robot,
00206                    const std::string &base_name, const std::string &tip_name)
00207 {
00208   initialized_ = false;
00209 
00210   if (!robot.getRoot())
00211   {
00212     ROS_ERROR("Invalid URDF in BasicKin::init call");
00213     return false;
00214   }
00215 
00216 //  KDL::Tree tree;
00217   if (!kdl_parser::treeFromUrdfModel(robot, kdl_tree_))
00218   {
00219     ROS_ERROR("Failed to initialize KDL from URDF model");
00220     return false;
00221   }
00222 
00223   if (!kdl_tree_.getChain(base_name, tip_name, robot_chain_))
00224   {
00225     ROS_ERROR_STREAM("Failed to initialize KDL between URDF links: '" <<
00226                      base_name << "' and '" << tip_name <<"'");
00227     return false;
00228   }
00229 
00230   joint_list_.resize(robot_chain_.getNrOfJoints());
00231   link_list_.resize(robot_chain_.getNrOfSegments());
00232   joint_limits_.resize(robot_chain_.getNrOfJoints(), 2);
00233 
00234   for (int i=0, j=0; i<robot_chain_.getNrOfSegments(); ++i)
00235   {
00236     const KDL::Segment &seg = robot_chain_.getSegment(i);
00237     link_list_[i] = seg.getName();
00238 
00239     const KDL::Joint   &jnt = seg.getJoint();
00240     if (jnt.getType() == KDL::Joint::None) continue;
00241 
00242     joint_list_[j] = jnt.getName();
00243     joint_limits_(j,0) = robot.getJoint(jnt.getName())->limits->lower;
00244     joint_limits_(j,1) = robot.getJoint(jnt.getName())->limits->upper;
00245     j++;
00246   }
00247 
00248   fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(robot_chain_));
00249   jac_solver_.reset(new KDL::ChainJntToJacSolver(robot_chain_));
00250 
00251   initialized_ = true;
00252 
00253 //  for (size_t ii=0; ii<joint_list_.size(); ++ii)
00254 //      ROS_INFO_STREAM("Added joint " << joint_list_[ii]);
00255 //  for (size_t ii=0; ii<link_list_.size(); ++ii)
00256 //      ROS_INFO_STREAM("Added link " <<link_list_[ii]);
00257 
00258   return true;
00259 }
00260 
00261 void BasicKin::KDLToEigen(const KDL::Frame &frame, Eigen::Affine3d &transform)
00262 {
00263   transform.setIdentity();
00264 
00265   // translation
00266   for (size_t i=0; i<3; ++i)
00267     transform(i,3) = frame.p[i];
00268 
00269   // rotation matrix
00270   for (size_t i=0; i<9; ++i)
00271     transform(i/3, i%3) = frame.M.data[i];
00272 }
00273 
00274 void BasicKin::KDLToEigen(const KDL::Jacobian &jacobian, MatrixXd &matrix)
00275 {
00276   matrix.resize(jacobian.rows(), jacobian.columns());
00277 
00278   for (size_t i=0; i<jacobian.rows(); ++i)
00279     for (size_t j=0; j<jacobian.columns(); ++j)
00280       matrix(i,j) = jacobian(i,j);
00281 }
00282 
00283 bool BasicKin::linkTransforms(const VectorXd &joint_angles,
00284                               std::vector<KDL::Frame> &poses,
00285                               const std::vector<std::string> &link_names) const
00286 {
00287     if (!checkInitialized()) return false;
00288     if (!checkJoints(joint_angles)) return false;
00289 
00290     std::vector<std::string> links(link_names);
00291     size_t n = links.size();
00292     if (!n) /*if link_names is an empty vector, return transforms of all links*/
00293     {
00294         links = link_list_;
00295         n = links.size();
00296     }
00297 
00298     KDL::JntArray kdl_joints;
00299     EigenToKDL(joint_angles, kdl_joints);
00300 
00301     // run FK solver
00302     poses.resize(n);
00303     int link_num;
00304     for (size_t ii=0; ii<n; ++ii)
00305     {
00306         link_num = getLinkNum(links[ii]);
00307         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*/
00308         {
00309             ROS_ERROR_STREAM("Failed to calculate FK for joint " << n);
00310             return false;
00311         }
00312     }
00313     return true;
00314 }
00315 
00316 BasicKin& BasicKin::operator=(const BasicKin& rhs)
00317 {
00318   initialized_  = rhs.initialized_;
00319   robot_chain_  = rhs.robot_chain_;
00320   kdl_tree_ = rhs.kdl_tree_;
00321   joint_limits_ = rhs.joint_limits_;
00322   joint_list_ = rhs.joint_list_;
00323   link_list_ = rhs.link_list_;
00324   fk_solver_.reset(new KDL::ChainFkSolverPos_recursive(robot_chain_));
00325   jac_solver_.reset(new KDL::ChainJntToJacSolver(robot_chain_));
00326 
00327   return *this;
00328 }
00329 
00330 bool BasicKin::solvePInv(const MatrixXd &A, const VectorXd &b, VectorXd &x) const
00331 {
00332   const double eps = 0.00001;  // TODO: Turn into class member var
00333   const double lambda = 0.01;  // TODO: Turn into class member var
00334 
00335   if ( (A.rows() == 0) || (A.cols() == 0) )
00336   {
00337     ROS_ERROR("Empty matrices not supported");
00338     return false;
00339   }
00340 
00341   if ( A.rows() != b.size() )
00342   {
00343     ROS_ERROR("Matrix size mismatch: A(%ld,%ld), b(%ld)",
00344               A.rows(), A.cols(), b.size());
00345     return false;
00346   }
00347 
00348   //Calculate A+ (pseudoinverse of A) = V S+ U*, where U* is Hermition of U (just transpose if all values of U are real)
00349   //in order to solve Ax=b -> x*=A+ b
00350   Eigen::JacobiSVD<MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
00351   const MatrixXd &U = svd.matrixU();
00352   const VectorXd &Sv = svd.singularValues();
00353   const MatrixXd &V = svd.matrixV();
00354 
00355   // calculate the reciprocal of Singular-Values
00356   // damp inverse with lambda so that inverse doesn't oscillate near solution
00357   size_t nSv = Sv.size();
00358   VectorXd inv_Sv(nSv);
00359   for(size_t i=0; i<nSv; ++i)
00360   {
00361     if (fabs(Sv(i)) > eps)
00362       inv_Sv(i) = 1/Sv(i);
00363     else
00364       inv_Sv(i) = Sv(i) / (Sv(i)*Sv(i) + lambda*lambda);
00365   }
00366   x = V * inv_Sv.asDiagonal() * U.transpose() * b;
00367 //  ROS_INFO_STREAM("Singular values:\n" << Sv.transpose());
00368 //  ROS_INFO_STREAM("U,V:\n" << U << std::endl << std::endl << V);
00369 
00370   return true;
00371 }
00372 
00373 } // namespace basic_kin
00374 } // namespace constrained_ik
00375 


constrained_ik
Author(s): Chris Lewis , Jeremy Zoss , Dan Solomon
autogenerated on Mon Oct 6 2014 00:52:26