trajectory_planner.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2008, Willow Garage, Inc.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the Willow Garage nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 *********************************************************************/
00036 
00037 #include <trajectory_planner.h>
00038 
00039 using namespace std;
00040 using namespace costmap_2d;
00041 
00042 namespace iri_ackermann_local_planner{
00043   void TrajectoryPlanner::reconfigure(AckermannLocalPlannerConfig &cfg) 
00044   {
00045     iri_ackermann_local_planner::AckermannLocalPlannerConfig config(cfg);
00046     boost::mutex::scoped_lock l(configuration_mutex_);
00047 
00048     sim_time_ = config.sim_time;
00049     sim_granularity_ = config.sim_granularity;
00050 
00051     pdist_scale_ = config.pdist_scale;
00052     gdist_scale_ = config.gdist_scale;
00053     hdiff_scale_ = config.hdiff_scale;
00054     occdist_scale_ = config.occdist_scale;
00055 
00056     vx_samples_ = config.vx_samples;
00057     vtheta_samples_ = config.vtheta_samples;
00058 
00059     if (vx_samples_ <= 0) 
00060     {
00061       config.vx_samples = 1;
00062       vx_samples_ = config.vx_samples;
00063       ROS_WARN("You've specified that you don't want any samples in the x dimension. We'll at least assume that you want to sample one value... so we're going to set vx_samples to 1 instead");
00064     }
00065     if(vtheta_samples_ <= 0) 
00066     {
00067       config.vtheta_samples = 1;
00068       vtheta_samples_ = config.vtheta_samples;
00069       ROS_WARN("You've specified that you don't want any samples in the theta dimension. We'll at least assume that you want to sample one value... so we're going to set vtheta_samples to 1 instead");
00070     }
00071 
00072     simple_attractor_ = config.simple_attractor;
00073 
00074     angular_sim_granularity_ = config.angular_sim_granularity;
00075 
00076     /* ackerman parameters */
00077     this->ack_vel_max_=config.ack_vel_max;//config.ack_vel_max;
00078     this->ack_vel_min_=config.ack_vel_max;//config.ack_vel_min;
00079     this->ack_acc_max_=config.ack_acc_max;//config.ack_acc_max;
00080     this->ack_steer_angle_max_=config.ack_steer_angle_max;//config.ack_steer_angle_max;
00081     this->ack_steer_angle_min_=config.ack_steer_angle_min;//config.ack_steer_angle_min;
00082     this->ack_steer_speed_max_=config.ack_steer_speed_max;//config.ack_steer_speed_max;
00083     this->ack_steer_speed_min_=config.ack_steer_speed_min;//config.ack_steer_speed_min;
00084     this->ack_steer_acc_max_=config.ack_steer_acc_max;//config.ack_steer_acc_max;
00085     this->ack_axis_distance_=config.ack_axis_distance;
00086     this->heading_points_=config.heading_points;
00087   }
00088 
00089   TrajectoryPlanner::TrajectoryPlanner(WorldModel &world_model,
00090     const costmap_2d::Costmap2D& costmap,
00091     std::vector<geometry_msgs::Point> footprint_spec,
00092     double max_acc, double max_vel, double min_vel,
00093     double max_steer_acc, double max_steer_vel, double min_steer_vel,
00094     double max_steer_angle, double min_steer_angle,double axis_distance,
00095     double sim_time, double sim_granularity,
00096     int vx_samples, int vtheta_samples,
00097     double pdist_scale, double gdist_scale, double occdist_scale, double hdiff_scale,
00098     bool simple_attractor, double angular_sim_granularity,int heading_points,double xy_goal_tol)
00099     : map_(costmap.getSizeInCellsX(), costmap.getSizeInCellsY()), costmap_(costmap), 
00100     world_model_(world_model), footprint_spec_(footprint_spec),
00101     sim_time_(sim_time), sim_granularity_(sim_granularity), angular_sim_granularity_(angular_sim_granularity),
00102     vx_samples_(vx_samples), vtheta_samples_(vtheta_samples),
00103     pdist_scale_(pdist_scale), gdist_scale_(gdist_scale), occdist_scale_(occdist_scale),hdiff_scale_(hdiff_scale),
00104     ack_acc_max_(max_acc), ack_vel_min_(min_vel), ack_vel_max_(max_vel),
00105     ack_steer_acc_max_(max_steer_acc),ack_steer_speed_max_(max_steer_vel),ack_steer_speed_min_(min_steer_vel),
00106     ack_steer_angle_max_(max_steer_angle),ack_steer_angle_min_(min_steer_angle),ack_axis_distance_(axis_distance),
00107     simple_attractor_(simple_attractor),heading_points_(heading_points),xy_goal_tol_(xy_goal_tol)
00108   {
00109   }
00110 
00111   TrajectoryPlanner::~TrajectoryPlanner(){}
00112 
00113   bool TrajectoryPlanner::getCellCosts(int cx, int cy, float &path_cost, float &goal_cost, float &occ_cost, float &total_cost) {
00114     MapCell cell = map_(cx, cy);
00115     if (cell.within_robot) {
00116         return false;
00117     }
00118     occ_cost = costmap_.getCost(cx, cy);
00119     if (cell.path_dist >= map_.map_.size() || cell.goal_dist >= map_.map_.size() || occ_cost >= costmap_2d::INSCRIBED_INFLATED_OBSTACLE) {
00120         return false;
00121     }
00122     path_cost = cell.path_dist;
00123     goal_cost = cell.goal_dist;
00124     total_cost = pdist_scale_ * path_cost + gdist_scale_ * goal_cost + occdist_scale_ * occ_cost;
00125     return true;
00126   }
00127 
00128   //create and score a trajectory given the current pose of the robot and selected velocities
00129   void TrajectoryPlanner::generateTrajectory(double x, double y, double theta, double vx, double vy, 
00130       double vtheta, double vx_samp, double vy_samp, double vtheta_samp, 
00131       double acc_x, double acc_y, double acc_theta, double impossible_cost,
00132       Trajectory& traj){
00133 
00134     // make sure the configuration doesn't change mid run
00135     boost::mutex::scoped_lock l(configuration_mutex_);
00136 
00137     // store the current state of the robot (pose (x,y,theta) and speed
00138     double x_i = x;
00139     double y_i = y;
00140     double theta_i = theta;
00141 
00142     // ackerman current state
00143     double vt_i;
00144     double steer_angle_i,steer_speed_i;
00145     double vx_int,vy_int;
00146     double r,d;
00147 
00148     // for the ackerman configuration, vx_samp -> v_t and vtheta_samp -> steer_angle
00149     vt_i=vx;
00150     steer_angle_i=vy;
00151     steer_speed_i=vtheta;
00152 
00153     vx_int = vx_samp;
00154     vy_int = 0;
00155 
00156     //compute the number of steps we must take along this trajectory to be "safe"
00157     int num_steps;
00158     num_steps = int(sim_time_ / sim_granularity_ + 0.5);
00159 
00160     //we at least want to take one step... even if we won't move, we want to score our current position
00161     if(num_steps == 0)
00162       num_steps = 1;
00163 
00164     double dt = sim_time_ / num_steps;
00165     double time = 0.0;
00166 
00167     //create a potential trajectory
00168     traj.resetPoints();
00169     traj.xv_ = vx_int; 
00170     traj.yv_ = vy_int; 
00171     traj.thetav_ = vtheta_samp;
00172     traj.cost_ = -1.0;
00173 
00174     //initialize the costs for the trajectory
00175     double path_dist = 0.0;
00176     double goal_dist = 0.0;
00177     double occ_cost = 0.0;
00178     double heading_diff = 0.0;
00179 
00180     double speed=0.0,angle=0.0;
00181     double T1=0.0,T4=0.0,T2=0.0,T3=0.0;
00182 
00183     /* check wether the trajectory can be generated or not */
00184     if(vtheta<0 && (-vtheta*vtheta/(2*this->ack_steer_acc_max_)+vy)>this->ack_steer_angle_max_)
00185       return;
00186 
00187     if(vtheta>0 && (vtheta*vtheta/(2*this->ack_steer_acc_max_)+vy)>this->ack_steer_angle_max_)
00188       return;
00189 
00190     if(vtheta<0 && (-vtheta*vtheta/(2*this->ack_steer_acc_max_)+vy)<this->ack_steer_angle_min_)
00191       return;
00192 
00193     if(vtheta>0 && (vtheta*vtheta/(2*this->ack_steer_acc_max_)+vy)<this->ack_steer_angle_min_)
00194       return;
00195 
00196     // compute the trajectory times
00197     if(steer_speed_i>=0)
00198     {
00199       if(vtheta_samp>steer_angle_i)
00200       { 
00201         speed=(steer_speed_i+this->ack_steer_acc_max_*sim_time_)/2.0;
00202         if(speed>=this->ack_steer_speed_max_)
00203         {
00204           speed=this->ack_steer_speed_max_;  
00205           T4=sim_time_-(2.0*speed-steer_speed_i)/this->ack_steer_acc_max_;
00206           angle=speed*speed/this->ack_steer_acc_max_-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+speed*sim_time_*T4+steer_angle_i;
00207           if(angle>vtheta_samp)
00208           {
00209             angle=vtheta_samp;
00210             T4=(vtheta_samp-steer_angle_i-speed*speed/this->ack_steer_acc_max_+steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_))/speed;
00211             if(T4<0)
00212             {
00213               T4=0;
00214               speed=sqrt(steer_speed_i*steer_speed_i/2.0+this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00215             }
00216           }
00217         }
00218         else
00219         { 
00220           angle=speed*speed/this->ack_steer_acc_max_-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+steer_angle_i;
00221           T4=0;
00222           if(angle>vtheta_samp)
00223           {
00224             angle=vtheta_samp;
00225             speed=sqrt(steer_speed_i*steer_speed_i/2.0+this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00226           }
00227         }
00228         T1=(speed-steer_speed_i)/this->ack_steer_acc_max_;
00229         if(T1<0)
00230           return;
00231       }
00232       else
00233       {
00234         speed=(steer_speed_i-this->ack_steer_acc_max_*sim_time_)/2.0;
00235         if(speed<=this->ack_steer_speed_min_)
00236         {
00237           speed=this->ack_steer_speed_min_;
00238           T4=sim_time_+(2.0*speed-steer_speed_i)/this->ack_steer_acc_max_;
00239           angle=steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)-speed*speed/this->ack_steer_acc_max_+speed*T4+steer_angle_i;
00240           if(angle<vtheta_samp)
00241           {
00242             angle=vtheta_samp;
00243             T4=(vtheta_samp-steer_angle_i+speed*speed/this->ack_steer_acc_max_-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_))/speed;
00244             if(T4<0)
00245             {
00246               T4=0;
00247               speed=-sqrt(steer_speed_i*steer_speed_i/2.0-this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00248             }
00249           }
00250         }
00251         else
00252         {
00253           angle=steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)-speed*speed/this->ack_steer_acc_max_+steer_angle_i;
00254           T4=0;
00255           if(angle<vtheta_samp)
00256           {
00257             angle=vtheta_samp;
00258             speed=-sqrt(steer_speed_i*steer_speed_i/2.0-this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i)); 
00259           }
00260         }
00261         T1=-(speed-steer_speed_i)/this->ack_steer_acc_max_;
00262         if(T1<0)
00263           return;
00264       }
00265     }
00266     else
00267     {
00268       if(vtheta_samp>steer_angle_i)
00269       {
00270         speed=(steer_speed_i+this->ack_steer_acc_max_*sim_time_)/2.0;
00271         if(speed>=this->ack_steer_speed_max_)
00272         {
00273           speed=this->ack_steer_speed_max_;
00274           T4=sim_time_-(2.0*speed-steer_speed_i)/this->ack_steer_acc_max_;
00275           angle=-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+speed*speed/this->ack_steer_acc_max_+speed*T4+steer_angle_i;
00276           if(angle>vtheta_samp)
00277           {
00278             angle=vtheta_samp;
00279             T4=(vtheta_samp-steer_angle_i-speed*speed/this->ack_steer_acc_max_+steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_))/speed;
00280             if(T4<0)
00281             {
00282               T4=0;
00283               speed=sqrt(steer_speed_i*steer_speed_i/2.0+this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00284             }
00285           }
00286         }
00287         else
00288         {
00289           angle=-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+speed*speed/this->ack_steer_acc_max_+steer_angle_i;
00290           T4=0;
00291           if(angle>vtheta_samp)
00292           {
00293             angle=vtheta_samp;
00294             speed=sqrt(steer_speed_i*steer_speed_i/2.0+this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00295           }
00296         }
00297         T1=(speed-steer_speed_i)/this->ack_steer_acc_max_;
00298         if(T1<0)
00299           return;
00300       }
00301       else
00302       {
00303         speed=(steer_speed_i-this->ack_steer_acc_max_*sim_time_)/2.0;
00304         if(speed<=this->ack_steer_speed_min_)
00305         {
00306           speed=this->ack_steer_speed_min_;
00307           T4=sim_time_+(2.0*speed-steer_speed_i)/this->ack_steer_acc_max_;
00308           angle=-speed*speed/this->ack_steer_acc_max_+steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+speed*T4+steer_angle_i;
00309           if(angle<vtheta_samp)
00310           {
00311             angle=vtheta_samp;
00312             T4=(vtheta_samp-steer_angle_i+speed*speed/this->ack_steer_acc_max_-steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_))/speed;
00313             if(T4<0)
00314             {
00315               T4=0;
00316               speed=-sqrt(steer_speed_i*steer_speed_i/2.0-this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i));
00317             }
00318           }
00319         }
00320         else
00321         {
00322           angle=-speed*speed/this->ack_steer_acc_max_+steer_speed_i*steer_speed_i/(2.0*this->ack_steer_acc_max_)+steer_angle_i;
00323           T4=0;
00324           if(angle<vtheta_samp)
00325           {
00326             angle=vtheta_samp;
00327             speed=-sqrt(steer_speed_i*steer_speed_i/2.0-this->ack_steer_acc_max_*(vtheta_samp-steer_angle_i)); 
00328           }
00329         }
00330         T1=-(speed-steer_speed_i)/this->ack_steer_acc_max_;
00331         if(T1<0)
00332           return;
00333       }
00334     }
00335 
00336     double v=0.0;
00337     if(vx_samp>vt_i)
00338     {
00339       v=(vt_i+this->ack_acc_max_*sim_time_)/2.0;
00340       if(v>vx_samp)
00341       {
00342         v=vx_samp;
00343         T3=sim_time_-(2.0*v-vt_i)/this->ack_acc_max_;
00344       }
00345       else
00346         T3=0;
00347       T2=(v-vt_i)/this->ack_acc_max_;
00348       if(T2<0)
00349         return;
00350     }
00351     else
00352     {
00353       v=(vt_i-this->ack_acc_max_*sim_time_)/2.0;
00354       if(v<vx_samp)
00355       {
00356         v=vx_samp;
00357         T3=sim_time_+(2.0*v-vt_i)/this->ack_acc_max_;
00358       }
00359       else
00360         T3=0;
00361       T2=-(v-vt_i)/this->ack_acc_max_;
00362       if(T2<0)
00363         return;
00364     }
00365 
00366     double time_window_start=sim_time_/heading_points_;
00367     double time_window_end=sim_time_/heading_points_+dt;
00368 
00369     for(int i = 0; i < num_steps; ++i){
00370       //get map coordinates of a point
00371       unsigned int cell_x, cell_y;
00372 
00373       //we don't want a path that goes off the know map
00374       if(!costmap_.worldToMap(x_i, y_i, cell_x, cell_y)){
00375         traj.cost_ = -1.0;
00376         ROS_DEBUG("TrajectoryPlanner::generateTrajectory: Current point out of map!");
00377         return;
00378       }
00379 
00380       //check the point on the trajectory for legality
00381       double footprint_cost = footprintCost(x_i, y_i, theta_i);
00382 
00383       occ_cost = std::max(std::max(occ_cost, footprint_cost), double(costmap_.getCost(cell_x, cell_y)));
00384 
00385       double cell_pdist = map_(cell_x, cell_y).path_dist;
00386       double cell_gdist = map_(cell_x, cell_y).goal_dist;
00387      
00388       double near_dist=DBL_MAX,dist;
00389       unsigned int near_index=0;
00390  
00391       //update path and goal distances
00392       path_dist = cell_pdist;
00393       goal_dist = cell_gdist;
00394       if(time >= time_window_start && time < time_window_end)
00395       {
00396         // find the nearrest point on the path
00397         for(unsigned int i = 0;i<global_plan_.size();i++)
00398         {
00399           dist=sqrt((global_plan_[i].pose.position.x-x_i)*(global_plan_[i].pose.position.x-x_i)+(global_plan_[i].pose.position.y-y_i)*(global_plan_[i].pose.position.y-y_i));
00400           if(dist<near_dist)
00401           { 
00402             near_dist=dist;
00403             near_index=i;
00404           }
00405         }
00406         double v1_x,v1_y;
00407         if(near_index==0)
00408         {
00409           v1_x = global_plan_[near_index+1].pose.position.x - global_plan_[near_index].pose.position.x;
00410           v1_y = global_plan_[near_index+1].pose.position.y - global_plan_[near_index].pose.position.y;
00411         }
00412         else
00413         {
00414           v1_x = global_plan_[near_index].pose.position.x - global_plan_[near_index-1].pose.position.x;
00415           v1_y = global_plan_[near_index].pose.position.y - global_plan_[near_index-1].pose.position.y;
00416         }
00417         double v2_x = cos(theta_i);
00418         double v2_y = sin(theta_i);
00419 
00420         double perp_dot = v1_x * v2_y - v1_y * v2_x;
00421         double dot = v1_x * v2_x + v1_y * v2_y;
00422 
00423         //get the signed angle
00424         heading_diff += fabs(atan2(perp_dot, dot));
00425 
00426         time_window_start+=sim_time_/heading_points_;
00427         time_window_end=time_window_start+dt;
00428       }
00429 
00430       //do we want to follow blindly
00431       if(simple_attractor_){
00432         goal_dist = (x_i - global_plan_[global_plan_.size() -1].pose.position.x) * 
00433           (x_i - global_plan_[global_plan_.size() -1].pose.position.x) + 
00434           (y_i - global_plan_[global_plan_.size() -1].pose.position.y) * 
00435           (y_i - global_plan_[global_plan_.size() -1].pose.position.y);
00436         path_dist = 0.0;
00437       }
00438       else{
00439         //if a point on this trajectory has no clear path to goal it is invalid
00440         if(impossible_cost <= goal_dist || impossible_cost <= path_dist){
00441           ROS_DEBUG("No path to goal with goal distance = %f, path_distance = %f and max cost = %f", 
00442               cell_gdist, cell_pdist, impossible_cost);
00443           traj.cost_ = -2.0;
00444           return;
00445         }
00446       }
00447 
00448 
00449       //the point is legal... add it to the trajectory
00450       traj.addPoint(x_i, y_i, theta_i);
00451 
00452       // compute the next point in the trajectory
00453       if(vtheta_samp>vtheta)
00454       {
00455         if(time<T1)
00456         {
00457           steer_speed_i=steer_speed_i+this->ack_steer_acc_max_*dt;
00458           if(steer_speed_i>speed)
00459             steer_speed_i=speed;
00460         }
00461         else if(time<T1+T4)
00462           steer_speed_i=speed;
00463         else
00464         { 
00465           steer_speed_i=steer_speed_i-this->ack_steer_acc_max_*dt;
00466           if(steer_speed_i<0)
00467             steer_speed_i=0;
00468         }
00469       }
00470       else
00471       {
00472         if(time<T1)
00473         {
00474           steer_speed_i=steer_speed_i-this->ack_steer_acc_max_*dt;
00475           if(steer_speed_i<speed)
00476             steer_speed_i=speed;
00477         }
00478         else if(time<T1+T4)
00479           steer_speed_i=speed;
00480         else
00481         {
00482           steer_speed_i=steer_speed_i+this->ack_steer_acc_max_*dt;
00483           if(steer_speed_i>0)
00484             steer_speed_i=0;
00485         }
00486       }
00487       steer_angle_i+=steer_speed_i*dt;
00488       if(vx_samp>vx)
00489       {
00490         if(time<T2)
00491         {
00492           vt_i=vt_i+this->ack_acc_max_*dt;
00493           if(vt_i>v)
00494             vt_i=v;
00495         }
00496         else if(time<(T2+T3))
00497           vt_i=v;
00498         else
00499         {
00500           vt_i=vt_i-this->ack_acc_max_*dt;
00501           if(vt_i<0)
00502             vt_i=0;
00503         }
00504       }
00505       else
00506       {
00507         if(time<T2)
00508         {
00509           vt_i=vt_i-this->ack_acc_max_*dt;
00510           if(vt_i<v)
00511             vt_i=v;
00512         }
00513         else if(time<T2+T3)
00514           vt_i=v;
00515         else
00516         {  
00517           vt_i=vt_i+this->ack_acc_max_*dt;
00518           if(vt_i>0)
00519             vt_i=0;
00520         }
00521       }
00522 
00523       if(fabs(steer_angle_i)>0.02)
00524       {
00525         r=ack_axis_distance_*tan(3.14159/2.0-steer_angle_i);
00526         d=vt_i*dt;
00527         x_i+=d*cos(theta_i);
00528         y_i+=d*sin(theta_i);
00529         theta_i+=d/r;
00530       }
00531       else
00532       {
00533         d=vt_i*dt;
00534         x_i+=d*cos(theta_i);
00535         y_i+=d*sin(theta_i);
00536       }
00537 
00538       //increment time
00539       time += dt;
00540     }
00541 
00542     //ROS_INFO("OccCost: %f, vx: %.2f, vy: %.2f, vtheta: %.2f", occ_cost, vx_samp, vy_samp, vtheta_samp);
00543     double cost = -1.0;
00544     cost = (pdist_scale_ * path_dist + goal_dist * gdist_scale_ + occdist_scale_ * occ_cost + hdiff_scale_ * heading_diff)*(1.0+0.0*fabs(vy-vtheta_samp));      
00545 
00546     traj.cost_ = cost;
00547   }
00548 
00549   double TrajectoryPlanner::headingDiff(int cell_x, int cell_y, double x, double y, double heading){
00550     double heading_diff = DBL_MAX;
00551     unsigned int goal_cell_x, goal_cell_y;
00552     //find a clear line of sight from the robot's cell to a point on the path
00553     for(int i = global_plan_.size() - 1; i >=0; --i){
00554       if(costmap_.worldToMap(global_plan_[i].pose.position.x, global_plan_[i].pose.position.y, goal_cell_x, goal_cell_y)){
00555         if(lineCost(cell_x, goal_cell_x, cell_y, goal_cell_y) >= 0){
00556           double gx, gy;
00557           costmap_.mapToWorld(goal_cell_x, goal_cell_y, gx, gy);
00558           double v1_x = gx - x;
00559           double v1_y = gy - y;
00560           double v2_x = cos(heading);
00561           double v2_y = sin(heading);
00562 
00563           double perp_dot = v1_x * v2_y - v1_y * v2_x;
00564           double dot = v1_x * v2_x + v1_y * v2_y;
00565 
00566           //get the signed angle
00567           double vector_angle = atan2(perp_dot, dot);
00568 
00569           heading_diff = fabs(vector_angle);
00570           return heading_diff;
00571 
00572         }
00573       }
00574     }
00575     return heading_diff;
00576   }
00577 
00578   //calculate the cost of a ray-traced line
00579   double TrajectoryPlanner::lineCost(int x0, int x1, 
00580       int y0, int y1){
00581     //Bresenham Ray-Tracing
00582     int deltax = abs(x1 - x0);        // The difference between the x's
00583     int deltay = abs(y1 - y0);        // The difference between the y's
00584     int x = x0;                       // Start x off at the first pixel
00585     int y = y0;                       // Start y off at the first pixel
00586 
00587     int xinc1, xinc2, yinc1, yinc2;
00588     int den, num, numadd, numpixels;
00589 
00590     double line_cost = 0.0;
00591     double point_cost = -1.0;
00592 
00593     if (x1 >= x0)                 // The x-values are increasing
00594     {
00595       xinc1 = 1;
00596       xinc2 = 1;
00597     }
00598     else                          // The x-values are decreasing
00599     {
00600       xinc1 = -1;
00601       xinc2 = -1;
00602     }
00603 
00604     if (y1 >= y0)                 // The y-values are increasing
00605     {
00606       yinc1 = 1;
00607       yinc2 = 1;
00608     }
00609     else                          // The y-values are decreasing
00610     {
00611       yinc1 = -1;
00612       yinc2 = -1;
00613     }
00614 
00615     if (deltax >= deltay)         // There is at least one x-value for every y-value
00616     {
00617       xinc1 = 0;                  // Don't change the x when numerator >= denominator
00618       yinc2 = 0;                  // Don't change the y for every iteration
00619       den = deltax;
00620       num = deltax / 2;
00621       numadd = deltay;
00622       numpixels = deltax;         // There are more x-values than y-values
00623     }
00624     else                          // There is at least one y-value for every x-value
00625     {
00626       xinc2 = 0;                  // Don't change the x for every iteration
00627       yinc1 = 0;                  // Don't change the y when numerator >= denominator
00628       den = deltay;
00629       num = deltay / 2;
00630       numadd = deltax;
00631       numpixels = deltay;         // There are more y-values than x-values
00632     }
00633 
00634     for (int curpixel = 0; curpixel <= numpixels; curpixel++)
00635     {
00636       point_cost = pointCost(x, y); //Score the current point
00637 
00638       if(point_cost < 0)
00639         return -1;
00640 
00641       if(line_cost < point_cost)
00642         line_cost = point_cost;
00643 
00644       num += numadd;              // Increase the numerator by the top of the fraction
00645       if (num >= den)             // Check if numerator >= denominator
00646       {
00647         num -= den;               // Calculate the new numerator value
00648         x += xinc1;               // Change the x as appropriate
00649         y += yinc1;               // Change the y as appropriate
00650       }
00651       x += xinc2;                 // Change the x as appropriate
00652       y += yinc2;                 // Change the y as appropriate
00653     }
00654 
00655     return line_cost;
00656   }
00657 
00658   double TrajectoryPlanner::pointCost(int x, int y){
00659     unsigned char cost = costmap_.getCost(x, y);
00660     //if the cell is in an obstacle the path is invalid
00661     if(cost == LETHAL_OBSTACLE || cost == INSCRIBED_INFLATED_OBSTACLE || cost == NO_INFORMATION){
00662       return -1;
00663     }
00664 
00665     return cost;
00666   }
00667 
00668   void TrajectoryPlanner::updatePlan(const vector<geometry_msgs::PoseStamped>& new_plan, bool compute_dists)
00669   {
00670     global_plan_.resize(new_plan.size());
00671     for(unsigned int i = 0; i < new_plan.size(); ++i)
00672     {
00673       global_plan_[i] = new_plan[i];
00674     }
00675     if(compute_dists){
00676       //reset the map for new operations
00677       map_.resetPathDist();
00678       //make sure that we update our path based on the global plan and compute costs
00679       map_.setPathCells(costmap_, global_plan_);
00680       ROS_DEBUG("Path/Goal distance computed");
00681     }
00682   }
00683 
00684   bool TrajectoryPlanner::checkTrajectory(double x, double y, double theta, double vx, double vy, 
00685       double vtheta, double vx_samp, double vy_samp, double vtheta_samp){
00686     Trajectory t; 
00687 
00688     double cost = scoreTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp);
00689 
00690     //if the trajectory is a legal one... the check passes
00691     if(cost >= 0)
00692       return true;
00693 
00694     //otherwise the check fails
00695     return false;
00696   }
00697 
00698   double TrajectoryPlanner::scoreTrajectory(double x, double y, double theta, double vx, double vy, 
00699       double vtheta, double vx_samp, double vy_samp, double vtheta_samp){
00700     Trajectory t; 
00701     double impossible_cost = map_.map_.size();
00702     generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, 
00703         ack_acc_max_, ack_vel_max_, ack_vel_min_, impossible_cost, t);
00704 
00705     // return the cost.
00706     return double( t.cost_ );
00707   }
00708 
00709   //create the trajectories we wish to score
00710   Trajectory TrajectoryPlanner::createTrajectories(double x, double y, double theta, 
00711       double vx, double vy, double vtheta,
00712       double acc_x, double acc_y, double acc_theta){
00713     //compute feasible velocity limits in robot space
00714     double max_vel_x, max_vel_theta;
00715     double min_vel_x, min_vel_theta;
00716     // ackerman variables
00717     double v_t;
00718     double steer_angle;
00719     double min_steer=0,max_steer=0;
00720       
00721     double dvx;
00722     double dvtheta;
00723  
00724     // should we use the ackerman configuration?
00725     /* transform the general status to the ackerman status */
00726     v_t=vx;
00727     if(vy>this->ack_steer_angle_max_)
00728       vy=this->ack_steer_angle_max_;
00729     else if(vy<this->ack_steer_angle_min_)
00730       vy=this->ack_steer_angle_min_;
00731     steer_angle=vy;
00732     if(vtheta>this->ack_steer_speed_max_)
00733       vtheta=this->ack_steer_speed_max_;
00734     else if(vtheta<this->ack_steer_speed_min_)
00735       vtheta=this->ack_steer_speed_min_;
00736     this->steering_speed_=vtheta;
00737       /* compute the margins */
00738     //should we use the dynamic window approach?
00739     double T4=0.0;
00740 
00741     // compute the simulation time
00742     double dist=sqrt((global_plan_[global_plan_.size()-1].pose.position.x-x)*(global_plan_[global_plan_.size()-1].pose.position.x-x)+
00743                      (global_plan_[global_plan_.size()-1].pose.position.y-y)*(global_plan_[global_plan_.size()-1].pose.position.y-y));
00744     sim_time_=dist/ack_vel_max_;
00745     if(sim_time_>10.0)
00746       sim_time_=10.0;
00747     else if(sim_time_<3.0)
00748       sim_time_=3.0;
00749     ROS_WARN("Simulation time %f\n",sim_time_);
00750     // compute the trajectory times
00751     if(this->steering_speed_>=0)
00752     {
00753       max_vel_theta=(this->steering_speed_+this->ack_steer_acc_max_*sim_time_)/2.0;
00754       if(max_vel_theta>=this->ack_steer_speed_max_)
00755       {
00756         max_vel_theta=this->ack_steer_speed_max_;  
00757         T4=sim_time_-(2.0*max_vel_theta-this->steering_speed_)/this->ack_steer_acc_max_;
00758         max_steer=max_vel_theta*max_vel_theta/this->ack_steer_acc_max_-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+max_vel_theta*T4+steer_angle;
00759         if(max_steer>this->ack_steer_angle_max_) 
00760         {
00761           max_steer=this->ack_steer_angle_max_;
00762           T4=(this->ack_steer_angle_max_-steer_angle-max_vel_theta*max_vel_theta/this->ack_steer_acc_max_+this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_))/max_vel_theta;
00763           if(T4<0)
00764           {
00765             T4=0;
00766             max_vel_theta=sqrt(this->steering_speed_*this->steering_speed_/2.0+this->ack_steer_acc_max_*(this->ack_steer_angle_max_-steer_angle));
00767           }
00768         }
00769       }
00770       else
00771       { 
00772         max_steer=max_vel_theta*max_vel_theta/this->ack_steer_acc_max_-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+steer_angle;
00773         T4=0;
00774         if(max_steer>this->ack_steer_angle_max_)
00775         {
00776           max_steer=this->ack_steer_angle_max_;
00777           max_vel_theta=sqrt(this->steering_speed_*this->steering_speed_/2.0+this->ack_steer_acc_max_*(this->ack_steer_angle_max_-steer_angle));
00778         }
00779       }
00780       min_vel_theta=(this->steering_speed_-this->ack_steer_acc_max_*sim_time_)/2.0;
00781       if(min_vel_theta<=this->ack_steer_speed_min_)
00782       {
00783         min_vel_theta=this->ack_steer_speed_min_;
00784         T4=sim_time_+(2.0*min_vel_theta-this->steering_speed_)/this->ack_steer_acc_max_;
00785         min_steer=this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)-min_vel_theta*min_vel_theta/this->ack_steer_acc_max_+min_vel_theta*T4+steer_angle;
00786         if(min_steer<this->ack_steer_angle_min_)
00787         {
00788           min_steer=this->ack_steer_angle_min_;
00789           T4=(this->ack_steer_angle_min_-steer_angle+min_vel_theta*min_vel_theta/this->ack_steer_acc_max_-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_))/min_vel_theta;
00790           if(T4<0)
00791           {
00792             T4=0;
00793             min_vel_theta=-sqrt(this->steering_speed_*this->steering_speed_/2.0-this->ack_steer_acc_max_*(this->ack_steer_angle_min_-steer_angle));
00794           }
00795         }
00796       }
00797       else
00798       {
00799         min_steer=this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)-min_vel_theta*min_vel_theta/this->ack_steer_acc_max_+steer_angle;
00800         T4=0;
00801         if(min_steer<this->ack_steer_angle_min_)
00802         {
00803           min_steer=this->ack_steer_angle_min_;
00804           min_vel_theta=-sqrt(this->steering_speed_*this->steering_speed_/2.0-this->ack_steer_acc_max_*(this->ack_steer_angle_min_-steer_angle)); 
00805         }
00806       }
00807     }
00808     else
00809     {
00810       max_vel_theta=(this->steering_speed_+this->ack_steer_acc_max_*sim_time_)/2.0;
00811       if(max_vel_theta>=this->ack_steer_speed_max_)
00812       {
00813         max_vel_theta=this->ack_steer_speed_max_;
00814         T4=sim_time_-(2.0*max_vel_theta-this->steering_speed_)/this->ack_steer_acc_max_;
00815         max_steer=-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+max_vel_theta*max_vel_theta/this->ack_steer_acc_max_+max_vel_theta*T4+steer_angle;
00816         if(max_steer>this->ack_steer_angle_max_)
00817         {
00818           max_steer=this->ack_steer_angle_max_;
00819           T4=(this->ack_steer_angle_max_-steer_angle-max_vel_theta*max_vel_theta/this->ack_steer_acc_max_+this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_))/max_vel_theta;
00820           if(T4<0)
00821           {
00822             T4=0;
00823             max_vel_theta=sqrt(this->steering_speed_*this->steering_speed_/2.0+this->ack_steer_acc_max_*(this->ack_steer_angle_max_-steer_angle));
00824           }
00825         }
00826       }
00827       else
00828       {
00829         max_steer=-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+max_vel_theta*max_vel_theta/this->ack_steer_acc_max_+steer_angle;
00830         T4=0;
00831         if(max_steer>this->ack_steer_angle_max_)
00832         {
00833           max_steer=this->ack_steer_angle_max_;
00834           max_vel_theta=sqrt(this->steering_speed_*this->steering_speed_/2.0+this->ack_steer_acc_max_*(this->ack_steer_angle_max_-steer_angle));
00835         }
00836       }
00837       min_vel_theta=(this->steering_speed_-this->ack_steer_acc_max_*sim_time_)/2.0;
00838       if(min_vel_theta<=this->ack_steer_speed_min_)
00839       {
00840         min_vel_theta=this->ack_steer_speed_min_;
00841         T4=sim_time_+(2.0*min_vel_theta-this->steering_speed_)/this->ack_steer_acc_max_;
00842         min_steer=-min_vel_theta*min_vel_theta/this->ack_steer_acc_max_+this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+min_vel_theta*T4+steer_angle;
00843         if(min_steer<this->ack_steer_angle_min_)
00844         {
00845           min_steer=this->ack_steer_angle_min_;
00846           T4=(this->ack_steer_angle_min_-steer_angle+min_vel_theta*min_vel_theta/this->ack_steer_acc_max_-this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_))/min_vel_theta;
00847           if(T4<0)
00848           {
00849             T4=0;
00850             min_vel_theta=-sqrt(this->steering_speed_*this->steering_speed_/2.0-this->ack_steer_acc_max_*(this->ack_steer_angle_min_-steer_angle));
00851           }
00852         }
00853       }
00854       else
00855       {
00856         min_steer=-min_vel_theta*min_vel_theta/this->ack_steer_acc_max_+this->steering_speed_*this->steering_speed_/(2.0*this->ack_steer_acc_max_)+steer_angle;
00857         T4=0;
00858         if(min_steer<this->ack_steer_angle_min_)
00859         {
00860           min_steer=this->ack_steer_angle_min_;
00861           min_vel_theta=-sqrt(this->steering_speed_*this->steering_speed_/2.0-this->ack_steer_acc_max_*(this->ack_steer_angle_min_-steer_angle)); 
00862         }
00863       }
00864     }
00865 
00866     dist=sqrt((map_.goal_x_-x)*(map_.goal_x_-x)+(map_.goal_y_-y)*(map_.goal_y_-y));
00867     double d=0.0,T5=0.0,a,b,c;
00868 
00869     max_vel_x=(v_t+this->ack_acc_max_*sim_time_)/2.0;
00870     if(max_vel_x>this->ack_vel_max_)
00871       max_vel_x=this->ack_vel_max_;
00872     if(v_t>0)
00873     {
00874       T5=sim_time_-(2.0*max_vel_x-v_t)/this->ack_acc_max_;
00875       d=max_vel_x*max_vel_x/this->ack_acc_max_-v_t*v_t/(2.0*this->ack_acc_max_)+max_vel_x*T5;
00876       if(d>dist)
00877       {
00878         d=dist;
00879         a=1;
00880         b=-v_t-sim_time_*this->ack_acc_max_;
00881         c=v_t*v_t/2.0+dist*this->ack_acc_max_;
00882         max_vel_x=(-b-sqrt(b*b-4*a*c))/(2.0*a);
00883       }
00884     }
00885     else
00886     {
00887       T5=sim_time_-(2.0*max_vel_x-v_t)/this->ack_acc_max_;
00888       d=-v_t*v_t/(2.0*this->ack_acc_max_)+max_vel_x*max_vel_x/this->ack_acc_max_+max_vel_x*T5;
00889       if(d>dist)
00890       {
00891         d=dist;
00892         a=1;
00893         b=-v_t-sim_time_*this->ack_acc_max_;
00894         c=v_t*v_t/2.0+dist*this->ack_acc_max_;
00895         max_vel_x=(-b-sqrt(b*b-4*a*c))/(2.0*a);
00896       }
00897     }
00898     min_vel_x=-max_vel_x;
00899     ROS_INFO("TrajectoryPlanner::createTrajectories: Goal_dist: %f, Dist: %f, Max_vel: %f", dist, d, max_vel_x);
00900       //we want to sample the velocity space regularly
00901     dvx = (max_vel_x - min_vel_x) / (vx_samples_ - 1);
00902     dvtheta = (max_steer - min_steer) / (vtheta_samples_ - 1);
00903 
00904     double vx_samp = min_vel_x;
00905     double vtheta_samp = min_steer;
00906     double vy_samp = 0.0;
00907 
00908     //keep track of the best trajectory seen so far
00909     Trajectory* best_traj = &traj_one;
00910     best_traj->cost_ = -1.0;
00911 
00912     Trajectory* comp_traj = &traj_two;
00913     comp_traj->cost_ = -1.0;
00914 
00915     Trajectory* swap = NULL;
00916 
00917     //any cell with a cost greater than the size of the map is impossible
00918     double impossible_cost = map_.map_.size();
00919 
00920     ROS_INFO("TrajectoryPlanner::createTrajectories: CurrentSteerAngle: %f, currentSteerSpeed: %f, CurrentSpeed: %f", vy, vtheta, vx);
00921     //loop through all x velocities
00922     for(int i = 0; i < vx_samples_; ++i)
00923     {
00924       vtheta_samp = 0;
00925       /* compute */
00926       //first sample the straight trajectory
00927       generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, 
00928           acc_x, acc_y, acc_theta, impossible_cost, *comp_traj);
00929 
00930       //if the new trajectory is better... let's take it
00931       if(comp_traj->cost_ >= 0 && (comp_traj->cost_ <= best_traj->cost_ || best_traj->cost_ < 0)){
00932         swap = best_traj;
00933         best_traj = comp_traj;
00934         comp_traj = swap;
00935         ROS_DEBUG("TrajectoryPlanner::createTrajectories: vt: %f, SteerAngle: 0, Cost: %f", i*dvx+min_vel_x, comp_traj->cost_);
00936       }
00937 
00938       vtheta_samp = min_steer;
00939       //next sample all theta trajectories
00940       for(int j = 0; j < vtheta_samples_ ; ++j){
00941         generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, 
00942             acc_x, acc_y, acc_theta, impossible_cost, *comp_traj);
00943         //if the new trajectory is better... let's take it
00944         if(comp_traj->cost_ >= 0 && (comp_traj->cost_ <= best_traj->cost_ || best_traj->cost_ < 0)){
00945           swap = best_traj;
00946           best_traj = comp_traj;
00947           comp_traj = swap;
00948           ROS_DEBUG("TrajectoryPlanner::createTrajectories: vt: %f, SteerAngle: %f, Cost: %f", i*dvx + min_vel_x, j*dvtheta + min_steer, comp_traj->cost_);
00949         }
00950         vtheta_samp += dvtheta;
00951       }
00952       vx_samp += dvx;
00953     }
00954 
00955     //next we want to generate trajectories for rotating in place
00956     vtheta_samp = min_vel_theta;
00957     vx_samp = 0.0;
00958     vy_samp = 0.0;
00959 
00960     //do we have a legal trajectory
00961     if(best_traj->cost_ >= 0)
00962     {
00963       /* if velocity command is small and the distance to goal is bigger than the threshold -> replan */
00964       dist=sqrt((map_.goal_x_-x)*(map_.goal_x_-x)+(map_.goal_y_-y)*(map_.goal_y_-y));
00965       if(dist>xy_goal_tol_ && fabs(best_traj->xv_)<0.02)
00966         best_traj->cost_=-1;
00967       return *best_traj;
00968     }
00969 
00970     //if the trajectory failed because the footprint hits something, we're still going to back up
00971     if(best_traj->cost_ == -1.0)
00972     {
00973       best_traj->resetPoints();
00974       best_traj->xv_ = 0.0;
00975       best_traj->yv_ = 0.0;
00976       best_traj->thetav_ = 0.0;
00977       best_traj->cost_ = -3.0;// no solution, keep the previous command
00978     }
00979 
00980     return *best_traj;
00981   }
00982 
00983   //given the current state of the robot, find a good trajectory
00984   Trajectory TrajectoryPlanner::findBestPath(tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel, 
00985       tf::Stamped<tf::Pose>& drive_velocities,geometry_msgs::Twist &ackermann_state)
00986   {
00987     static Trajectory last_best_traj;
00988 
00989     double yaw = tf::getYaw(global_pose.getRotation());
00990     //double vel_yaw = tf::getYaw(global_vel.getRotation());
00991 
00992     double x = global_pose.getOrigin().getX();
00993     double y = global_pose.getOrigin().getY();
00994     double theta = yaw;
00995 
00996     double vx = ackermann_state.linear.z;
00997     double vy = ackermann_state.angular.x;
00998     double vtheta = ackermann_state.angular.y;
00999 
01000     //reset the map for new operations
01001     map_.resetPathDist();
01002 
01003     //temporarily remove obstacles that are within the footprint of the robot
01004     vector<iri_ackermann_local_planner::Position2DInt> footprint_list = getFootprintCells(x, y, theta, true);
01005 
01006     //mark cells within the initial footprint of the robot
01007     for(unsigned int i = 0; i < footprint_list.size(); ++i){
01008       map_(footprint_list[i].x, footprint_list[i].y).within_robot = true;
01009     }
01010 
01011     //make sure that we update our path based on the global plan and compute costs
01012     map_.setPathCells(costmap_, global_plan_);
01013     ROS_DEBUG("Path/Goal distance computed");
01014 
01015 
01016     //rollout trajectories and find the minimum cost one
01017     Trajectory best = createTrajectories(x, y, theta, 
01018         vx, vy, vtheta, 
01019         ack_acc_max_, ack_vel_max_, ack_vel_min_);
01020     ROS_DEBUG("Trajectories created");
01021 
01022     if(best.cost_ < 0){
01023       if(best.cost_==-3)
01024       {
01025         best.xv_=last_best_traj.xv_;
01026         best.yv_=last_best_traj.yv_;
01027         best.thetav_=last_best_traj.thetav_;
01028         best.cost_=last_best_traj.cost_;
01029         tf::Vector3 start(best.xv_, best.yv_, 0);
01030         drive_velocities.setOrigin(start);
01031         tf::Matrix3x3 matrix;
01032         matrix.setRotation(tf::createQuaternionFromYaw(best.thetav_));
01033         drive_velocities.setBasis(matrix);
01034       }
01035       else
01036         drive_velocities.setIdentity();
01037     }
01038     else{
01039       tf::Vector3 start(best.xv_, best.yv_, 0);
01040       drive_velocities.setOrigin(start);
01041       tf::Matrix3x3 matrix;
01042       matrix.setRotation(tf::createQuaternionFromYaw(best.thetav_));
01043       drive_velocities.setBasis(matrix);
01044       last_best_traj.xv_=best.xv_;
01045       last_best_traj.yv_=best.yv_;
01046       last_best_traj.thetav_=best.thetav_;
01047       last_best_traj.cost_=best.cost_;
01048     }
01049 
01050     return best;
01051   }
01052 
01053   //we need to take the footprint of the robot into account when we calculate cost to obstacles
01054   double TrajectoryPlanner::footprintCost(double x_i, double y_i, double theta_i){
01055     //build the oriented footprint
01056     double cos_th = cos(theta_i);
01057     double sin_th = sin(theta_i);
01058     vector<geometry_msgs::Point> oriented_footprint;
01059     for(unsigned int i = 0; i < footprint_spec_.size(); ++i){
01060       geometry_msgs::Point new_pt;
01061       new_pt.x = x_i + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
01062       new_pt.y = y_i + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
01063       oriented_footprint.push_back(new_pt);
01064     }
01065 
01066     geometry_msgs::Point robot_position;
01067     robot_position.x = x_i;
01068     robot_position.y = y_i;
01069 
01070     //check if the footprint is legal
01071     double footprint_cost = world_model_.footprintCost(robot_position, oriented_footprint, costmap_.getInscribedRadius(), costmap_.getCircumscribedRadius());
01072 
01073     return footprint_cost;
01074   }
01075 
01076   void TrajectoryPlanner::getLineCells(int x0, int x1, int y0, int y1, vector<iri_ackermann_local_planner::Position2DInt>& pts){
01077     //Bresenham Ray-Tracing
01078     int deltax = abs(x1 - x0);        // The difference between the x's
01079     int deltay = abs(y1 - y0);        // The difference between the y's
01080     int x = x0;                       // Start x off at the first pixel
01081     int y = y0;                       // Start y off at the first pixel
01082 
01083     int xinc1, xinc2, yinc1, yinc2;
01084     int den, num, numadd, numpixels;
01085 
01086     iri_ackermann_local_planner::Position2DInt pt;
01087 
01088     if (x1 >= x0)                 // The x-values are increasing
01089     {
01090       xinc1 = 1;
01091       xinc2 = 1;
01092     }
01093     else                          // The x-values are decreasing
01094     {
01095       xinc1 = -1;
01096       xinc2 = -1;
01097     }
01098 
01099     if (y1 >= y0)                 // The y-values are increasing
01100     {
01101       yinc1 = 1;
01102       yinc2 = 1;
01103     }
01104     else                          // The y-values are decreasing
01105     {
01106       yinc1 = -1;
01107       yinc2 = -1;
01108     }
01109 
01110     if (deltax >= deltay)         // There is at least one x-value for every y-value
01111     {
01112       xinc1 = 0;                  // Don't change the x when numerator >= denominator
01113       yinc2 = 0;                  // Don't change the y for every iteration
01114       den = deltax;
01115       num = deltax / 2;
01116       numadd = deltay;
01117       numpixels = deltax;         // There are more x-values than y-values
01118     }
01119     else                          // There is at least one y-value for every x-value
01120     {
01121       xinc2 = 0;                  // Don't change the x for every iteration
01122       yinc1 = 0;                  // Don't change the y when numerator >= denominator
01123       den = deltay;
01124       num = deltay / 2;
01125       numadd = deltax;
01126       numpixels = deltay;         // There are more y-values than x-values
01127     }
01128 
01129     for (int curpixel = 0; curpixel <= numpixels; curpixel++)
01130     {
01131       pt.x = x;      //Draw the current pixel
01132       pt.y = y;
01133       pts.push_back(pt);
01134 
01135       num += numadd;              // Increase the numerator by the top of the fraction
01136       if (num >= den)             // Check if numerator >= denominator
01137       {
01138         num -= den;               // Calculate the new numerator value
01139         x += xinc1;               // Change the x as appropriate
01140         y += yinc1;               // Change the y as appropriate
01141       }
01142       x += xinc2;                 // Change the x as appropriate
01143       y += yinc2;                 // Change the y as appropriate
01144     }
01145   }
01146 
01147   //get the cellsof a footprint at a given position
01148   vector<iri_ackermann_local_planner::Position2DInt> TrajectoryPlanner::getFootprintCells(double x_i, double y_i, double theta_i, bool fill){
01149     vector<iri_ackermann_local_planner::Position2DInt> footprint_cells;
01150 
01151     //if we have no footprint... do nothing
01152     if(footprint_spec_.size() <= 1){
01153       unsigned int mx, my;
01154       if(costmap_.worldToMap(x_i, y_i, mx, my)){
01155         Position2DInt center;
01156         center.x = mx;
01157         center.y = my;
01158         footprint_cells.push_back(center);
01159       }
01160       return footprint_cells;
01161     }
01162 
01163     //pre-compute cos and sin values
01164     double cos_th = cos(theta_i);
01165     double sin_th = sin(theta_i);
01166     double new_x, new_y;
01167     unsigned int x0, y0, x1, y1;
01168     unsigned int last_index = footprint_spec_.size() - 1;
01169 
01170     for(unsigned int i = 0; i < last_index; ++i){
01171       //find the cell coordinates of the first segment point
01172       new_x = x_i + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
01173       new_y = y_i + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
01174       if(!costmap_.worldToMap(new_x, new_y, x0, y0))
01175         return footprint_cells;
01176 
01177       //find the cell coordinates of the second segment point
01178       new_x = x_i + (footprint_spec_[i + 1].x * cos_th - footprint_spec_[i + 1].y * sin_th);
01179       new_y = y_i + (footprint_spec_[i + 1].x * sin_th + footprint_spec_[i + 1].y * cos_th);
01180       if(!costmap_.worldToMap(new_x, new_y, x1, y1))
01181         return footprint_cells;
01182 
01183       getLineCells(x0, x1, y0, y1, footprint_cells);
01184     }
01185 
01186     //we need to close the loop, so we also have to raytrace from the last pt to first pt
01187     new_x = x_i + (footprint_spec_[last_index].x * cos_th - footprint_spec_[last_index].y * sin_th);
01188     new_y = y_i + (footprint_spec_[last_index].x * sin_th + footprint_spec_[last_index].y * cos_th);
01189     if(!costmap_.worldToMap(new_x, new_y, x0, y0))
01190       return footprint_cells;
01191 
01192     new_x = x_i + (footprint_spec_[0].x * cos_th - footprint_spec_[0].y * sin_th);
01193     new_y = y_i + (footprint_spec_[0].x * sin_th + footprint_spec_[0].y * cos_th);
01194     if(!costmap_.worldToMap(new_x, new_y, x1, y1))
01195       return footprint_cells;
01196 
01197     getLineCells(x0, x1, y0, y1, footprint_cells);
01198 
01199     if(fill)
01200       getFillCells(footprint_cells);
01201 
01202     return footprint_cells;
01203   }
01204 
01205   void TrajectoryPlanner::getFillCells(vector<iri_ackermann_local_planner::Position2DInt>& footprint){
01206     //quick bubble sort to sort pts by x
01207     iri_ackermann_local_planner::Position2DInt swap, pt;
01208     unsigned int i = 0;
01209     while(i < footprint.size() - 1){
01210       if(footprint[i].x > footprint[i + 1].x){
01211         swap = footprint[i];
01212         footprint[i] = footprint[i + 1];
01213         footprint[i + 1] = swap;
01214         if(i > 0)
01215           --i;
01216       }
01217       else
01218         ++i;
01219     }
01220 
01221     i = 0;
01222     iri_ackermann_local_planner::Position2DInt min_pt;
01223     iri_ackermann_local_planner::Position2DInt max_pt;
01224     unsigned int min_x = footprint[0].x;
01225     unsigned int max_x = footprint[footprint.size() -1].x;
01226     //walk through each column and mark cells inside the footprint
01227     for(unsigned int x = min_x; x <= max_x; ++x){
01228       if(i >= footprint.size() - 1)
01229         break;
01230 
01231       if(footprint[i].y < footprint[i + 1].y){
01232         min_pt = footprint[i];
01233         max_pt = footprint[i + 1];
01234       }
01235       else{
01236         min_pt = footprint[i + 1];
01237         max_pt = footprint[i];
01238       }
01239 
01240       i += 2;
01241       while(i < footprint.size() && footprint[i].x == x){
01242         if(footprint[i].y < min_pt.y)
01243           min_pt = footprint[i];
01244         else if(footprint[i].y > max_pt.y)
01245           max_pt = footprint[i];
01246         ++i;
01247       }
01248 
01249       //loop though cells in the column
01250       for(unsigned int y = min_pt.y; y < max_pt.y; ++y){
01251         pt.x = x;
01252         pt.y = y;
01253         footprint.push_back(pt);
01254       }
01255     }
01256   }
01257 
01258   void TrajectoryPlanner::getLocalGoal(double& x, double& y){
01259     x = map_.goal_x_;
01260     y = map_.goal_y_;
01261   }
01262 
01263 };


iri_ackermann_local_planner
Author(s): Sergi Hernandez Juan
autogenerated on Fri Dec 6 2013 23:50:18