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
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
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
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
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
00242 for (size_t i=0; i<3; ++i)
00243 transform(i,3) = frame.p[i];
00244
00245
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)
00291 {
00292 links = link_list_;
00293 n = links.size();
00294 }
00295
00296 KDL::JntArray kdl_joints;
00297 EigenToKDL(joint_angles, kdl_joints);
00298
00299
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)
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;
00334 const double lambda = 0.01;
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
00350
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
00357
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
00380
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
00387
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 }
00404 }
00405