FootstepPlanner.cpp
Go to the documentation of this file.
00001 // SVN $HeadURL$
00002 // SVN $Id$
00003 
00004 /*
00005  * A footstep planner for humanoid robots
00006  *
00007  * Copyright 2010-2011 Johannes Garimort, Armin Hornung, University of Freiburg
00008  * http://www.ros.org/wiki/footstep_planner
00009  *
00010  *
00011  * This program is free software: you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation, version 3.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00022  */
00023 
00024 #include <footstep_planner/FootstepPlanner.h>
00025 #include <humanoid_nav_msgs/ClipFootstep.h>
00026 
00027 
00028 using gridmap_2d::GridMap2D;
00029 using gridmap_2d::GridMap2DPtr;
00030 
00031 
00032 namespace footstep_planner
00033 {
00034 FootstepPlanner::FootstepPlanner()
00035 : ivStartPoseSetUp(false),
00036   ivGoalPoseSetUp(false),
00037   ivLastMarkerMsgSize(0),
00038   ivPathCost(0),
00039   ivMarkerNamespace("")
00040 {
00041   // private NodeHandle for parameters and private messages (debug / info)
00042   ros::NodeHandle nh_private("~");
00043   ros::NodeHandle nh_public;
00044 
00045   // ..publishers
00046   ivExpandedStatesVisPub = nh_private.advertise<
00047       sensor_msgs::PointCloud>("expanded_states", 1);
00048   ivRandomStatesVisPub = nh_private.advertise<
00049       sensor_msgs::PointCloud>("random_states", 1);
00050   ivFootstepPathVisPub = nh_private.advertise<
00051       visualization_msgs::MarkerArray>("footsteps_array", 1);
00052   ivHeuristicPathVisPub = nh_private.advertise<
00053       nav_msgs::Path>("heuristic_path", 1);
00054   ivPathVisPub = nh_private.advertise<nav_msgs::Path>("path", 1);
00055   ivStartPoseVisPub = nh_private.advertise<
00056       geometry_msgs::PoseStamped>("start", 1);
00057 
00058   std::string heuristic_type;
00059   double diff_angle_cost;
00060 
00061   // read parameters from config file:
00062   // planner environment settings
00063   nh_private.param("heuristic_type", heuristic_type,
00064                    std::string("EuclideanHeuristic"));
00065   nh_private.param("heuristic_scale", ivEnvironmentParams.heuristic_scale, 1.0);
00066   nh_private.param("max_hash_size", ivEnvironmentParams.hash_table_size, 65536);
00067   nh_private.param("accuracy/collision_check",
00068                    ivEnvironmentParams.collision_check_accuracy,
00069                    2);
00070   nh_private.param("accuracy/cell_size", ivEnvironmentParams.cell_size, 0.01);
00071   nh_private.param("accuracy/num_angle_bins",
00072                    ivEnvironmentParams.num_angle_bins,
00073                    64);
00074   nh_private.param("step_cost", ivEnvironmentParams.step_cost, 0.05);
00075   nh_private.param("diff_angle_cost", diff_angle_cost, 0.0);
00076 
00077   nh_private.param("planner_type", ivPlannerType, std::string("ARAPlanner"));
00078   nh_private.param("search_until_first_solution", ivSearchUntilFirstSolution,
00079                    false);
00080   nh_private.param("allocated_time", ivMaxSearchTime, 7.0);
00081   nh_private.param("forward_search", ivEnvironmentParams.forward_search, false);
00082   nh_private.param("initial_epsilon", ivInitialEpsilon, 3.0);
00083   nh_private.param("changed_cells_limit", ivChangedCellsLimit, 20000);
00084   nh_private.param("num_random_nodes", ivEnvironmentParams.num_random_nodes,
00085                    20);
00086   nh_private.param("random_node_dist", ivEnvironmentParams.random_node_distance,
00087                    1.0);
00088 
00089   // footstep settings
00090   nh_private.param("foot/size/x", ivEnvironmentParams.footsize_x, 0.16);
00091   nh_private.param("foot/size/y", ivEnvironmentParams.footsize_y, 0.06);
00092   nh_private.param("foot/size/z", ivEnvironmentParams.footsize_z, 0.015);
00093   nh_private.param("foot/separation", ivFootSeparation, 0.1);
00094   nh_private.param("foot/origin_shift/x",
00095                    ivEnvironmentParams.foot_origin_shift_x,
00096                    0.02);
00097   nh_private.param("foot/origin_shift/y",
00098                    ivEnvironmentParams.foot_origin_shift_y,
00099                    0.0);
00100   nh_private.param("foot/max/step/x", ivEnvironmentParams.max_footstep_x, 0.08);
00101   nh_private.param("foot/max/step/y", ivEnvironmentParams.max_footstep_y, 0.16);
00102   nh_private.param("foot/max/step/theta",
00103                    ivEnvironmentParams.max_footstep_theta,
00104                    0.3);
00105   nh_private.param("foot/max/inverse/step/x",
00106                    ivEnvironmentParams.max_inverse_footstep_x,
00107                    -0.04);
00108   nh_private.param("foot/max/inverse/step/y",
00109                    ivEnvironmentParams.max_inverse_footstep_y,
00110                    0.09);
00111   nh_private.param("foot/max/inverse/step/theta",
00112                    ivEnvironmentParams.max_inverse_footstep_theta,
00113                    -0.3);
00114 
00115   // footstep discretization
00116   XmlRpc::XmlRpcValue footsteps_x;
00117   XmlRpc::XmlRpcValue footsteps_y;
00118   XmlRpc::XmlRpcValue footsteps_theta;
00119   nh_private.getParam("footsteps/x", footsteps_x);
00120   nh_private.getParam("footsteps/y", footsteps_y);
00121   nh_private.getParam("footsteps/theta", footsteps_theta);
00122   if (footsteps_x.getType() != XmlRpc::XmlRpcValue::TypeArray)
00123     ROS_ERROR("Error reading footsteps/x from config file.");
00124   if (footsteps_y.getType() != XmlRpc::XmlRpcValue::TypeArray)
00125     ROS_ERROR("Error reading footsteps/y from config file.");
00126   if (footsteps_theta.getType() != XmlRpc::XmlRpcValue::TypeArray)
00127     ROS_ERROR("Error reading footsteps/theta from config file.");
00128   int size_x = footsteps_x.size();
00129   int size_y = footsteps_y.size();
00130   int size_t = footsteps_theta.size();
00131   if (size_x != size_y || size_x != size_t)
00132   {
00133     ROS_ERROR("Footstep parameterization has different sizes for x/y/theta. "
00134               "Exit!");
00135     exit(2);
00136   }
00137   // create footstep set
00138   ivEnvironmentParams.footstep_set.clear();
00139   double max_step_width = 0;
00140   for(int i=0; i < footsteps_x.size(); ++i)
00141   {
00142     double x = (double)footsteps_x[i];
00143     double y = (double)footsteps_y[i];
00144     double theta = (double)footsteps_theta[i];
00145 
00146     Footstep f(x, y, theta,
00147                ivEnvironmentParams.cell_size,
00148                ivEnvironmentParams.num_angle_bins,
00149                ivEnvironmentParams.hash_table_size);
00150     ivEnvironmentParams.footstep_set.push_back(f);
00151 
00152     double cur_step_width = sqrt(x*x + y*y);
00153 
00154     if (cur_step_width > max_step_width)
00155       max_step_width = cur_step_width;
00156   }
00157 
00158   // step range
00159   XmlRpc::XmlRpcValue step_range_x;
00160   XmlRpc::XmlRpcValue step_range_y;
00161   nh_private.getParam("step_range/x", step_range_x);
00162   nh_private.getParam("step_range/y", step_range_y);
00163   if (step_range_x.getType() != XmlRpc::XmlRpcValue::TypeArray)
00164     ROS_ERROR("Error reading footsteps/x from config file.");
00165   if (step_range_y.getType() != XmlRpc::XmlRpcValue::TypeArray)
00166     ROS_ERROR("Error reading footsteps/y from config file.");
00167   if (step_range_x.size() != step_range_y.size())
00168   {
00169     ROS_ERROR("Step range points have different size. Exit!");
00170     exit(2);
00171   }
00172   // create step range
00173   ivEnvironmentParams.step_range.clear();
00174   ivEnvironmentParams.step_range.reserve(step_range_x.size());
00175   double x, y;
00176   double max_x = 0.0;
00177   double max_y = 0.0;
00178   double cell_size = ivEnvironmentParams.cell_size;
00179   for (int i=0; i < step_range_x.size(); ++i)
00180   {
00181     x = (double)step_range_x[i];
00182     y = (double)step_range_y[i];
00183     if (fabs(x) > max_x)
00184       max_x = fabs(x);
00185     if (fabs(y) > max_y)
00186       max_y = fabs(y);
00187     ivEnvironmentParams.step_range.push_back(
00188       std::pair<int, int>(disc_val(x, cell_size), disc_val(y, cell_size)));
00189   }
00190   // insert first point again at the end!
00191   ivEnvironmentParams.step_range.push_back(ivEnvironmentParams.step_range[0]);
00192   ivEnvironmentParams.max_step_width = sqrt(max_x*max_x + max_y*max_y) * 1.5;
00193 
00194   // initialize the heuristic
00195   boost::shared_ptr<Heuristic> h;
00196   if (heuristic_type == "EuclideanHeuristic")
00197   {
00198     h.reset(
00199         new EuclideanHeuristic(ivEnvironmentParams.cell_size,
00200                                ivEnvironmentParams.num_angle_bins));
00201     ROS_INFO("FootstepPlanner heuristic: euclidean distance");
00202   }
00203   else if(heuristic_type == "EuclStepCostHeuristic")
00204   {
00205     h.reset(
00206         new EuclStepCostHeuristic(ivEnvironmentParams.cell_size,
00207                                   ivEnvironmentParams.num_angle_bins,
00208                                   ivEnvironmentParams.step_cost,
00209                                   diff_angle_cost,
00210                                   max_step_width));
00211     ROS_INFO("FootstepPlanner heuristic: euclidean distance with step costs");
00212   }
00213   else if (heuristic_type == "PathCostHeuristic")
00214   {
00215     // for heuristic inflation
00216     double foot_incircle =
00217       std::min((ivEnvironmentParams.footsize_x / 2.0 -
00218                 std::abs(ivEnvironmentParams.foot_origin_shift_x)),
00219                (ivEnvironmentParams.footsize_y / 2.0 -
00220                 std::abs(ivEnvironmentParams.foot_origin_shift_y)));
00221     assert(foot_incircle > 0.0);
00222 
00223     h.reset(
00224         new PathCostHeuristic(ivEnvironmentParams.cell_size,
00225                               ivEnvironmentParams.num_angle_bins,
00226                               ivEnvironmentParams.step_cost,
00227                               diff_angle_cost,
00228                               max_step_width,
00229                               foot_incircle));
00230     ROS_INFO("FootstepPlanner heuristic: 2D path euclidean distance with step "
00231              "costs");
00232 
00233     // keep a local ptr for visualization
00234     ivPathCostHeuristicPtr = boost::dynamic_pointer_cast<PathCostHeuristic>(h);
00235   }
00236   else
00237   {
00238     ROS_ERROR_STREAM("Heuristic " << heuristic_type << " not available, "
00239                      "exiting.");
00240     exit(1);
00241   }
00242   ivEnvironmentParams.heuristic = h;
00243 
00244   // initialize the planner environment
00245   ivPlannerEnvironmentPtr.reset(
00246     new FootstepPlannerEnvironment(ivEnvironmentParams));
00247 
00248   // set up planner
00249   if (ivPlannerType == "ARAPlanner" ||
00250       ivPlannerType == "ADPlanner"  ||
00251       ivPlannerType == "RSTARPlanner" )
00252   {
00253     ROS_INFO_STREAM("Planning with " << ivPlannerType);
00254   }
00255   else
00256   {
00257     ROS_ERROR_STREAM("Planner "<< ivPlannerType <<" not available / "
00258                      "untested.");
00259     exit(1);
00260   }
00261   if (ivEnvironmentParams.forward_search)
00262   {
00263     ROS_INFO_STREAM("Search direction: forward planning");
00264   }
00265   else
00266   {
00267     ROS_INFO_STREAM("Search direction: backward planning");
00268   }
00269   setPlanner();
00270 }
00271 
00272 
00273 FootstepPlanner::~FootstepPlanner()
00274 {}
00275 
00276 
00277 void
00278 FootstepPlanner::setPlanner()
00279 {
00280   if (ivPlannerType == "ARAPlanner")
00281   {
00282     ivPlannerPtr.reset(
00283         new ARAPlanner(ivPlannerEnvironmentPtr.get(),
00284                        ivEnvironmentParams.forward_search));
00285   }
00286   else if (ivPlannerType == "ADPlanner")
00287   {
00288     ivPlannerPtr.reset(
00289         new ADPlanner(ivPlannerEnvironmentPtr.get(),
00290                       ivEnvironmentParams.forward_search));
00291   }
00292   else if (ivPlannerType == "RSTARPlanner")
00293   {
00294     RSTARPlanner* p =
00295         new RSTARPlanner(ivPlannerEnvironmentPtr.get(),
00296                          ivEnvironmentParams.forward_search);
00297     // new options, require patched SBPL
00298     //          p->set_local_expand_thres(500);
00299     //          p->set_eps_step(1.0);
00300     ivPlannerPtr.reset(p);
00301   }
00302   //        else if (ivPlannerType == "ANAPlanner")
00303   //            ivPlannerPtr.reset(new anaPlanner(ivPlannerEnvironmentPtr.get(),
00304   //                                              ivForwardSearch));
00305 }
00306 
00307 
00308 bool
00309 FootstepPlanner::run()
00310 {
00311   bool path_existed = (bool)ivPath.size();
00312   int ret = 0;
00313   MDPConfig mdp_config;
00314   std::vector<int> solution_state_ids;
00315 
00316   // commit start/goal poses to the environment
00317   ivPlannerEnvironmentPtr->updateStart(ivStartFootLeft, ivStartFootRight);
00318   ivPlannerEnvironmentPtr->updateGoal(ivGoalFootLeft, ivGoalFootRight);
00319   ivPlannerEnvironmentPtr->updateHeuristicValues();
00320   ivPlannerEnvironmentPtr->InitializeEnv(NULL);
00321   ivPlannerEnvironmentPtr->InitializeMDPCfg(&mdp_config);
00322 
00323   // inform AD planner about changed (start) states for replanning
00324   if (path_existed &&
00325       !ivEnvironmentParams.forward_search &&
00326       ivPlannerType == "ADPlanner")
00327   {
00328     std::vector<int> changed_edges;
00329     changed_edges.push_back(mdp_config.startstateid);
00330     // update the AD planner
00331     boost::shared_ptr<ADPlanner> ad_planner =
00332       boost::dynamic_pointer_cast<ADPlanner>(ivPlannerPtr);
00333     ad_planner->update_preds_of_changededges(&changed_edges);
00334   }
00335 
00336   // set up SBPL
00337   if (ivPlannerPtr->set_start(mdp_config.startstateid) == 0)
00338   {
00339     ROS_ERROR("Failed to set start state.");
00340     return false;
00341   }
00342   if (ivPlannerPtr->set_goal(mdp_config.goalstateid) == 0)
00343   {
00344     ROS_ERROR("Failed to set goal state\n");
00345     return false;
00346   }
00347 
00348   ivPlannerPtr->set_initialsolution_eps(ivInitialEpsilon);
00349   ivPlannerPtr->set_search_mode(ivSearchUntilFirstSolution);
00350 
00351   ROS_INFO("Start planning (max time: %f, initial eps: %f (%f))\n",
00352            ivMaxSearchTime, ivInitialEpsilon,
00353            ivPlannerPtr->get_initial_eps());
00354   int path_cost;
00355   ros::WallTime startTime = ros::WallTime::now();
00356   try
00357   {
00358     ret = ivPlannerPtr->replan(ivMaxSearchTime, &solution_state_ids,
00359                                &path_cost);
00360   }
00361   catch (const SBPL_Exception& e)
00362   {
00363     // ROS_ERROR("SBPL planning failed (%s)", e.what());
00364     return false;
00365   }
00366   ivPathCost = double(path_cost) / FootstepPlannerEnvironment::cvMmScale;
00367 
00368   bool path_is_new = pathIsNew(solution_state_ids);
00369   if (ret && solution_state_ids.size() > 0 && path_is_new)
00370   {
00371     ROS_INFO("Solution of size %zu found after %f s",
00372              solution_state_ids.size(),
00373              (ros::WallTime::now()-startTime).toSec());
00374 
00375     if (extractPath(solution_state_ids))
00376     {
00377       ROS_INFO("Expanded states: %i total / %i new",
00378                ivPlannerEnvironmentPtr->getNumExpandedStates(),
00379                ivPlannerPtr->get_n_expands());
00380       ROS_INFO("Final eps: %f", ivPlannerPtr->get_final_epsilon());
00381       ROS_INFO("Path cost: %f (%i)\n", ivPathCost, path_cost);
00382 
00383       ivPlanningStatesIds = solution_state_ids;
00384 
00385       broadcastExpandedNodesVis();
00386       broadcastRandomNodesVis();
00387       broadcastFootstepPathVis();
00388       broadcastPathVis();
00389 
00390       return true;
00391     }
00392     else
00393     {
00394       ROS_ERROR("extracting path failed\n\n");
00395       return false;
00396     }
00397   }
00398   else if (!path_is_new)
00399   {
00400     ROS_ERROR("Solution found by SBPL is the same as the old solution. "
00401               "Replanning failed.");
00402     return false;
00403   }
00404   else
00405   {
00406     broadcastExpandedNodesVis();
00407     broadcastRandomNodesVis();
00408 
00409     ROS_ERROR("No solution found");
00410     return false;
00411   }
00412 }
00413 
00414 
00415 bool
00416 FootstepPlanner::extractPath(const std::vector<int>& state_ids)
00417 {
00418   ivPath.clear();
00419 
00420   State s;
00421   State start_left;
00422   std::vector<int>::const_iterator state_ids_iter = state_ids.begin();
00423 
00424   // first state is always the robot's left foot
00425   if (!ivPlannerEnvironmentPtr->getState(*state_ids_iter, &start_left))
00426   {
00427     ivPath.clear();
00428     return false;
00429   }
00430   ++state_ids_iter;
00431   if (!ivPlannerEnvironmentPtr->getState(*state_ids_iter, &s))
00432   {
00433     ivPath.clear();
00434     return false;
00435   }
00436   ++state_ids_iter;
00437 
00438   // check if the robot's left foot can be ommited as first state in the path,
00439   // i.e. the robot's right foot is appended first to the path
00440   if (s.getLeg() == LEFT)
00441     ivPath.push_back(ivStartFootRight);
00442   else
00443     ivPath.push_back(start_left);
00444   ivPath.push_back(s);
00445 
00446   for(; state_ids_iter < state_ids.end(); ++state_ids_iter)
00447   {
00448     if (!ivPlannerEnvironmentPtr->getState(*state_ids_iter, &s))
00449     {
00450       ivPath.clear();
00451       return false;
00452     }
00453     ivPath.push_back(s);
00454   }
00455 
00456   // add last neutral step
00457   if (ivPath.back().getLeg() == RIGHT)
00458     ivPath.push_back(ivGoalFootLeft);
00459   else // last_leg == LEFT
00460     ivPath.push_back(ivGoalFootRight);
00461 
00462   return true;
00463 }
00464 
00465 
00466 void
00467 FootstepPlanner::reset()
00468 {
00469   // reset the previously calculated paths
00470   ivPath.clear();
00471   ivPlanningStatesIds.clear();
00472   // reset the planner
00473   // INFO: force_planning_from_scratch was not working properly the last time
00474   // checked; therefore instead of using this function the planner is manually
00475   // reset
00476   //ivPlannerPtr->force_planning_from_scratch();
00477   ivPlannerEnvironmentPtr->reset();
00478   setPlanner();
00479 }
00480 
00481 
00482 void
00483 FootstepPlanner::resetTotally()
00484 {
00485   // reset the previously calculated paths
00486   ivPath.clear();
00487   ivPlanningStatesIds.clear();
00488   // reinitialize the planner environment
00489   ivPlannerEnvironmentPtr.reset(
00490       new FootstepPlannerEnvironment(ivEnvironmentParams));
00491   setPlanner();
00492 }
00493 
00494 
00495 bool
00496 FootstepPlanner::plan()
00497 {
00498   if (!ivMapPtr)
00499   {
00500     ROS_ERROR("FootstepPlanner has no map for planning yet.");
00501     return false;
00502   }
00503   if (!ivGoalPoseSetUp || !ivStartPoseSetUp)
00504   {
00505     ROS_ERROR("FootstepPlanner has not set the start and/or goal pose "
00506               "yet.");
00507     return false;
00508   }
00509 
00510   reset();
00511   // start the planning and return success
00512   return run();
00513 }
00514 
00515 
00516 bool
00517 FootstepPlanner::replan()
00518 {
00519   if (!ivMapPtr)
00520   {
00521     ROS_ERROR("FootstepPlanner has no map for re-planning yet.");
00522     return false;
00523   }
00524   if (!ivGoalPoseSetUp || !ivStartPoseSetUp)
00525   {
00526     ROS_ERROR("FootstepPlanner has not set start and/or goal pose yet.");
00527     return false;
00528   }
00529   // Workaround for R* and ARA: need to reinit. everything
00530   if (ivPlannerType == "RSTARPlanner" || ivPlannerType == "ARAPlanner")
00531   {
00532     ROS_INFO("Reset planning information because planner cannot handle "
00533              "replanning.");
00534     reset();
00535   }
00536 
00537   return run();
00538 }
00539 
00540 
00541 bool
00542 FootstepPlanner::plan(const geometry_msgs::PoseStampedConstPtr start,
00543                       const geometry_msgs::PoseStampedConstPtr goal)
00544 {
00545   return plan(start->pose.position.x, start->pose.position.y,
00546               tf::getYaw(start->pose.orientation),
00547               goal->pose.position.x, goal->pose.position.y,
00548               tf::getYaw(goal->pose.orientation));
00549 }
00550 
00551 
00552 bool
00553 FootstepPlanner::plan(float start_x, float start_y, float start_theta,
00554                       float goal_x, float goal_y, float goal_theta)
00555 {
00556   if (!(setStart(start_x, start_y, start_theta) &&
00557       setGoal(goal_x, goal_y, goal_theta)))
00558   {
00559     return false;
00560   }
00561 
00562   return plan();
00563 }
00564 
00565 
00566 bool
00567 FootstepPlanner::planService(humanoid_nav_msgs::PlanFootsteps::Request &req,
00568                              humanoid_nav_msgs::PlanFootsteps::Response &resp)
00569 {
00570   bool result = plan(req.start.x, req.start.y, req.start.theta,
00571                      req.goal.x, req.goal.y, req.goal.theta);
00572 
00573   resp.costs = getPathCosts();
00574   resp.footsteps.reserve(getPathSize());
00575   resp.final_eps = ivPlannerPtr->get_final_epsilon();
00576   resp.expanded_states = ivPlannerEnvironmentPtr->getNumExpandedStates();
00577 
00578   humanoid_nav_msgs::StepTarget foot;
00579   state_iter_t path_iter;
00580   for (path_iter = getPathBegin(); path_iter != getPathEnd(); ++path_iter)
00581   {
00582     foot.pose.x = path_iter->getX();
00583     foot.pose.y = path_iter->getY();
00584     foot.pose.theta = path_iter->getTheta();
00585     if (path_iter->getLeg() == LEFT)
00586       foot.leg = humanoid_nav_msgs::StepTarget::left;
00587     else if (path_iter->getLeg() == RIGHT)
00588       foot.leg = humanoid_nav_msgs::StepTarget::right;
00589     else
00590     {
00591       ROS_ERROR("Footstep pose at (%f, %f, %f) is set to NOLEG!",
00592                 path_iter->getX(), path_iter->getY(),
00593                 path_iter->getTheta());
00594       continue;
00595     }
00596 
00597     resp.footsteps.push_back(foot);
00598   }
00599   resp.result = result;
00600 
00601   // return true since service call was successful (independent from the
00602   // success of the planning call)
00603   return true;
00604 }
00605 
00606 
00607 void
00608 FootstepPlanner::goalPoseCallback(
00609     const geometry_msgs::PoseStampedConstPtr& goal_pose)
00610 {
00611   // update the goal states in the environment
00612   if (setGoal(goal_pose))
00613   {
00614     if (ivStartPoseSetUp)
00615     {
00616       // this check enforces a planning from scratch if necessary (dependent on
00617       // planning direction)
00618           if (ivEnvironmentParams.forward_search)
00619         replan();
00620           else
00621         plan();
00622     }
00623   }
00624 }
00625 
00626 
00627 void
00628 FootstepPlanner::startPoseCallback(
00629     const geometry_msgs::PoseWithCovarianceStampedConstPtr& start_pose)
00630 {
00631   if (setStart(start_pose->pose.pose.position.x,
00632                start_pose->pose.pose.position.y,
00633                tf::getYaw(start_pose->pose.pose.orientation)))
00634   {
00635     if (ivGoalPoseSetUp)
00636     {
00637       // this check enforces a planning from scratch if necessary (dependent on
00638       // planning direction)
00639       if (ivEnvironmentParams.forward_search)
00640         plan();
00641       else
00642         replan();
00643     }
00644   }
00645 }
00646 
00647 
00648 void
00649 FootstepPlanner::mapCallback(
00650     const nav_msgs::OccupancyGridConstPtr& occupancy_map)
00651 {
00652   GridMap2DPtr map(new GridMap2D(occupancy_map));
00653 
00654   // new map: update the map information
00655   if (updateMap(map))
00656   {
00657     // NOTE: update map currently simply resets the planner, i.e. replanning
00658     // here is in fact a planning from the scratch
00659     replan();
00660   }
00661 }
00662 
00663 
00664 bool
00665 FootstepPlanner::setGoal(const geometry_msgs::PoseStampedConstPtr goal_pose)
00666 {
00667   return setGoal(goal_pose->pose.position.x,
00668                  goal_pose->pose.position.y,
00669                  tf::getYaw(goal_pose->pose.orientation));
00670 }
00671 
00672 
00673 bool
00674 FootstepPlanner::setGoal(float x, float y, float theta)
00675 {
00676   if (!ivMapPtr)
00677   {
00678     ROS_ERROR("Distance map hasn't been initialized yet.");
00679     return false;
00680   }
00681 
00682   State goal(x, y, theta, NOLEG);
00683   State foot_left = getFootPose(goal, LEFT);
00684   State foot_right = getFootPose(goal, RIGHT);
00685 
00686   if (ivPlannerEnvironmentPtr->occupied(foot_left) ||
00687       ivPlannerEnvironmentPtr->occupied(foot_right))
00688   {
00689     ROS_ERROR("Goal pose at (%f %f %f) not accessible.", x, y, theta);
00690     ivGoalPoseSetUp = false;
00691     return false;
00692   }
00693   ivGoalFootLeft = foot_left;
00694   ivGoalFootRight = foot_right;
00695 
00696   ivGoalPoseSetUp = true;
00697   ROS_INFO("Goal pose set to (%f %f %f)", x, y, theta);
00698 
00699   return true;
00700 }
00701 
00702 
00703 bool
00704 FootstepPlanner::setStart(const geometry_msgs::PoseStampedConstPtr start_pose)
00705 {
00706   return setStart(start_pose->pose.position.x,
00707                   start_pose->pose.position.y,
00708                   tf::getYaw(start_pose->pose.orientation));
00709 }
00710 
00711 
00712 bool
00713 FootstepPlanner::setStart(const State& left_foot, const State& right_foot)
00714 {
00715   if (ivPlannerEnvironmentPtr->occupied(left_foot) ||
00716       ivPlannerEnvironmentPtr->occupied(right_foot))
00717   {
00718     ivStartPoseSetUp = false;
00719     return false;
00720   }
00721   ivStartFootLeft = left_foot;
00722   ivStartFootRight = right_foot;
00723 
00724   ivStartPoseSetUp = true;
00725 
00726   return true;
00727 }
00728 
00729 
00730 bool
00731 FootstepPlanner::setStart(float x, float y, float theta)
00732 {
00733   if (!ivMapPtr)
00734   {
00735     ROS_ERROR("Distance map hasn't been initialized yet.");
00736     return false;
00737   }
00738 
00739   State start(x, y, theta, NOLEG);
00740   State foot_left = getFootPose(start, LEFT);
00741   State foot_right = getFootPose(start, RIGHT);
00742 
00743   bool success = setStart(foot_left, foot_right);
00744   if (success)
00745     ROS_INFO("Start pose set to (%f %f %f)", x, y, theta);
00746   else
00747     ROS_ERROR("Start pose (%f %f %f) not accessible.", x, y, theta);
00748 
00749   // publish visualization:
00750   geometry_msgs::PoseStamped start_pose;
00751   start_pose.pose.position.x = x;
00752   start_pose.pose.position.y = y;
00753   start_pose.pose.position.z = 0.025;
00754   start_pose.pose.orientation = tf::createQuaternionMsgFromYaw(theta);
00755   start_pose.header.frame_id = ivMapPtr->getFrameID();
00756   start_pose.header.stamp = ros::Time::now();
00757   ivStartPoseVisPub.publish(start_pose);
00758 
00759   return success;
00760 }
00761 
00762 
00763 bool
00764 FootstepPlanner::updateMap(const GridMap2DPtr map)
00765 {
00766   // store old map pointer locally
00767   GridMap2DPtr old_map = ivMapPtr;
00768   // store new map
00769   ivMapPtr.reset();
00770   ivMapPtr = map;
00771 
00772   // check if a previous map and a path existed
00773   if (old_map && (bool)ivPath.size())
00774   {
00775     updateEnvironment(old_map);
00776     return true;
00777   }
00778 
00779   // ..otherwise the environment's map can simply be updated
00780   ivPlannerEnvironmentPtr->updateMap(map);
00781   return false;
00782 }
00783 
00784 
00785 void
00786 FootstepPlanner::updateEnvironment(const GridMap2DPtr old_map)
00787 {
00788   ROS_INFO("Reseting the planning environment.");
00789   // reset environment
00790   resetTotally();
00791   // set the new map
00792   ivPlannerEnvironmentPtr->updateMap(ivMapPtr);
00793 
00794 
00795   // The following is not used any more
00796 
00797   // Replanning based on old planning info currently disabled
00798   //        // TODO: handle size changes of the map; currently the planning
00799   //        // information is reseted
00800   //
00801   //        if (ivPlannerType == "ADPlanner" &&
00802   //            ivMapPtr->getResolution() == old_map->getResolution() &&
00803   //            ivMapPtr->size().height == old_map->size().height &&
00804   //            ivMapPtr->size().width == old_map->size().width)
00805   //        {
00806   //            ROS_INFO("Received an updated map => change detection");
00807   //
00808   //            std::vector<State2> changed_states;
00809   //            cv::Mat changed_cells;
00810   //
00811   //            // get new occupied cells only (0: occupied in binary map)
00812   //            // changedCells(x,y) = old(x,y) AND NOT(new(x,y))
00815   //
00816   //            // to get all changed cells (new free and occupied) use XOR:
00817   //            cv::bitwise_xor(old_map->binaryMap(), ivMapPtr->binaryMap(),
00818   //                            changed_cells);
00819   //
00820   //            //inflate by outer foot radius:
00821   //            cv::bitwise_not(changed_cells, changed_cells); // invert for distanceTransform
00822   //            cv::Mat changedDistMap = cv::Mat(changed_cells.size(), CV_32FC1);
00823   //            cv::distanceTransform(changed_cells, changedDistMap,
00824   //                                  CV_DIST_L2, CV_DIST_MASK_PRECISE);
00825   //            double max_foot_radius = sqrt(
00826   //                    pow(std::abs(ivOriginFootShiftX) + ivFootsizeX / 2.0, 2.0) +
00827   //                    pow(std::abs(ivOriginFootShiftY) + ivFootsizeY / 2.0, 2.0))
00828   //                    / ivMapPtr->getResolution();
00829   //            changed_cells = (changedDistMap <= max_foot_radius); // threshold, also invert back
00830   //
00831   //            // loop over changed cells (now marked with 255 in the mask):
00832   //            unsigned int num_changed_cells = 0;
00833   //            double wx, wy;
00834   //            State2 s;
00835   //            for (int y = 0; y < changed_cells.rows; ++y)
00836   //            {
00837   //                for (int x = 0; x < changed_cells.cols; ++x)
00838   //                {
00839   //                    if (changed_cells.at<uchar>(x,y) == 255)
00840   //                    {
00841   //                        ++num_changed_cells;
00842   //                        ivMapPtr->mapToWorld(x, y, wx, wy);
00843   //                        s.setX(wx);
00844   //                        s.setY(wy);
00845   //                        // on each grid cell ivNumAngleBins-many planning states
00846   //                        // can be placed (if the resolution of the grid cells is
00847   //                        // the same as of the planning state grid)
00848   //                        for (int theta = 0; theta < ivNumAngleBins; ++theta)
00849   //                        {
00850   //                            s.setTheta(angle_cell_2_state(theta, ivNumAngleBins));
00851   //                            changed_states.push_back(s);
00852   //                        }
00853   //                    }
00854   //                }
00855   //            }
00856   //
00857   //            if (num_changed_cells == 0)
00858   //            {
00859   //                ROS_INFO("old map equals new map; no replanning necessary");
00860   //                return;
00861   //            }
00862   //
00863   //            ROS_INFO("%d changed map cells found", num_changed_cells);
00864   //            if (num_changed_cells <= ivChangedCellsLimit)
00865   //            {
00866   //                // update planer
00867   //                ROS_INFO("Use old information in new planning taks");
00868   //
00869   //                std::vector<int> neighbour_ids;
00870   //                if (ivForwardSearch)
00871   //                    ivPlannerEnvironmentPtr->getSuccsOfGridCells(
00872   //                            changed_states, &neighbour_ids);
00873   //                else
00874   //                    ivPlannerEnvironmentPtr->getPredsOfGridCells(
00875   //                            changed_states, &neighbour_ids);
00876   //
00877   //                boost::shared_ptr<ADPlanner> h =
00878   //                        boost::dynamic_pointer_cast<ADPlanner>(ivPlannerPtr);
00879   //                h->costs_changed(PlanningStateChangeQuery(neighbour_ids));
00880   //            }
00881   //            else
00882   //            {
00883   //                ROS_INFO("Reset old information in new planning task");
00884   //                // reset planner
00885   //                ivPlannerEnvironmentPtr->reset();
00886   //                setPlanner();
00887   //                //ivPlannerPtr->force_planning_from_scratch();
00888   //            }
00889   //        }
00890   //        else
00891   //        {
00892   //            ROS_INFO("Reset old information in new planning task");
00893   //            // reset planner
00894   //            ivPlannerEnvironmentPtr->reset();
00895   //            setPlanner();
00896   //            //ivPlannerPtr->force_planning_from_scratch();
00897   //        }
00898 }
00899 
00900 
00901 State
00902 FootstepPlanner::getFootPose(const State& robot, Leg leg)
00903 {
00904   double shift_x = -sin(robot.getTheta()) * ivFootSeparation / 2.0;
00905   double shift_y =  cos(robot.getTheta()) * ivFootSeparation / 2.0;
00906 
00907   double sign = -1.0;
00908   if (leg == LEFT)
00909     sign = 1.0;
00910 
00911   return State(robot.getX() + sign * shift_x,
00912                robot.getY() + sign * shift_y,
00913                robot.getTheta(),
00914                leg);
00915 }
00916 
00917 
00918 bool
00919 FootstepPlanner::pathIsNew(const std::vector<int>& new_path)
00920 {
00921   if (new_path.size() != ivPlanningStatesIds.size())
00922     return true;
00923 
00924   bool unequal = true;
00925   for (unsigned i = 0; i < new_path.size(); ++i)
00926     unequal = new_path[i] != ivPlanningStatesIds[i] && unequal;
00927 
00928   return unequal;
00929 }
00930 
00931 
00932 void
00933 FootstepPlanner::clearFootstepPathVis(unsigned num_footsteps)
00934 {
00935   visualization_msgs::Marker marker;
00936   visualization_msgs::MarkerArray marker_msg;
00937 
00938   marker.header.stamp = ros::Time::now();
00939   marker.header.frame_id = ivMapPtr->getFrameID();
00940 
00941 
00942   if (num_footsteps < 1)
00943     num_footsteps = ivLastMarkerMsgSize;
00944 
00945   for (unsigned i = 0; i < num_footsteps; ++i)
00946   {
00947     marker.ns = ivMarkerNamespace;
00948     marker.id = i;
00949     marker.action = visualization_msgs::Marker::DELETE;
00950 
00951     marker_msg.markers.push_back(marker);
00952   }
00953 
00954   ivFootstepPathVisPub.publish(marker_msg);
00955 }
00956 
00957 
00958 void
00959 FootstepPlanner::broadcastExpandedNodesVis()
00960 {
00961   if (ivExpandedStatesVisPub.getNumSubscribers() > 0)
00962   {
00963     sensor_msgs::PointCloud cloud_msg;
00964     geometry_msgs::Point32 point;
00965     std::vector<geometry_msgs::Point32> points;
00966 
00967     State s;
00968     FootstepPlannerEnvironment::exp_states_2d_iter_t state_id_it;
00969     for(state_id_it = ivPlannerEnvironmentPtr->getExpandedStatesStart();
00970         state_id_it != ivPlannerEnvironmentPtr->getExpandedStatesEnd();
00971         ++state_id_it)
00972     {
00973       point.x = cell_2_state(state_id_it->first,
00974                              ivEnvironmentParams.cell_size);
00975       point.y = cell_2_state(state_id_it->second,
00976                              ivEnvironmentParams.cell_size);
00977       point.z = 0.01;
00978       points.push_back(point);
00979     }
00980     cloud_msg.header.stamp = ros::Time::now();
00981     cloud_msg.header.frame_id = ivMapPtr->getFrameID();
00982 
00983     cloud_msg.points = points;
00984 
00985     ivExpandedStatesVisPub.publish(cloud_msg);
00986   }
00987 }
00988 
00989 
00990 void
00991 FootstepPlanner::broadcastFootstepPathVis()
00992 {
00993   if (getPathSize() == 0)
00994   {
00995     ROS_INFO("no path has been extracted yet");
00996     return;
00997   }
00998 
00999   clearFootstepPathVis(0);
01000 
01001   visualization_msgs::Marker marker;
01002   visualization_msgs::MarkerArray broadcast_msg;
01003   std::vector<visualization_msgs::Marker> markers;
01004 
01005   int markers_counter = 0;
01006 
01007   marker.header.stamp = ros::Time::now();
01008   marker.header.frame_id = ivMapPtr->getFrameID();
01009 
01010   // add the missing start foot to the publish vector for visualization:
01011   if (ivPath.front().getLeg() == LEFT)
01012     footPoseToMarker(ivStartFootRight, &marker);
01013   else
01014     footPoseToMarker(ivStartFootLeft, &marker);
01015   marker.id = markers_counter++;
01016   markers.push_back(marker);
01017 
01018   // add the footsteps of the path to the publish vector
01019   for(state_iter_t path_iter = getPathBegin(); path_iter != getPathEnd();
01020       ++path_iter)
01021   {
01022     footPoseToMarker(*path_iter, &marker);
01023     marker.id = markers_counter++;
01024     markers.push_back(marker);
01025   }
01026 
01027   broadcast_msg.markers = markers;
01028   ivLastMarkerMsgSize = markers.size();
01029 
01030   ivFootstepPathVisPub.publish(broadcast_msg);
01031 }
01032 
01033 
01034 void
01035 FootstepPlanner::broadcastRandomNodesVis()
01036 {
01037   if (ivRandomStatesVisPub.getNumSubscribers() > 0){
01038     sensor_msgs::PointCloud cloud_msg;
01039     geometry_msgs::Point32 point;
01040     std::vector<geometry_msgs::Point32> points;
01041     visualization_msgs::Marker marker;
01042     visualization_msgs::MarkerArray broadcast_msg;
01043     std::vector<visualization_msgs::Marker> markers;
01044 
01045     marker.header.stamp = ros::Time::now();
01046     marker.header.frame_id = ivMapPtr->getFrameID();
01047 
01048     State s;
01049     FootstepPlannerEnvironment::exp_states_iter_t state_id_iter;
01050     for(state_id_iter = ivPlannerEnvironmentPtr->getRandomStatesStart();
01051         state_id_iter != ivPlannerEnvironmentPtr->getRandomStatesEnd();
01052         ++state_id_iter)
01053     {
01054       if (!ivPlannerEnvironmentPtr->getState(*state_id_iter, &s))
01055       {
01056         ROS_WARN("Could not get random state %d", *state_id_iter);
01057       }
01058       else
01059       {
01060         point.x = s.getX();
01061         point.y = s.getY();
01062         point.z = 0.01;
01063         points.push_back(point);
01064       }
01065     }
01066     cloud_msg.header.stamp = ros::Time::now();
01067     cloud_msg.header.frame_id = ivMapPtr->getFrameID();
01068 
01069     cloud_msg.points = points;
01070 
01071     ivRandomStatesVisPub.publish(cloud_msg);
01072   }
01073 }
01074 
01075 
01076 void
01077 FootstepPlanner::broadcastPathVis()
01078 {
01079   if (getPathSize() == 0)
01080   {
01081     ROS_INFO("no path has been extracted yet");
01082     return;
01083   }
01084 
01085   nav_msgs::Path path_msg;
01086   geometry_msgs::PoseStamped state;
01087 
01088   state.header.stamp = ros::Time::now();
01089   state.header.frame_id = ivMapPtr->getFrameID();
01090 
01091   state_iter_t path_iter;
01092   for(path_iter = getPathBegin(); path_iter != getPathEnd(); ++path_iter)
01093   {
01094     state.pose.position.x = path_iter->getX();
01095     state.pose.position.y = path_iter->getY();
01096     path_msg.poses.push_back(state);
01097   }
01098 
01099   path_msg.header = state.header;
01100   ivPathVisPub.publish(path_msg);
01101 }
01102 
01103 
01104 void
01105 FootstepPlanner::footPoseToMarker(const State& foot_pose,
01106                                   visualization_msgs::Marker* marker)
01107 {
01108   marker->header.stamp = ros::Time::now();
01109   marker->header.frame_id = ivMapPtr->getFrameID();
01110   marker->ns = ivMarkerNamespace;
01111   marker->type = visualization_msgs::Marker::CUBE;
01112   marker->action = visualization_msgs::Marker::ADD;
01113 
01114   float cos_theta = cos(foot_pose.getTheta());
01115   float sin_theta = sin(foot_pose.getTheta());
01116   float x_shift = cos_theta * ivEnvironmentParams.foot_origin_shift_x -
01117                   sin_theta * ivEnvironmentParams.foot_origin_shift_y;
01118   float y_shift;
01119   if (foot_pose.getLeg() == LEFT)
01120     y_shift = sin_theta * ivEnvironmentParams.foot_origin_shift_x +
01121               cos_theta * ivEnvironmentParams.foot_origin_shift_y;
01122   else // leg == RLEG
01123     y_shift = sin_theta * ivEnvironmentParams.foot_origin_shift_x -
01124               cos_theta * ivEnvironmentParams.foot_origin_shift_y;
01125   marker->pose.position.x = foot_pose.getX() + x_shift;
01126   marker->pose.position.y = foot_pose.getY() + y_shift;
01127   marker->pose.position.z = ivEnvironmentParams.footsize_z / 2.0;
01128   tf::quaternionTFToMsg(tf::createQuaternionFromYaw(foot_pose.getTheta()),
01129                         marker->pose.orientation);
01130 
01131   marker->scale.x = ivEnvironmentParams.footsize_x; // - 0.01;
01132   marker->scale.y = ivEnvironmentParams.footsize_y; // - 0.01;
01133   marker->scale.z = ivEnvironmentParams.footsize_z;
01134 
01135   // TODO: make color configurable?
01136   if (foot_pose.getLeg() == RIGHT)
01137   {
01138     marker->color.r = 0.0f;
01139     marker->color.g = 1.0f;
01140   }
01141   else // leg == LEFT
01142       {
01143     marker->color.r = 1.0f;
01144     marker->color.g = 0.0f;
01145       }
01146   marker->color.b = 0.0;
01147   marker->color.a = 0.6;
01148 
01149   marker->lifetime = ros::Duration();
01150 }
01151 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


footstep_planner
Author(s): Johannes Garimort, Armin Hornung
autogenerated on Tue Oct 15 2013 10:06:51