00001
00030 #include "constrained_ik/constraints/avoid_obstacles.h"
00031 #include <utility>
00032 #include <ros/ros.h>
00033 #include <pluginlib/class_list_macros.h>
00034 PLUGINLIB_EXPORT_CLASS(constrained_ik::constraints::AvoidObstacles, constrained_ik::Constraint)
00035
00036 const double DEFAULT_WEIGHT = 1.0;
00037 const double DEFAULT_MIN_DISTANCE = 0.1;
00038 const double DEFAULT_AVOIDANCE_DISTANCE = 0.3;
00039 const double DEFAULT_AMPLITUDE = 0.3;
00040 const double DEFAULT_SHIFT = 5.0;
00041 const double DEFAULT_ZERO_POINT = 10;
00042 const double DYNAMIC_WEIGHT_FUNCTION_CONSTANT = -13.86;
00044 namespace constrained_ik
00045 {
00046 namespace constraints
00047 {
00048
00049 using namespace Eigen;
00050 using namespace collision_detection;
00051 using Eigen::VectorXd;
00052 using Eigen::MatrixXd;
00053 using std::string;
00054 using std::vector;
00055
00056 AvoidObstacles::LinkAvoidance::LinkAvoidance(): weight_(DEFAULT_WEIGHT), min_distance_(DEFAULT_MIN_DISTANCE), avoidance_distance_(DEFAULT_AVOIDANCE_DISTANCE), amplitude_(DEFAULT_AMPLITUDE), jac_solver_(NULL) {}
00057 AvoidObstacles::LinkAvoidance::LinkAvoidance(std::string link_name): LinkAvoidance() {link_name_ = link_name;}
00058
00059 void AvoidObstacles::init(const Constrained_IK * ik)
00060 {
00061 Constraint::init(ik);
00062
00063 if (link_names_.size() == 0)
00064 {
00065 ik_->getLinkNames(link_names_);
00066 ROS_WARN("Avoid Obstacles: No links were specified therefore using all links in kinematic chain.");
00067 }
00068
00069 for (std::map<std::string, LinkAvoidance>::iterator it = links_.begin(); it != links_.end(); ++it)
00070 {
00071 it->second.num_robot_joints_ = ik_->getKin().numJoints();
00072 if (!ik_->getKin().getSubChain(it->second.link_name_, it->second.avoid_chain_))
00073 {
00074 ROS_ERROR_STREAM("Failed to initialize Avoid Obstalces constraint because"
00075 "it failed to create a KDL chain between URDF links: '" <<
00076 ik_->getKin().getRobotBaseLinkName() << "' and '" << it->second.link_name_ <<"'");
00077 initialized_ = false;
00078 return;
00079 }
00080 it->second.num_inboard_joints_ = it->second.avoid_chain_.getNrOfJoints();
00081 it->second.jac_solver_ = new KDL::ChainJntToJacSolver(it->second.avoid_chain_);
00082 }
00083
00084 std::vector<const robot_model::LinkModel*> tmp = ik_->getKin().getJointModelGroup()->getLinkModels();
00085 for (std::vector<const robot_model::LinkModel*>::const_iterator it = tmp.begin(); it < tmp.end(); ++it)
00086 {
00087 std::vector<std::string>::iterator name_it = std::find(link_names_.begin(), link_names_.end(), (*it)->getName());
00088 if (name_it != link_names_.end())
00089 link_models_.insert(*it);
00090 }
00091 }
00092
00093 void AvoidObstacles::loadParameters(const XmlRpc::XmlRpcValue &constraint_xml)
00094 {
00095 XmlRpc::XmlRpcValue local_xml = constraint_xml;
00096 std::vector<std::string> link_names;
00097 if (getParam(local_xml, "link_names", link_names))
00098 {
00099 std::vector<double> amplitude, minimum_distance, avoidance_distance, weight;
00100 if (getParam(local_xml, "amplitude", amplitude))
00101 {
00102 if (link_names.size()!=amplitude.size())
00103 {
00104 ROS_WARN("Abstacle Avoidance: amplitude memebr must be same size array as link_names member, default parameters will be used.");
00105 amplitude.clear();
00106 }
00107 }
00108 else
00109 {
00110 ROS_WARN("Abstacle Avoidance: Unable to retrieve amplitude member, default parameter will be used.");
00111 }
00112
00113 if (getParam(local_xml, "minimum_distance", minimum_distance))
00114 {
00115 if (link_names.size()!=minimum_distance.size())
00116 {
00117 ROS_WARN("Abstacle Avoidance: minimum_distance memebr must be same size array as link_names member, default parameters will be used.");
00118 minimum_distance.clear();
00119 }
00120 }
00121 else
00122 {
00123 ROS_WARN("Abstacle Avoidance: Unable to retrieve minimum_distance member, default parameter will be used.");
00124 }
00125
00126 if (getParam(local_xml, "avoidance_distance", avoidance_distance))
00127 {
00128 if (link_names.size()!=avoidance_distance.size())
00129 {
00130 ROS_WARN("Abstacle Avoidance: avoidance_distance memebr must be same size array as link_names member, default parameters will be used.");
00131 avoidance_distance.clear();
00132 }
00133 }
00134 else
00135 {
00136 ROS_WARN("Abstacle Avoidance: Unable to retrieve avoidance_distance member, default parameter will be used.");
00137 }
00138
00139 if (getParam(local_xml, "weights", weight))
00140 {
00141 if (link_names.size()!=weight.size())
00142 {
00143 ROS_WARN("Abstacle Avoidance: weights member must be same size array as link_names member, default parameters will be used.");
00144 weight.clear();
00145 }
00146 }
00147 else
00148 {
00149 ROS_WARN("Abstacle Avoidance: Unable to retrieve weight member, default parameter will be used.");
00150 }
00151
00152
00153 for (int i=0; i<link_names.size(); ++i)
00154 {
00155 addAvoidanceLink(link_names[i]);
00156 if (!amplitude.empty())
00157 {
00158 setAmplitude(link_names[i], amplitude[i]);
00159 }
00160 if (!minimum_distance.empty())
00161 {
00162 setMinDistance(link_names[i], minimum_distance[i]);
00163 }
00164 if (!avoidance_distance.empty())
00165 {
00166 setAvoidanceDistance(link_names[i], avoidance_distance[i]);
00167 }
00168 if (!weight.empty())
00169 {
00170 setWeight(link_names[i], weight[i]);
00171 }
00172 }
00173 }
00174 else
00175 {
00176 ROS_WARN("Abstacle Avoidance: Unable to retrieve link_names member, default parameter will be used.");
00177 }
00178 }
00179
00180 ConstraintResults AvoidObstacles::evalConstraint(const SolverState &state) const
00181 {
00182 ConstraintResults output;
00183 AvoidObstaclesData cdata(state, this);
00184 double dynamic_weight;
00185 for (std::map<std::string, LinkAvoidance>::const_iterator it = links_.begin(); it != links_.end(); ++it)
00186 {
00187 DistanceInfoMap::const_iterator dit = cdata.distance_info_map_.find(it->second.link_name_);
00188 if (dit != cdata.distance_info_map_.end() && dit->second.distance > 0)
00189 {
00190 dynamic_weight = std::exp(DYNAMIC_WEIGHT_FUNCTION_CONSTANT * (std::abs(dit->second.distance-cdata.distance_res_.minimum_distance.min_distance)/distance_threshold_));
00191 constrained_ik::ConstraintResults tmp;
00192 tmp.error = calcError(cdata, it->second) * it->second.weight_ * dynamic_weight;
00193 tmp.jacobian = calcJacobian(cdata, it->second) * it->second.weight_ * dynamic_weight;
00194 tmp.status = checkStatus(cdata, it->second);
00195 output.append(tmp);
00196 }
00197 }
00198
00199 return output;
00200 }
00201
00202 VectorXd AvoidObstacles::calcError(const AvoidObstacles::AvoidObstaclesData &cdata, const LinkAvoidance &link) const
00203 {
00204 Eigen::VectorXd dist_err;
00205 DistanceInfoMap::const_iterator it;
00206
00207 dist_err.resize(1,1);
00208 it = cdata.distance_info_map_.find(link.link_name_);
00209 if (it != cdata.distance_info_map_.end() && it->second.distance > 0)
00210 {
00211 double dist = it->second.distance;
00212 double scale_x = link.avoidance_distance_/(DEFAULT_ZERO_POINT + DEFAULT_SHIFT);
00213 double scale_y = link.amplitude_;
00214 dist_err(0, 0) = scale_y/(1.0 + std::exp((dist/scale_x) - DEFAULT_SHIFT));
00215 }
00216 else
00217 {
00218 ROS_DEBUG("Unable to retrieve distance info, couldn't find link with that name %s", link.link_name_.c_str());
00219 }
00220 return dist_err;
00221 }
00222
00223 MatrixXd AvoidObstacles::calcJacobian(const AvoidObstacles::AvoidObstaclesData &cdata, const LinkAvoidance &link) const
00224 {
00225 KDL::Jacobian link_jacobian(link.num_inboard_joints_);
00226 MatrixXd jacobian;
00227
00228
00229
00230 DistanceInfoMap::const_iterator it;
00231 jacobian.setZero(1, link.num_robot_joints_);
00232 it = cdata.distance_info_map_.find(link.link_name_);
00233 if (it != cdata.distance_info_map_.end() && it->second.distance > 0)
00234 {
00235 KDL::JntArray joint_array(link.num_inboard_joints_);
00236 for(int i=0; i<link.num_inboard_joints_; i++) joint_array(i) = cdata.state_.joints(i);
00237 link.jac_solver_->JntToJac(joint_array, link_jacobian);
00238
00239
00240 KDL::Vector link_point(it->second.link_point.x(), it->second.link_point.y(), it->second.link_point.z());
00241 link_jacobian.changeRefPoint(link_point);
00242
00243 MatrixXd j_tmp;
00244 basic_kin::BasicKin::KDLToEigen(link_jacobian,j_tmp);
00245
00246
00247
00248 jacobian.block(0, 0, 1, j_tmp.cols()) = it->second.avoidance_vector.transpose() * j_tmp.topRows(3);
00249 }
00250 else
00251 {
00252 ROS_DEBUG("Unable to retrieve distance info, couldn't find link with that name %s", link.link_name_.c_str());
00253 }
00254
00255 return jacobian;
00256 }
00257
00258 bool AvoidObstacles::checkStatus(const AvoidObstacles::AvoidObstaclesData &cdata, const LinkAvoidance &link) const
00259 {
00260 DistanceInfoMap::const_iterator it;
00261
00262 it = cdata.distance_info_map_.find(link.link_name_);
00263 if (it != cdata.distance_info_map_.end())
00264 {
00265 if(it->second.distance<link.min_distance_) return false;
00266 }
00267 else
00268 {
00269 ROS_DEBUG("couldn't find link with that name %s", link.link_name_.c_str());
00270 }
00271
00272 return true;
00273 }
00274
00275 AvoidObstacles::AvoidObstaclesData::AvoidObstaclesData(const SolverState &state, const AvoidObstacles *parent): ConstraintData(state), parent_(parent)
00276 {
00277 DistanceRequest distance_req(true, false, parent_->link_models_, state_.planning_scene->getAllowedCollisionMatrix(), parent_->distance_threshold_);
00278 distance_req.group_name = state.group_name;
00279 distance_res_.clear();
00280
00281 collision_detection::CollisionRequest collision_req;
00282 collision_detection::CollisionResult collision_res;
00283
00284 state.collision_robot->distanceSelf(distance_req, distance_res_, *state_.robot_state);
00285 state.collision_world->distanceRobot(distance_req, distance_res_, *state_.collision_robot, *state_.robot_state);
00286 if (distance_res_.collision)
00287 {
00288 collision_req.distance = false;
00289 collision_req.contacts = true;
00290 collision_req.max_contacts = parent_->link_models_.size() * 2.0;
00291 state.collision_robot->checkSelfCollision(collision_req, collision_res, *state_.robot_state, state_.planning_scene->getAllowedCollisionMatrix());
00292 state.collision_world->checkRobotCollision(collision_req, collision_res, *state.collision_robot, *state_.robot_state, state_.planning_scene->getAllowedCollisionMatrix());
00293 }
00294 Eigen::Affine3d tf = state_.robot_state->getGlobalLinkTransform(parent_->ik_->getKin().getRobotBaseLinkName()).inverse();
00295 getDistanceInfo(distance_res_.distance, distance_info_map_, tf);
00296 }
00297
00298 }
00299 }