00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 #include <costmap_trajectory_checker/costmap_trajectory_checker.h>
00039 #include "nav_msgs/Path.h"
00040 #include <ros/console.h>
00041 #include <sys/time.h>
00042 
00043 using namespace std;
00044 using namespace costmap_2d;
00045 
00046 CostmapTrajectoryChecker::CostmapTrajectoryChecker() :
00047                 world_model_(NULL), costmap_ros_(NULL), initialized_(false) {
00048 }
00049 
00050 CostmapTrajectoryChecker::CostmapTrajectoryChecker(Costmap2DROS* costmap_ros, std::string topic) :
00051         world_model_(NULL), costmap_ros_(NULL), initialized_(false)
00052 {
00053         initialize(costmap_ros, topic);
00054 }
00055 
00056 CostmapTrajectoryChecker::CostmapTrajectoryChecker(
00057                 costmap_2d::Costmap2DROS* costmap_ros,
00058                 std::string frame_id,
00059                 std::vector<geometry_msgs::Point> footprint,
00060                 std::string topic) :
00061                 world_model_(NULL), costmap_ros_(NULL), initialized_(false)
00062 {
00063         initialize(costmap_ros, topic);
00064         robot_frame_ = frame_id;
00065         footprint_spec_ = footprint;
00066 }
00067 
00068 CostmapTrajectoryChecker::CostmapTrajectoryChecker(const CostmapTrajectoryChecker &checker) : world_model_(NULL), costmap_ros_(NULL), initialized_(false)
00069 {
00070         if(this == &checker)
00071               return;
00072 
00073         initialize(checker.costmap_ros_, checker.traj_topic_name_);
00074         robot_frame_ = checker.robot_frame_;
00075         footprint_spec_ = checker.footprint_spec_;
00076 }
00077 
00078 CostmapTrajectoryChecker& CostmapTrajectoryChecker::operator=(const CostmapTrajectoryChecker &checker)
00079 {
00080         if(this == &checker)
00081               return *this;
00082 
00083         initialize(checker.costmap_ros_, checker.traj_topic_name_);
00084         robot_frame_ = checker.robot_frame_;
00085         footprint_spec_ = checker.footprint_spec_;
00086         return *this;
00087 }
00088 
00089 CostmapTrajectoryChecker::~CostmapTrajectoryChecker(){}
00090 
00091 void CostmapTrajectoryChecker::initialize(Costmap2DROS* costmap_ros, std::string topic)
00092 {
00093         if (!initialized_) {
00094                 costmap_ros_ = costmap_ros;
00095 
00096                 
00097                 costmap_ros_->getCostmapCopy(costmap_);
00098 
00099                 robot_frame_ = costmap_ros_->getBaseFrameID();
00100                 global_frame_ = costmap_ros_->getGlobalFrameID();
00101                 footprint_spec_ = costmap_ros_->getRobotFootprint();
00102 
00103                 
00104                 inscribed_radius_ = costmap_ros_->getInscribedRadius();
00105                 circumscribed_radius_ = costmap_ros_->getCircumscribedRadius();
00106                 inflation_radius_ = costmap_ros_->getInflationRadius();
00107 
00108                 world_model_ = new base_local_planner::CostmapModel(costmap_);
00109 
00110                 setPubTopic(topic);
00111 
00112                 initialized_ = true;
00113         }
00114         else
00115                 ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00116 }
00117 
00118 void CostmapTrajectoryChecker::setFootprint(const std::vector<
00119                 geometry_msgs::Point> &footprint) {
00120         footprint_spec_ = footprint;
00121 }
00122 
00123 void CostmapTrajectoryChecker::setFootprint(double length, double width, double x_offset, double y_offset)
00124 {
00125         footprint_spec_.resize(4);
00126         footprint_spec_[0].x = -x_offset;
00127         footprint_spec_[0].y = -y_offset;
00128         footprint_spec_[1].x = -x_offset + length;
00129         footprint_spec_[1].y = -y_offset;
00130         footprint_spec_[2].x = -x_offset + length;
00131         footprint_spec_[2].y = -y_offset + width;
00132         footprint_spec_[3].x = -x_offset;
00133         footprint_spec_[3].y = -y_offset + width;
00134 }
00135 
00136 std::vector<geometry_msgs::Point> CostmapTrajectoryChecker::getFootprint()
00137 {
00138         return footprint_spec_;
00139 }
00140 
00141 void CostmapTrajectoryChecker::setGlobalFrameID(std::string frame_id)
00142 {
00143         global_frame_ = frame_id;
00144 }
00145 
00146 
00147 void CostmapTrajectoryChecker::setRobotFrameID(std::string frame_id)
00148 {
00149         robot_frame_ = frame_id;
00150 }
00151 
00152 std::string CostmapTrajectoryChecker::getGlobalFrameID()
00153 {
00154         return global_frame_;
00155 }
00156 
00157 std::string CostmapTrajectoryChecker::getRobotFrameID()
00158 {
00159         return robot_frame_;
00160 }
00161 
00162 void CostmapTrajectoryChecker::setPubTopic(std::string topic)
00163 {
00164         traj_topic_name_ = topic;
00165         if (traj_topic_name_ != "")
00166                 traj_pub_ = nh_.advertise<nav_msgs::Path> (traj_topic_name_, 1);
00167 }
00168 
00169 std::string CostmapTrajectoryChecker::getPubTopic()
00170 {
00171         return traj_topic_name_;
00172 }
00173 
00174 void CostmapTrajectoryChecker::generateTrajectory(
00175                 const geometry_msgs::Pose2D &start_pose,
00176                 const geometry_msgs::Twist &vel, unsigned int num_steps, double dt,
00177                 std::vector<geometry_msgs::Pose2D>& traj) {
00178 
00179         traj.resize(0);
00180         traj.push_back(start_pose);
00181         geometry_msgs::Pose2D cur_pose = start_pose;
00182 
00183         for (unsigned int i = 1; i < num_steps; ++i) {
00184                 integratePose(vel, dt, cur_pose);
00185                 ROS_DEBUG("dt: %f, cur_pose: %f %f %f",dt,cur_pose.x,cur_pose.y,cur_pose.theta);
00186                 traj.push_back(cur_pose);
00187         }
00188 }
00189 
00190 double CostmapTrajectoryChecker::checkTrajectory(const std::vector<geometry_msgs::Pose2D>& traj, bool update_map, bool clear_footprint)
00191 {
00192     
00193         if (update_map)
00194                 costmap_ros_->getCostmapCopy(costmap_);
00195 
00196         if (clear_footprint) {
00197                 vector<geometry_msgs::Point> oriented_footprint;
00198                 getOrientedFootprint(traj[0], oriented_footprint);
00199 
00200                 
00201                 if(!costmap_.setConvexPolygonCost(oriented_footprint, costmap_2d::FREE_SPACE)) {
00202                         ROS_ERROR("Could not clear robot footprint: ");
00203                         for (uint i = 0; i < oriented_footprint.size(); ++i)
00204                                 ROS_ERROR("oriented_footprint: %.2lf %.2lf %.2lf", oriented_footprint[i].x, oriented_footprint[i].y, oriented_footprint[i].z);
00205                         return false;
00206                 }
00207         }
00208 
00209         double cost = -1.0;
00210         for (unsigned int i = 0; i < traj.size(); ++i) {
00211                 double newcost = footprintCost(traj[i]);
00212                 
00213                 cost = newcost < 0 ? -1.0 : std::max(cost, newcost);
00214         }
00215 
00216         if (traj_topic_name_ != "")
00217                 publishTrajectory(traj);
00218 
00219         ROS_DEBUG("trajectory cost = %.4lf", cost);
00220         return cost;
00221 }
00222 
00223 bool CostmapTrajectoryChecker::clearFootprint(const geometry_msgs::Pose2D &traj, bool update_map)
00224 {
00225     
00226   if(update_map)
00227     costmap_ros_->getCostmapCopy(costmap_);
00228   
00229   vector<geometry_msgs::Point> oriented_footprint;
00230   getOrientedFootprint(traj, oriented_footprint);
00231   
00232   
00233   if(!costmap_.setConvexPolygonCost(oriented_footprint, costmap_2d::FREE_SPACE)) 
00234   {
00235       ROS_ERROR("Could not clear robot footprint: ");
00236       for (uint i = 0; i < oriented_footprint.size(); ++i)
00237         ROS_ERROR("oriented_footprint: %.2lf %.2lf %.2lf", oriented_footprint[i].x, oriented_footprint[i].y, oriented_footprint[i].z);
00238       return false;     
00239   }
00240   return true;
00241 }
00242 
00243 bool CostmapTrajectoryChecker::clearFootprint(bool update_map)
00244 {
00245     
00246   if(update_map)
00247     costmap_ros_->getCostmapCopy(costmap_);
00248   
00249   vector<geometry_msgs::Point> oriented_footprint;
00250   geometry_msgs::Pose2D pose;
00251   getRobotPose(pose);
00252   getOrientedFootprint(pose, oriented_footprint);
00253   
00254   
00255   if(!costmap_.setConvexPolygonCost(oriented_footprint, costmap_2d::FREE_SPACE)) 
00256   {
00257       ROS_ERROR("Could not clear robot footprint: ");
00258       for (uint i = 0; i < oriented_footprint.size(); ++i)
00259         ROS_ERROR("oriented_footprint: %.2lf %.2lf %.2lf", oriented_footprint[i].x, oriented_footprint[i].y, oriented_footprint[i].z);
00260       return false;     
00261   }
00262   return true;
00263 }
00264 
00265 
00266 double CostmapTrajectoryChecker::checkTrajectoryMonotonic(const std::vector<geometry_msgs::Pose2D>& traj, 
00267                                                           bool update_map, 
00268                                                           bool clear_footprint, 
00269                                                           unsigned int num_consec_points_in_collision)
00270 {
00271     
00272   if (update_map)
00273     costmap_ros_->getCostmapCopy(costmap_);
00274   
00275   if (clear_footprint) {
00276     vector<geometry_msgs::Point> oriented_footprint;
00277     getOrientedFootprint(traj[0], oriented_footprint);
00278     
00279     
00280     if(!costmap_.setConvexPolygonCost(oriented_footprint, costmap_2d::FREE_SPACE)) {
00281       ROS_ERROR("Could not clear robot footprint: ");
00282       for (uint i = 0; i < oriented_footprint.size(); ++i)
00283         ROS_ERROR("oriented_footprint: %.2lf %.2lf %.2lf", oriented_footprint[i].x, oriented_footprint[i].y, oriented_footprint[i].z);
00284       return false;
00285     }
00286   }
00287   
00288   double cost = -1.0;
00289   double lastcost = 0.0;
00290   unsigned int num_lethal_cost = 0;
00291   
00292   for (unsigned int i = 0; i < traj.size(); ++i) {
00293     
00294 
00295     double newcost = footprintCost(traj[i]);
00296     cost = std::max(newcost,cost);
00297     if(newcost < 0)
00298       newcost = costmap_2d::LETHAL_OBSTACLE;
00299     
00300     if(i > 0 && i < (num_consec_points_in_collision+1)&& lastcost==costmap_2d::LETHAL_OBSTACLE && newcost == costmap_2d::LETHAL_OBSTACLE)
00301       num_lethal_cost++;
00302     
00303     if(i > 0 && lastcost < costmap_2d::LETHAL_OBSTACLE && (newcost==costmap_2d::LETHAL_OBSTACLE) )
00304     {
00305       ROS_INFO("Twist points: %d %d are leading us into collision",i-1,i);
00306       return -1.0;
00307     }
00308 
00309     if(num_lethal_cost > num_consec_points_in_collision || num_lethal_cost == traj.size()-1)
00310       return -1.0;
00311     lastcost = newcost;
00312   }
00313   
00314   if (traj_topic_name_ != "")
00315     publishTrajectory(traj);
00316   
00317   ROS_DEBUG("trajectory cost = %.4lf", cost);
00318   return cost;
00319 }
00320 
00321 double CostmapTrajectoryChecker::checkTwistMonotonic(const geometry_msgs::Twist &vel, unsigned int num_steps, double dt, bool update_map, bool clear_footprint)
00322 {
00323         geometry_msgs::Pose2D pose;
00324         getRobotPose(pose);
00325         std::vector<geometry_msgs::Pose2D> traj;
00326         generateTrajectory(pose, vel, num_steps, dt, traj);
00327 
00328         return checkTrajectoryMonotonic(traj, update_map, clear_footprint,5);
00329 }
00330 
00331 
00332 double CostmapTrajectoryChecker::checkTwist(const geometry_msgs::Twist &vel, unsigned int num_steps, double dt, bool update_map, bool clear_footprint)
00333 {
00334         geometry_msgs::Pose2D pose;
00335         getRobotPose(pose);
00336         std::vector<geometry_msgs::Pose2D> traj;
00337         generateTrajectory(pose, vel, num_steps, dt, traj);
00338 
00339         return checkTrajectory(traj, update_map, clear_footprint);
00340 }
00341 
00342 void CostmapTrajectoryChecker::getOrientedFootprint(const geometry_msgs::Pose2D &pose, std::vector<geometry_msgs::Point> &oriented_footprint)
00343 {
00344         oriented_footprint.resize(0);
00345         double cos_th = cos(pose.theta);
00346         double sin_th = sin(pose.theta);
00347         for(unsigned int i = 0; i < footprint_spec_.size(); ++i){
00348                 geometry_msgs::Point new_pt;
00349                 new_pt.x = pose.x + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
00350                 new_pt.y = pose.y + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
00351                 oriented_footprint.push_back(new_pt);
00352         }
00353 }
00354 
00355 
00356 double CostmapTrajectoryChecker::footprintCost(const geometry_msgs::Pose2D &pose)
00357 {
00358         
00359         vector<geometry_msgs::Point> oriented_footprint;
00360         getOrientedFootprint(pose, oriented_footprint);
00361 
00362         geometry_msgs::Point robot_position;
00363         robot_position.x = pose.x;
00364         robot_position.y = pose.y;
00365 
00366         
00367         
00368         
00369         
00370         
00371         
00372         return world_model_->footprintCost(robot_position, oriented_footprint, inscribed_radius_, circumscribed_radius_);
00373 }
00374 
00375 void CostmapTrajectoryChecker::poseTFToPose2D(const tf::Pose &pose_tf, geometry_msgs::Pose2D &pose_2d)
00376 {
00377         btScalar pitch, roll, yaw;
00378         pose_tf.getBasis().getRPY(roll, pitch, yaw);
00379 
00380         pose_2d.x = pose_tf.getOrigin()[0];
00381         pose_2d.y = pose_tf.getOrigin()[1];
00382         pose_2d.theta = yaw;
00383 
00384         if (pose_tf.getOrigin()[2]>0.1)
00385                 ROS_WARN("Large linear Z component lost in conversion to 2D pose (%.2f)", pose_tf.getOrigin()[2]);
00386         if (roll>0.1)
00387                 ROS_WARN("Large roll component lost in conversion to 2D pose (%.2f)", roll);
00388         if (pitch>0.1)
00389                 ROS_WARN("Large roll component lost in conversion to 2D pose (%.2f)", pitch);
00390 }
00391 
00392 void CostmapTrajectoryChecker::pose2DToTF(const geometry_msgs::Pose2D pose_2d, tf::Pose &pose_tf)
00393 {
00394         btQuaternion q;
00395         q.setRPY(0, 0, pose_2d.theta);
00396         pose_tf.setRotation(q);
00397         pose_tf.setOrigin(btVector3(pose_2d.x, pose_2d.y, 0));
00398 }
00399 
00400 void CostmapTrajectoryChecker::pose2DToPose(const geometry_msgs::Pose2D pose_2d, geometry_msgs::Pose &pose)
00401 {
00402         pose.position.x = pose_2d.x;
00403         pose.position.y = pose_2d.y;
00404         pose.position.z = 0;
00405         pose.orientation = tf::createQuaternionMsgFromYaw(pose_2d.theta);
00406 }
00407 
00408 void CostmapTrajectoryChecker::poseToPose2D(const geometry_msgs::Pose pose, geometry_msgs::Pose2D &pose_2d)
00409 {
00410         pose_2d.x = pose.position.x;
00411         pose_2d.y = pose.position.y;
00412         pose_2d.theta = tf::getYaw(pose.orientation);
00413 }
00414 
00415 bool CostmapTrajectoryChecker::getRobotPose(geometry_msgs::Pose2D &pose_2d) const
00416 {
00417         tf::StampedTransform pose_tf;
00418 
00419         
00420         try {
00421                 tl_.lookupTransform(global_frame_, robot_frame_, ros::Time(), pose_tf);
00422         } catch (tf::LookupException& ex) {
00423                 ROS_ERROR("No Transform available Error: %s\n", ex.what());
00424                 return false;
00425         } catch (tf::ConnectivityException& ex) {
00426                 ROS_ERROR("Connectivity Error: %s\n", ex.what());
00427                 return false;
00428         } catch (tf::ExtrapolationException& ex) {
00429                 ROS_ERROR("Extrapolation Error: %s\n", ex.what());
00430                 return false;
00431         }
00432 
00433         poseTFToPose2D(pose_tf, pose_2d);
00434 
00435   return true;
00436 }
00437 
00438 void CostmapTrajectoryChecker::integratePose(const geometry_msgs::Twist &vel, double dt,
00439                 geometry_msgs::Pose2D &pose)
00440 {
00441         pose.x += (vel.linear.x * cos(pose.theta) + vel.linear.y * cos(M_PI_2 + pose.theta)) * dt;
00442         pose.y += (vel.linear.x * sin(pose.theta) + vel.linear.y * sin(M_PI_2 + pose.theta)) * dt;
00443         pose.theta += vel.angular.z * dt;
00444 }
00445 
00446 void CostmapTrajectoryChecker::publishTrajectory(const std::vector<geometry_msgs::Pose2D>& path)
00447 {
00448   
00449   if(path.empty())
00450     return;
00451 
00452   
00453   nav_msgs::Path gui_path;
00454   gui_path.poses.resize(path.size());
00455   gui_path.header.frame_id = global_frame_;
00456   gui_path.header.stamp = ros::Time::now();
00457 
00458   
00459   for(unsigned int i=0; i < path.size(); i++){
00460           gui_path.poses[i].header.frame_id = global_frame_;
00461           gui_path.poses[i].header.stamp = ros::Time::now();
00462           pose2DToPose(path[i], gui_path.poses[i].pose);
00463   }
00464 
00465   traj_pub_.publish(gui_path);
00466 }