constrained_ik.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 #include "constrained_ik/constrained_ik.h"
00020 #include "constrained_ik/constraint_group.h"
00021 #include <ros/ros.h>
00022 
00023 namespace constrained_ik
00024 {
00025 
00026 using Eigen::MatrixXd;
00027 using Eigen::VectorXd;
00028 using Eigen::Affine3d;
00029 
00030 Constrained_IK::Constrained_IK()
00031 {
00032   initialized_ = false;
00033   joint_update_gain_ = 0.09;        //default joint update gain
00034   max_iter_ = 500;                  //default max_iter
00035   joint_convergence_tol_ = 0.0001;   //default convergence tolerance
00036   debug_ = false;
00037 }
00038 
00039 Eigen::VectorXd Constrained_IK::calcConstraintError()
00040 {
00041   return constraints_.calcError();
00042 }
00043 
00044 Eigen::MatrixXd Constrained_IK::calcConstraintJacobian()
00045 {
00046   return constraints_.calcJacobian();
00047 }
00048 
00049 void Constrained_IK::calcInvKin(const Eigen::Affine3d &goal, const Eigen::VectorXd &joint_seed, Eigen::VectorXd &joint_angles)
00050 {
00051   if (!checkInitialized())
00052     throw std::runtime_error("Must call init() before using Constrained_IK");
00053   //TODO should goal be checked here instead of in reset()?
00054 
00055   // initialize state
00056   joint_angles = joint_seed;  // initialize result to seed value
00057   reset(goal, joint_seed);    // reset state vars for this IK solve
00058   update(joint_angles);       // update current state
00059 
00060   // iterate until solution converges (or aborted)
00061   while (!checkStatus())
00062   {
00063     // calculate a Jacobian (relating joint-space updates/deltas to cartesian-space errors/deltas)
00064     // and the associated cartesian-space error/delta vector
00065     MatrixXd J  = calcConstraintJacobian();
00066     VectorXd err = calcConstraintError();
00067 
00068     // solve for the resulting joint-space update
00069     VectorXd dJoint;
00070 
00071     kin_.solvePInv(J, err, dJoint);
00072 
00073     // update joint solution by the calculated update (or a partial fraction)
00074     joint_angles += dJoint * joint_update_gain_;
00075     clipToJointLimits(joint_angles);
00076 
00077     // re-update internal state variables
00078     update(joint_angles);
00079   }
00080 
00081   ROS_INFO_STREAM("IK solution: " << joint_angles.transpose());
00082 }
00083 
00084 bool Constrained_IK::checkStatus() const
00085 {
00086   // check constraints for completion
00087   if (constraints_.checkStatus())
00088     return true;
00089 
00090   // check maximum iterations
00091   if (state_.iter > max_iter_)
00092     throw std::runtime_error("Maximum iterations reached.  IK solution may be invalid.");
00093 
00094   // check for joint convergence
00095   //   - this is an error: joints stabilize, but goal pose not reached
00096   if (state_.joints_delta.cwiseAbs().maxCoeff() < joint_convergence_tol_)
00097   {
00098 //        ROS_ERROR_STREAM("Reached " << state_.iter << " / " << max_iter_ << " iterations before convergence.");
00099 //        throw std::runtime_error("Iteration converged before goal reached.  IK solution may be invalid");
00100 
00101           ROS_WARN_STREAM("Reached " << state_.iter << " / " << max_iter_ << " iterations before convergence.");
00102       return true;
00103   }
00104 
00105   return false;
00106 }
00107 
00108 void Constrained_IK::clearConstraintList()
00109 {
00110   constraints_.clear();
00111 }
00112 
00113 void Constrained_IK::clipToJointLimits(Eigen::VectorXd &joints)
00114 {
00115   const MatrixXd limits = kin_.getLimits();
00116   const VectorXd orig_joints(joints);
00117 
00118   if (joints.size() != limits.rows())
00119     throw std::invalid_argument("clipToJointLimits: Unexpected number of joints");
00120 
00121   for (size_t i=0; i<limits.rows(); ++i)
00122   {
00123     joints[i] = std::max(limits(i,0), std::min(limits(i,1), joints[i]));
00124   }
00125   if (debug_ && !joints.isApprox(orig_joints))
00126       ROS_WARN("Joints have been clipped");
00127 }
00128 
00129 void Constrained_IK::init(const urdf::Model &robot, const std::string &base_name, const std::string &tip_name)
00130 {
00131   basic_kin::BasicKin kin;
00132   if (! kin.init(robot, base_name, tip_name))
00133     throw std::runtime_error("Failed to initialize BasicKin");
00134 
00135   init(kin);
00136 }
00137 
00138 void Constrained_IK::init(const basic_kin::BasicKin &kin)
00139 {
00140   if (!kin.checkInitialized())
00141     throw std::invalid_argument("Input argument 'BasicKin' must be initialized");
00142 
00143   kin_ = kin;
00144   initialized_ = true;
00145   constraints_.init(this);
00146 }
00147 
00148 double Constrained_IK::rangedAngle(double angle)
00149 {
00150     angle = copysign(fmod(fabs(angle),2.0*M_PI), angle);
00151     if (angle < -M_PI) return angle+2.*M_PI;
00152     if (angle > M_PI)  return angle-2.*M_PI;
00153     return angle;
00154 }
00155 
00156 void Constrained_IK::reset(const Eigen::Affine3d &goal, const Eigen::VectorXd &joint_seed)
00157 {
00158   if (!kin_.checkJoints(joint_seed))
00159     throw std::invalid_argument("Seed doesn't match kinematic model");
00160 
00161   if (!goal.matrix().block(0,0,3,3).isUnitary(1e-6))
00162         throw std::invalid_argument("Goal pose not proper affine");
00163 
00164   state_.reset(goal, joint_seed);  // reset state
00165   constraints_.reset();            // reset constraints
00166 
00167 }
00168 
00169 void Constrained_IK::update(const Eigen::VectorXd &joints)
00170 {
00171   // update maximum iterations
00172   state_.iter++;
00173 
00174   // update joint convergence
00175   state_.joints_delta = joints - state_.joints;
00176   state_.joints = joints;
00177   kin_.calcFwdKin(joints, state_.pose_estimate);
00178 
00179   if (debug_)
00180       iteration_path_.push_back(joints);
00181 
00182   constraints_.update(state_);
00183 }
00184 
00185 } // namespace constrained_ik
00186 


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