planner_core.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Author: Roman Fedorenko
00004  *
00005  *********************************************************************/
00006 #include <voronoi_planner/planner_core.h>
00007 #include <pluginlib/class_list_macros.h>
00008 #include <tf/transform_listener.h>
00009 #include <costmap_2d/cost_values.h>
00010 #include <costmap_2d/costmap_2d.h>
00011 
00012 
00013 //register this planner as a BaseGlobalPlanner plugin
00014 PLUGINLIB_EXPORT_CLASS(voronoi_planner::VoronoiPlanner, nav_core::BaseGlobalPlanner)
00015 
00016 namespace voronoi_planner {
00017 
00018 
00019     void visualize(const char *filename, DynamicVoronoi* voronoi, bool** map,
00020                    std::vector<std::pair<float, float> > *path) {
00021         // write pgm files
00022 
00023         FILE* F = fopen(filename, "w");
00024         if (!F) {
00025             std::cerr << "visualize: could not open file for writing!\n";
00026             return;
00027         }
00028         fprintf(F, "P6\n");
00029         fprintf(F, "%d %d 255\n", voronoi->getSizeX(), voronoi->getSizeY());
00030 
00031 
00032 
00033         for(int y = voronoi->getSizeY()-1; y >=0; y--){
00034             for(int x = 0; x<voronoi->getSizeX(); x++){
00035                 unsigned char c = 0;
00036                 if (voronoi->isVoronoi(x,y) && map[x][y] != 1) {
00037                     fputc( 255, F );
00038                     fputc( 0, F );
00039                     fputc( 0, F );
00040                 } else if (map[x][y] == 1 ) {
00041                     fputc( 255, F );
00042                     fputc( 255, F );
00043                     fputc( 255, F );
00044                 }
00045                 else
00046                 {
00047                     fputc( 0, F );
00048                     fputc( 0, F );
00049                     fputc( 0, F );
00050                 }
00051             }
00052         }
00053 
00054 
00055         fclose(F);
00056     }
00057 
00058 
00059 
00060 void VoronoiPlanner::outlineMap(unsigned char* costarr, int nx, int ny, unsigned char value) {
00061     unsigned char* pc = costarr;
00062     for (int i = 0; i < nx; i++)
00063         *pc++ = value;
00064     pc = costarr + (ny - 1) * nx;
00065     for (int i = 0; i < nx; i++)
00066         *pc++ = value;
00067     pc = costarr;
00068     for (int i = 0; i < ny; i++, pc += nx)
00069         *pc = value;
00070     pc = costarr + nx - 1;
00071     for (int i = 0; i < ny; i++, pc += nx)
00072         *pc = value;
00073 }
00074 
00075 VoronoiPlanner::VoronoiPlanner() :
00076         costmap_(NULL), initialized_(false), publish_voronoi_grid_(true),
00077         smooth_path_ (true), weight_data_ (0.5), weight_smooth_ (0.3) {
00078 }
00079 
00080 VoronoiPlanner::VoronoiPlanner(std::string name, costmap_2d::Costmap2D* costmap, std::string frame_id) :
00081         costmap_(NULL), initialized_(false), publish_voronoi_grid_(true),
00082         smooth_path_ (true), weight_data_ (0.5), weight_smooth_ (0.3)
00083 {
00084     //initialize the planner
00085     initialize(name, costmap, frame_id);
00086 }
00087 
00088 VoronoiPlanner::~VoronoiPlanner() {
00089 
00090 }
00091 
00092 void VoronoiPlanner::initialize(std::string name, costmap_2d::Costmap2DROS* costmap_ros) {
00093     initialize(name, costmap_ros->getCostmap(), costmap_ros->getGlobalFrameID());
00094 }
00095 
00096 void VoronoiPlanner::initialize(std::string name, costmap_2d::Costmap2D* costmap, std::string frame_id) {
00097     if (!initialized_) {
00098         ros::NodeHandle private_nh("~/" + name);
00099         costmap_ = costmap;
00100         frame_id_ = frame_id;
00101 
00102         unsigned int cx = costmap->getSizeInCellsX(), cy = costmap->getSizeInCellsY();
00103 
00104 
00105         plan_pub_ = private_nh.advertise<nav_msgs::Path>("plan", 1);
00106         voronoi_grid_pub_ = private_nh.advertise<nav_msgs::OccupancyGrid>("voronoi_grid", 1);
00107 
00108 
00109         //get the tf prefix
00110         ros::NodeHandle prefix_nh;
00111         tf_prefix_ = tf::getPrefixParam(prefix_nh);
00112 
00113         make_plan_srv_ = private_nh.advertiseService("make_plan", &VoronoiPlanner::makePlanService, this);
00114 
00115         dsrv_ = new dynamic_reconfigure::Server<voronoi_planner::VoronoiPlannerConfig>(ros::NodeHandle("~/" + name));
00116         dynamic_reconfigure::Server<voronoi_planner::VoronoiPlannerConfig>::CallbackType cb = boost::bind(
00117                 &VoronoiPlanner::reconfigureCB, this, _1, _2);
00118         dsrv_->setCallback(cb);
00119 
00120 
00121         ros::Subscriber costmapUpdateSubscriber = private_nh.subscribe("/move_base/global_costmap/costmap_updates", 10, &VoronoiPlanner::costmapUpdateCallback, this);
00122 
00123 
00124 
00125         initialized_ = true;
00126     } else
00127         ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00128 
00129 }
00130 
00131 void VoronoiPlanner::costmapUpdateCallback(const map_msgs::OccupancyGridUpdate::ConstPtr& msg)
00132 {
00133     ROS_INFO("Map update. x %d; y %d; w %d; h %d", msg->x, msg->y, msg->width, msg->height);
00134 }
00135 
00136 
00137 void VoronoiPlanner::reconfigureCB(voronoi_planner::VoronoiPlannerConfig& config, uint32_t level) {
00138     weight_data_ = config.weight_data;
00139     weight_smooth_ = config.weight_smooth;
00140 
00141     publish_voronoi_grid_ = config.publish_voronoi_grid;
00142     smooth_path_ = config.smooth_path;
00143 }
00144 
00145 void VoronoiPlanner::clearRobotCell(const tf::Stamped<tf::Pose>& global_pose, unsigned int mx, unsigned int my) {
00146     if (!initialized_) {
00147         ROS_ERROR(
00148                 "This planner has not been initialized yet, but it is being used, please call initialize() before use");
00149         return;
00150     }
00151 
00152     //set the associated costs in the cost map to be free
00153     costmap_->setCost(mx, my, costmap_2d::FREE_SPACE);
00154 }
00155 
00156 bool VoronoiPlanner::makePlanService(nav_msgs::GetPlan::Request& req, nav_msgs::GetPlan::Response& resp) {
00157     makePlan(req.start, req.goal, resp.plan.poses);
00158 
00159     resp.plan.header.stamp = ros::Time::now();
00160     resp.plan.header.frame_id = frame_id_;
00161 
00162     return true;
00163 }
00164 
00165 void VoronoiPlanner::mapToWorld(double mx, double my, double& wx, double& wy) {
00166     float convert_offset_ = 0;
00167     wx = costmap_->getOriginX() + (mx+convert_offset_) * costmap_->getResolution();
00168     wy = costmap_->getOriginY() + (my+convert_offset_) * costmap_->getResolution();
00169 }
00170 
00171 bool VoronoiPlanner::worldToMap(double wx, double wy, double& mx, double& my) {
00172     double origin_x = costmap_->getOriginX(), origin_y = costmap_->getOriginY();
00173     double resolution = costmap_->getResolution();
00174 
00175     if (wx < origin_x || wy < origin_y)
00176         return false;
00177 
00178     float convert_offset_ = 0;
00179     mx = (wx - origin_x) / resolution - convert_offset_;
00180     my = (wy - origin_y) / resolution - convert_offset_;
00181 
00182     if (mx < costmap_->getSizeInCellsX() && my < costmap_->getSizeInCellsY())
00183         return true;
00184 
00185     return false;
00186 }
00187 
00188 bool VoronoiPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal,
00189                            std::vector<geometry_msgs::PoseStamped>& plan) {
00190     return makePlan(start, goal, default_tolerance_, plan);
00191 }
00192 
00193 bool VoronoiPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal,
00194                            double tolerance, std::vector<geometry_msgs::PoseStamped>& plan) {
00195     boost::mutex::scoped_lock lock(mutex_);
00196     if (!initialized_) {
00197         ROS_ERROR(
00198                 "This planner has not been initialized yet, but it is being used, please call initialize() before use");
00199         return false;
00200     }
00201 
00202     //clear the plan, just in case
00203     plan.clear();
00204 
00205     ros::NodeHandle n;
00206     std::string global_frame = frame_id_;
00207 
00208     //until tf can handle transforming things that are way in the past... we'll require the goal to be in our global frame
00209     if (tf::resolve(tf_prefix_, goal.header.frame_id) != tf::resolve(tf_prefix_, global_frame)) {
00210         ROS_ERROR(
00211                 "The goal pose passed to this planner must be in the %s frame.  It is instead in the %s frame.", tf::resolve(tf_prefix_, global_frame).c_str(), tf::resolve(tf_prefix_, goal.header.frame_id).c_str());
00212         return false;
00213     }
00214 
00215     if (tf::resolve(tf_prefix_, start.header.frame_id) != tf::resolve(tf_prefix_, global_frame)) {
00216         ROS_ERROR(
00217                 "The start pose passed to this planner must be in the %s frame.  It is instead in the %s frame.", tf::resolve(tf_prefix_, global_frame).c_str(), tf::resolve(tf_prefix_, start.header.frame_id).c_str());
00218         return false;
00219     }
00220 
00221     double wx = start.pose.position.x;
00222     double wy = start.pose.position.y;
00223 
00224     unsigned int start_x_i, start_y_i, goal_x_i, goal_y_i;
00225     double start_x, start_y, goal_x, goal_y;
00226 
00227     if (!costmap_->worldToMap(wx, wy, start_x_i, start_y_i)) {
00228         ROS_WARN(
00229                 "The robot's start position is off the global costmap. Planning will always fail, are you sure the robot has been properly localized?");
00230         return false;
00231     }
00232     worldToMap(wx, wy, start_x, start_y);
00233 
00234 
00235     wx = goal.pose.position.x;
00236     wy = goal.pose.position.y;
00237 
00238     if (!costmap_->worldToMap(wx, wy, goal_x_i, goal_y_i)) {
00239         ROS_WARN_THROTTLE(1.0,
00240                 "The goal sent to the global planner is off the global costmap. Planning will always fail to this goal.");
00241         return false;
00242     }
00243     worldToMap(wx, wy, goal_x, goal_y);
00244 
00245 
00246     //clear the starting cell within the costmap because we know it can't be an obstacle
00247     tf::Stamped<tf::Pose> start_pose;
00248     tf::poseStampedMsgToTF(start, start_pose);
00249     clearRobotCell(start_pose, start_x_i, start_y_i);
00250 
00251     int nx = costmap_->getSizeInCellsX(), ny = costmap_->getSizeInCellsY();
00252 
00253     outlineMap(costmap_->getCharMap(), nx, ny, costmap_2d::LETHAL_OBSTACLE);
00254 
00255 
00256 
00257 
00258 
00259     bool **map=NULL;
00260     int sizeX, sizeY;
00261 
00262     sizeX = costmap_->getSizeInCellsX();
00263     sizeY = costmap_->getSizeInCellsY();
00264 
00265 
00266     map = new bool*[sizeX];
00267 
00268 //    ROS_INFO("Map size is %d %d", sizeX, sizeY);
00269 
00270     ros::Time t = ros::Time::now();
00271     ros::Time t_b = ros::Time::now();
00272 
00273 
00274     for (int x=0; x<sizeX; x++) {
00275         (map)[x] = new bool[sizeY];
00276     }
00277 
00278     for (int y=sizeY-1; y>=0; y--) {
00279         for (int x=0; x<sizeX; x++) {
00280             unsigned char c = costmap_->getCost(x,y);
00281 
00282             if ( c == costmap_2d::FREE_SPACE || c == costmap_2d::NO_INFORMATION )
00283                 (map)[x][y] = false; // cell is free
00284             else (map)[x][y] = true;// cell is occupied
00285         }
00286     }
00287 
00288     ROS_INFO("Time (for map convert): %f sec", (ros::Time::now() - t).toSec());
00289     t = ros::Time::now();
00290 
00291 
00292     bool doPrune = true;
00293 
00294 
00295     // initialize voronoi object it with the map
00296 
00297     ROS_INFO("voronoi.initializeMap");
00298     voronoi_.initializeMap(sizeX, sizeY, map);
00299     ROS_INFO("Time (for initializeMap): %f sec", (ros::Time::now() - t).toSec());
00300     t = ros::Time::now();
00301 
00302 
00303 
00304     ROS_INFO("voronoi.update");
00305     voronoi_.update(); // update distance map and Voronoi diagram
00306     ROS_INFO("Time (for update): %f sec", (ros::Time::now() - t).toSec());
00307     t = ros::Time::now();
00308 
00309 
00310 
00311     ROS_INFO("voronoi.prune");
00312     if (doPrune) voronoi_.prune();  // prune the Voronoi
00313     ROS_INFO("Time (for prune): %f sec", (ros::Time::now() - t).toSec());
00314     t = ros::Time::now();
00315 
00316 
00317 
00318 //    ROS_INFO("voronoi.visualize");
00319 //    voronoi_.visualize("/tmp/initial.ppm");
00320 //    ROS_INFO("Time (for visualize): %f sec", (ros::Time::now() - t).toSec());
00321 
00322 
00323     std::cerr << "Generated initial frame.\n";
00324 
00325 
00326 
00327     std::vector<std::pair<float, float> > path1;
00328     std::vector<std::pair<float, float> > path2;
00329     std::vector<std::pair<float, float> > path3;
00330 
00331 //    start_x = 10;
00332 //    start_y = 100;
00333 //    goal_x = 300;
00334 //    goal_y = 330;
00335 
00336 
00337     std::cout << "start_x,start_y " << start_x <<
00338               " " << start_y << std::endl;
00339     std::cout << "goal_x,goal_y " << goal_x <<
00340               " " << goal_y << std::endl;
00341 
00342 
00343     bool res1 = false, res2 = false, res3 = false;
00344 
00345     if( !voronoi_.isVoronoi(goal_x,goal_y) )
00346     {
00347         //        path3 = findPath( goal, init, A, 0, 1 );
00348         res3 = findPath( &path3, goal_x, goal_y, start_x, start_y, &voronoi_, 0, 1 );
00349         std::cout << "findPath 3 res " << res3 << std::endl;
00350         //        goal = path3(end,:);
00351         goal_x = std::get<0>( path3[path3.size()-1] );
00352         goal_y = std::get<1>( path3[path3.size()-1] );
00353 
00354         std::cout << "voronoi.isVoronoi(goal_x,goal_y) " << voronoi_.isVoronoi(goal_x,goal_y) << std::endl;
00355 
00356 
00357         //        path3 = flipud(path3);
00358         std::reverse(path3.begin(), path3.end());
00359     }
00360 
00361     if( !voronoi_.isVoronoi(start_x,start_y) )
00362     {
00363         res1 = findPath( &path1, start_x, start_y, goal_x, goal_y, &voronoi_, 0, 1 );
00364         std::cout << "findPath 1 res " << res1 << std::endl;
00365         start_x = std::get<0>( path1[path1.size()-1] );
00366         start_y = std::get<1>( path1[path1.size()-1] );
00367 
00368         std::cout << "voronoi.isVoronoi(start_x,start_y) " << voronoi_.isVoronoi(start_x,start_y) << std::endl;
00369     }
00370 
00371     res2 = findPath( &path2, start_x, start_y, goal_x, goal_y, &voronoi_, 1, 0 );
00372     std::cout << "findPath 2 res " << res2 << std::endl;
00373 
00374 
00375     if(!(res1 && res2 && res3))
00376     {
00377         ROS_INFO("Failed to find full path");
00378     }
00379 //    else
00380 //    {
00381 
00382 //    path = [path1;path2;path3];
00383     path1.insert( path1.end(), path2.begin(), path2.end() );
00384     path1.insert( path1.end(), path3.begin(), path3.end() );
00385 
00386 
00387     for(int i = 0; i < path1.size(); i++)
00388     {
00389         int x = std::get<0>(path1[i]);
00390         int y = std::get<1>(path1[i]);
00391 
00392 
00393 //        std::cout << "[" << x << "; " <<
00394 //                     y << "]" << std::endl;
00395 
00396         if(x > 0 && y > 0)
00397             map[x][y] = 1;
00398     }
00399 
00400 //    if(smooth_path_){
00401 //        smoothPath(&path1);
00402 //    }
00403 
00404 //    visualize("/tmp/plan.ppm", &voronoi_, map, &path1);
00405 
00406 
00407     for(int i = 0; i < path1.size(); i++)
00408     {
00409 
00410         geometry_msgs::PoseStamped new_goal = goal;
00411         tf::Quaternion goal_quat = tf::createQuaternionFromYaw(1.54);
00412 
00413         new_goal.pose.position.x = std::get<0>(path1[i]);
00414         new_goal.pose.position.y = std::get<1>(path1[i]);
00415 
00416         mapToWorld(new_goal.pose.position.x, new_goal.pose.position.y,
00417                    new_goal.pose.position.x, new_goal.pose.position.y);
00418 
00419 //        std::cout << "[" << new_goal.pose.position.x << "; " <<
00420 //                     new_goal.pose.position.y << "]" << std::endl;
00421 
00422 
00423 
00424         new_goal.pose.orientation.x = goal_quat.x();
00425         new_goal.pose.orientation.y = goal_quat.y();
00426         new_goal.pose.orientation.z = goal_quat.z();
00427         new_goal.pose.orientation.w = goal_quat.w();
00428         plan.push_back( new_goal );
00429     }
00430 
00431     // add orientations if needed
00432 //    orientation_filter_->processPath(start, plan);
00433 
00434 //    }
00435 
00436     ROS_ERROR("\nTime to get plan: %f sec\n", (ros::Time::now() - t_b).toSec());
00437 
00438 
00439     //publish the plan for visualization purposes
00440     publishPlan(plan);
00441 
00442     if(publish_voronoi_grid_){
00443         publishVoronoiGrid(&voronoi_);
00444     }
00445 
00446 //    delete potential_array_;
00447     return !plan.empty();
00448 }
00449 
00450 bool VoronoiPlanner::findPath(std::vector<std::pair<float, float> > *path,
00451               int init_x, int init_y,
00452               int goal_x, int goal_y,
00453               DynamicVoronoi *voronoi,
00454               bool check_is_voronoi_cell,
00455               bool stop_at_voronoi )
00456 {
00457 //    ROS_INFO("init_x %d, init_y %d, goal_x %d, goal_y %d, check_is_voronoi_cell %d, stop_at_voronoi %d", init_x, init_y, goal_x, goal_y, check_is_voronoi_cell, stop_at_voronoi);
00458 //    ROS_INFO("isVoronoi(init) %d; isVoronoi(goal) %d", voronoi->isVoronoi(init_x, init_y), voronoi->isVoronoi(goal_x, goal_y) );
00459     // available movements (actions) of the robot on the grid
00460     std::vector<std::pair<int, int> > delta;
00461     delta.push_back( {-1, 0} );     // go up
00462     delta.push_back( {0, -1} );     // go left
00463     delta.push_back( {1, 0} );      // go down
00464     delta.push_back( {0, 1} );      // go right
00465     delta.push_back( {-1, -1} );    // up and left
00466     delta.push_back( {-1, 1} );     // up and right
00467     delta.push_back( {1, -1} );     // down and left
00468     delta.push_back( {1,  1} );     // down and right
00469 
00470     // cost of movement
00471     float cost = 1;
00472 
00473     // grid size
00474     unsigned int sizeX = voronoi->getSizeX();
00475     unsigned int sizeY = voronoi->getSizeY();
00476 
00477     // closed cells grid (same size as map grid)
00478     bool **closed=NULL;
00479     closed = new bool*[sizeX];
00480     for (int x=0; x<sizeX; x++) {
00481         (closed)[x] = new bool[sizeY];
00482     }
00483 
00484     for (int y=sizeY-1; y>=0; y--) {
00485         for (int x=0; x<sizeX; x++) {
00486             (closed)[x][y] = false;
00487         }
00488     }
00489 
00490     //heuristic = zeros(szA(1), szA(2));
00491     //for(i=1:szA(1))
00492     //    for(j=1:szA(2))
00493     //        heuristic(i,j) = norm( [i - goal(1); j - goal(2)] );
00494     //    end
00495     //end
00496 
00497     // actions (number of delta's row) cells grid (same size as map grid)
00498     int **action=NULL;
00499     action = new int*[sizeX];
00500     for (int x=0; x<sizeX; x++) {
00501         (action)[x] = new int[sizeY];
00502     }
00503     for (int y=sizeY-1; y>=0; y--) {
00504         for (int x=0; x<sizeX; x++) {
00505             (action)[x][y] = -1;
00506         }
00507     }
00508 
00509     // set current cell
00510     int x = init_x;
00511     int y = init_y;
00512 
00513     // set cost
00514     float g = 0;
00515 
00516     //f = heuristic(x,y) + g;
00517 
00518     // vector of open (for possible expansion) nodes
00519     std::vector<std::tuple<float, int, int> > open;
00520     open.push_back( std::make_tuple( g, x, y ) );
00521 
00522     // path found flag
00523     bool found = false;
00524     // no solution could be found flag
00525     bool resign = false;
00526 
00527     while( !found && !resign )
00528     {
00529         if (open.size() == 0)
00530         {
00531             resign = true;
00532             path->empty();
00533             return false;
00534         }
00535         else
00536         {
00537             // sort open by cost
00538             sort(open.begin(), open.end());
00539             reverse(open.begin(), open.end());
00540             // get node with lowest cost
00541             std::tuple<float, int, int> next = open[open.size()-1];
00542             open.pop_back();
00543             g = std::get<0>(next);
00544             x = std::get<1>(next);
00545             y = std::get<2>(next);
00546 
00547             // check, whether the solution is found (we are at the goal)
00548             if(stop_at_voronoi)
00549             {
00550                 // if stop_at_voronoi is set, we stop, when get path to any voronoi cell
00551                 if(voronoi->isVoronoi(x,y))
00552                 {
00553                     found = true;
00554                     goal_x = x;
00555                     goal_y = y;
00556                     continue;
00557                 }
00558             }
00559             else
00560             {
00561                 if ( x == goal_x && y == goal_y )
00562                 {
00563                     found = true;
00564                     continue;
00565                 }
00566             }
00567             for( int i=0; i < delta.size(); i++ )
00568             {
00569                 // expansion
00570                 int x2 = x + std::get<0>(delta[i]);
00571                 int y2 = y + std::get<1>(delta[i]);
00572 
00573                 // check new node to be in grid bounds
00574                 if ( x2 >= 0 && x2 < sizeX && y2 >= 0 && y2 < sizeY )
00575                 {
00576                     // check new node not to be in obstacle
00577                     if(voronoi->isOccupied(x2,y2))
00578                     {
00579                         continue;
00580                     }
00581                     // check new node was not early visited
00582                     if ( closed[x2][y2] ){
00583                         continue;
00584                     }
00585 
00586                     // check new node is on Voronoi diagram
00587                     if (!voronoi->isVoronoi(x2,y2) && check_is_voronoi_cell){
00588                         continue;
00589                     }
00590 
00591                     float g2 = g + cost;
00592                     //                        f2 = heuristic(x2,y2) + g2;
00593                     open.push_back( std::make_tuple( g2, x2, y2 ) );
00594                     closed[x2][y2] = true;
00595                     action[x2][y2] = i;
00596                 }
00597             }
00598         }
00599     }
00600 
00601     // Make reverse steps from goal to init to write path
00602     x = goal_x;
00603     y = goal_y;
00604 
00605     int i = 0;
00606     path->clear();
00607 
00608     while( x != init_x || y != init_y )
00609     {
00610         path->push_back({x,y});
00611         i++;
00612 
00613         int x2 = x - std::get<0>( delta[ action[x][y] ] );
00614         int y2 = y - std::get<1>( delta[ action[x][y] ] );
00615 
00616 
00617         x = x2;
00618         y = y2;
00619     }
00620 
00621     reverse(path->begin(), path->end());
00622     return true;
00623 }
00624 
00625 
00626 
00627 
00628 void VoronoiPlanner::smoothPath(std::vector<std::pair<float, float> > *path)
00629 {
00630     // Make a deep copy of path into newpath
00631     std::vector<std::pair<float, float> > newpath = *path;
00632 
00633     float tolerance = 0.00001;
00634     float change = tolerance;
00635 
00636     if(path->size() < 2)
00637         return;
00638 
00639     while (change >= tolerance)
00640     {
00641 
00642         change = 0.0;
00643         for(int i = 1; i < path->size() - 1; i++)
00644         {
00645             float aux_x = newpath[i].first;
00646             float aux_y = newpath[i].second;
00647 
00648 
00649             float newpath_x = newpath[i].first + weight_data_ * ( path->at(i).first - newpath[i].first);
00650             float newpath_y = newpath[i].second + weight_data_ * ( path->at(i).second - newpath[i].second);
00651 
00652 
00653             newpath_x = newpath_x + weight_smooth_ *
00654                     (newpath[i-1].first + newpath[i+1].first - (2.0 * newpath_x));
00655             newpath_y = newpath_y + weight_smooth_ *
00656                     (newpath[i-1].second + newpath[i+1].second - (2.0 * newpath_y));
00657 
00658             change = change + fabs(aux_x - newpath_x);
00659             change = change + fabs(aux_y - newpath_y);
00660 
00661             newpath[i] = std::make_pair(newpath_x,newpath_y);
00662         }
00663     }
00664     *path = newpath;
00665 }
00666 
00667 
00668 void VoronoiPlanner::publishPlan(const std::vector<geometry_msgs::PoseStamped>& path) {
00669     if (!initialized_) {
00670         ROS_ERROR(
00671                 "This planner has not been initialized yet, but it is being used, please call initialize() before use");
00672         return;
00673     }
00674 
00675     //create a message for the plan
00676     nav_msgs::Path gui_path;
00677     gui_path.poses.resize(path.size());
00678 
00679     if (!path.empty()) {
00680         gui_path.header.frame_id = path[0].header.frame_id;
00681         gui_path.header.stamp = ros::Time::now();
00682     }
00683 
00684     // Extract the plan in world co-ordinates, we assume the path is all in the same frame
00685     for (unsigned int i = 0; i < path.size(); i++) {
00686         gui_path.poses[i] = path[i];
00687     }
00688 
00689     plan_pub_.publish(gui_path);
00690 }
00691 
00692 void VoronoiPlanner::publishVoronoiGrid(DynamicVoronoi *voronoi)
00693 {
00694     int nx = costmap_->getSizeInCellsX(), ny = costmap_->getSizeInCellsY();
00695 
00696     ROS_WARN("costmap sx = %d,sy = %d, voronoi sx = %d, sy = %d", nx, ny,
00697              voronoi->getSizeX(), voronoi->getSizeY());
00698 
00699     double resolution = costmap_->getResolution();
00700     nav_msgs::OccupancyGrid grid;
00701     // Publish Whole Grid
00702     grid.header.frame_id = frame_id_;
00703     grid.header.stamp = ros::Time::now();
00704     grid.info.resolution = resolution;
00705 
00706     grid.info.width = nx;
00707     grid.info.height = ny;
00708 
00709     double wx, wy;
00710     costmap_->mapToWorld(0, 0, wx, wy);
00711     grid.info.origin.position.x = wx - resolution / 2;
00712     grid.info.origin.position.y = wy - resolution / 2;
00713     grid.info.origin.position.z = 0.0;
00714     grid.info.origin.orientation.w = 1.0;
00715 
00716     grid.data.resize(nx * ny);
00717 
00718     for (unsigned int x = 0; x < nx; x++)
00719     {
00720         for (unsigned int y = 0; y < ny; y++)
00721         {
00722             if(voronoi->isVoronoi(x,y))
00723                 grid.data[x + y*nx] = 128;
00724             else
00725                 grid.data[x + y*nx] = 0;
00726         }
00727     }
00728     voronoi_grid_pub_.publish(grid);
00729 }
00730 
00731 
00732 
00733 } //end namespace voronoi_planner
00734 


voronoi_planner
Author(s): Roman Fedorenko
autogenerated on Sat Jun 8 2019 20:10:29