00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
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
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
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
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
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
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
00254
00255
00256
00257
00258 return true;
00259 }
00260
00261 void BasicKin::KDLToEigen(const KDL::Frame &frame, Eigen::Affine3d &transform)
00262 {
00263 transform.setIdentity();
00264
00265
00266 for (size_t i=0; i<3; ++i)
00267 transform(i,3) = frame.p[i];
00268
00269
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)
00293 {
00294 links = link_list_;
00295 n = links.size();
00296 }
00297
00298 KDL::JntArray kdl_joints;
00299 EigenToKDL(joint_angles, kdl_joints);
00300
00301
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)
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;
00333 const double lambda = 0.01;
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
00349
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
00356
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
00368
00369
00370 return true;
00371 }
00372
00373 }
00374 }
00375