footstep_planner.cpp
Go to the documentation of this file.
00001 #include <vigir_footstep_planner/footstep_planner.h>
00002 
00003 namespace vigir_footstep_planning
00004 {
00005 FootstepPlanner::FootstepPlanner(ros::NodeHandle &nh)
00006   : foot_pose_transformer(FootPoseTransformer(nh))
00007   , start_foot_selection(msgs::StepPlanRequest::AUTO)
00008   , start_pose_set_up(false)
00009   , goal_pose_set_up(false)
00010   , max_number_steps(0.0)
00011   , max_path_length_ratio(0.0)
00012   , ivPathCost(0)
00013   , ivCheckedFootContactSupport(new pcl::PointCloud<pcl::PointXYZI>())
00014   , step_plan_uid(0)
00015 {
00016   nh.getParam("world_frame_id", frame_id);
00017 
00018   // publish topics
00019   ivCheckedFootContactSupportPub = nh.advertise<sensor_msgs::PointCloud2>("foot_contact_support", 1);
00020 
00021   // initialize the planner environment
00022   if (!ParameterManager::empty())
00023     setParams(ParameterManager::getActive());
00024   else
00025     ROS_ERROR("[FootstepPlanner] Can't initialize environment due to missing parameters!");
00026 }
00027 
00028 FootstepPlanner::~FootstepPlanner()
00029 {
00030   boost::recursive_mutex::scoped_lock lock(planner_mutex);
00031 
00032   planning_thread.interrupt();
00033   planning_thread.join();
00034 }
00035 
00036 void FootstepPlanner::setPlanner()
00037 {
00038   if (env_params->ivPlannerType == "ARAPlanner" ||
00039       env_params->ivPlannerType == "ADPlanner"  ||
00040       env_params->ivPlannerType == "RSTARPlanner" )
00041   {
00042     ROS_INFO_STREAM("Planning with " << env_params->ivPlannerType);
00043   }
00044   else
00045   {
00046     ROS_ERROR_STREAM("Planner " << env_params->ivPlannerType << " not available / untested.");
00047     exit(1);
00048   }
00049   if (env_params->forward_search)
00050   {
00051     ROS_INFO_STREAM("Search direction: forward planning");
00052   }
00053   else
00054   {
00055     ROS_INFO_STREAM("Search direction: backward planning");
00056   }
00057 
00058   if (env_params->ivPlannerType == "ARAPlanner")
00059   {
00060     ivPlannerPtr.reset(
00061           new ARAPlanner(ivPlannerEnvironmentPtr.get(),
00062                          env_params->forward_search));
00063   }
00064   else if (env_params->ivPlannerType == "ADPlanner")
00065   {
00066     ivPlannerPtr.reset(
00067           new ADPlanner(ivPlannerEnvironmentPtr.get(),
00068                         env_params->forward_search));
00069   }
00070   else if (env_params->ivPlannerType == "RSTARPlanner")
00071   {
00072     RSTARPlanner* p =
00073         new RSTARPlanner(ivPlannerEnvironmentPtr.get(),
00074                          env_params->forward_search);
00075     // new options, require patched SBPL
00076     //          p->set_local_expand_thres(500);
00077     //          p->set_eps_step(1.0);
00078     ivPlannerPtr.reset(p);
00079   }
00080   //        else if (env_params->ivPlannerType == "ANAPlanner")
00081   //            ivPlannerPtr.reset(new anaPlanner(ivPlannerEnvironmentPtr.get(),
00082   //                                              ivForwardSearch));
00083 }
00084 
00085 bool FootstepPlanner::isPlanning() const
00086 {
00087   return planning_thread.joinable();
00088 }
00089 
00090 bool FootstepPlanner::plan(ReplanParams& params)
00091 {
00092   bool path_existed = (bool)ivPath.size();
00093   int ret = 0;
00094   MDPConfig mdp_config;
00095   std::vector<int> solution_state_ids;
00096 
00097   // commit start/goal poses to the environment
00099   ivPlannerEnvironmentPtr->getStateSpace()->updateStart(ivStartFootLeft, ivStartFootRight);
00100   ivPlannerEnvironmentPtr->getStateSpace()->updateGoal(ivGoalFootLeft, ivGoalFootRight);
00101   ivPlannerEnvironmentPtr->getStateSpace()->setPlannerStartAndGoal(start_foot_selection);
00102   ivPlannerEnvironmentPtr->updateHeuristicValues();
00103   ivPlannerEnvironmentPtr->InitializeEnv(NULL);
00104   ivPlannerEnvironmentPtr->InitializeMDPCfg(&mdp_config);
00105 
00106   // inform AD planner about changed (start) states for replanning
00107   if (path_existed &&
00108       !env_params->forward_search &&
00109       env_params->ivPlannerType == "ADPlanner")
00110   {
00111     std::vector<int> changed_edges;
00112     changed_edges.push_back(mdp_config.startstateid);
00113     // update the AD planner
00114     boost::shared_ptr<ADPlanner> ad_planner =
00115         boost::dynamic_pointer_cast<ADPlanner>(ivPlannerPtr);
00116     ad_planner->update_preds_of_changededges(&changed_edges);
00117   }
00118 
00119   // set up SBPL
00120   if (ivPlannerPtr->set_start(mdp_config.startstateid) == 0)
00121   {
00122     ROS_ERROR("Failed to set start state.");
00123     return false;
00124   }
00125   if (ivPlannerPtr->set_goal(mdp_config.goalstateid) == 0)
00126   {
00127     ROS_ERROR("Failed to set goal state");
00128     return false;
00129   }
00130 
00131   int path_cost;
00132   ros::WallTime startTime = ros::WallTime::now();
00133   try
00134   {
00135     ROS_INFO("Start planning (max time: %f, eps_0: %.2f, d_eps: %.2f, h(start, goal): %.3f (l) - %.3f (r))",
00136              params.max_time, params.initial_eps, params.dec_eps,
00137              (double)ivPlannerEnvironmentPtr->GetGoalHeuristic(ivPlannerEnvironmentPtr->getStateSpace()->ivIdStartFootLeft)/(double)cvMmScale,
00138              (double)ivPlannerEnvironmentPtr->GetGoalHeuristic(ivPlannerEnvironmentPtr->getStateSpace()->ivIdStartFootRight)/(double)cvMmScale);
00139     ret = ivPlannerPtr->replan(&solution_state_ids, params, &path_cost);
00140   }
00141   catch (const SBPL_Exception* e)
00142   {
00143     ROS_ERROR("SBPL planning failed (%s)", e->what());
00144     return false;
00145   }
00146   ivPathCost = double(path_cost) / cvMmScale;
00147 
00148   bool path_is_new = pathIsNew(solution_state_ids);
00149   if (ret && solution_state_ids.size() > 0 && path_is_new)
00150   {
00151     ROS_INFO("Solution of size %zu found after %f s",
00152              solution_state_ids.size(),
00153              (ros::WallTime::now()-startTime).toSec());
00154 
00155     if (extractPath(solution_state_ids))
00156     {
00157       ROS_INFO("Expanded states: %i total / %i new",
00158                ivPlannerEnvironmentPtr->getNumExpandedStates(),
00159                ivPlannerPtr->get_n_expands());
00160       ROS_INFO("Final eps: %f", ivPlannerPtr->get_final_epsilon());
00161       ROS_INFO("Path cost: %f (%i)\n", ivPathCost, path_cost);
00162 
00163       ivPlanningStatesIds = solution_state_ids;
00164       return true;
00165     }
00166     else
00167     {
00168       ROS_ERROR("extracting path failed\n\n");
00169       return false;
00170     }
00171   }
00172   else if (!path_is_new)
00173   {
00174     ROS_ERROR("Solution found by SBPL is the same as the old solution. Replanning failed.");
00175     return false;
00176   }
00177   else
00178   {
00179     ROS_ERROR("No solution found");
00180     return false;
00181   }
00182 }
00183 
00184 bool FootstepPlanner::extractPath(const std::vector<int>& state_ids)
00185 {
00186   ivPath.clear();
00187 
00188   for(std::vector<int>::const_iterator state_ids_iter = state_ids.begin(); state_ids_iter != state_ids.end(); ++state_ids_iter)
00189   {
00190     State s;
00191     if (!ivPlannerEnvironmentPtr->getStateSpace()->getState(*state_ids_iter, s))
00192     {
00193       ivPath.clear();
00194       return false;
00195     }
00196     ivPath.push_back(s);
00197   }
00198 
00199   // add last neutral step
00200   if (ivPath.back().getLeg() == RIGHT)
00201     ivPath.push_back(ivGoalFootLeft);
00202   else // last_leg == LEFT
00203     ivPath.push_back(ivGoalFootRight);
00204 
00205   return true;
00206 }
00207 
00208 bool FootstepPlanner::setParams(const vigir_generic_params::ParameterSet& params)
00209 {
00210   boost::recursive_mutex::scoped_lock lock(planner_mutex);
00211 
00212   // reinitialize the planner environment parameters
00213   env_params.reset(new EnvironmentParameters(params));
00214 
00215   std::string plugin_set;
00216   if (params.getParam("plugin_set", plugin_set))
00217     vigir_pluginlib::PluginManager::loadPluginSet(plugin_set);
00218   else
00219     ROS_WARN("[FootstepPlanner] setParams: No plugin set was given by parameter set '%s'", params.getName().c_str());
00220 
00221   // reinitialize step plan msg plugin
00222   StepPlanMsgPlugin::Ptr plugin;
00223   if (vigir_pluginlib::PluginManager::getPlugin(plugin))
00224     plugin->loadParams(params);
00225 
00226   // reinitialize state generator
00227   StateGenerator::mutableInstance().loadPlugins();
00228   StateGenerator::mutableInstance().loadParams(params);
00229 
00230   // reinitialize robot model
00231   RobotModel::mutableInstance().loadPlugins();
00232   RobotModel::mutableInstance().loadParams(params);
00233 
00234   // reinitialize post processor
00235   PostProcessor::mutableInstance().loadPlugins();
00236   PostProcessor::mutableInstance().loadParams(params);
00237 
00238   // reinitialize world model
00239   WorldModel::mutableInstance().loadPlugins();
00240   WorldModel::mutableInstance().loadParams(params);
00241 
00242   // reinitialize step cost estimators
00243   StepCostEstimator::mutableInstance().loadPlugins();
00244   StepCostEstimator::mutableInstance().loadParams(params);
00245 
00246   // reinitialize heuristics
00247   Heuristic::mutableInstance().loadPlugins();
00248   Heuristic::mutableInstance().loadParams(params);
00249 
00250   resetTotally();
00251 
00252   return true;
00253 }
00254 
00255 msgs::ErrorStatus FootstepPlanner::updateFoot(msgs::Foot& foot, uint8_t mode, bool transform) const
00256 {
00257   msgs::ErrorStatus status;
00258 
00259   // transform to sole frame
00260   if (transform)
00261     foot_pose_transformer.transformToPlannerFrame(foot);
00262 
00263   if (mode & msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID)
00264   {
00265     State s(foot);
00266     if (findNearestValidState(s))
00267       s.getFoot(foot);
00268     else
00269       status += ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't determine valid position!");
00270   }
00271   else if (mode & msgs::UpdateMode::UPDATE_MODE_3D)
00272   {
00273     if (!WorldModel::instance().isTerrainModelAvailable() || !WorldModel::instance().getTerrainModel()->update3DData(foot.pose))
00274       status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't update 3D data.", false);
00275   }
00276   else if (mode & msgs::UpdateMode::UPDATE_MODE_Z)
00277   {
00278     if (!WorldModel::instance().isTerrainModelAvailable() || !WorldModel::instance().getTerrainModel()->getHeight(foot.pose.position.x, foot.pose.position.y, foot.pose.position.z))
00279       status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't update z.", false);
00280   }
00281 
00282   // transform back to robot frame
00283   if (transform)
00284     foot_pose_transformer.transformToRobotFrame(foot);
00285 
00286   foot.header.stamp = ros::Time::now();
00287 
00288   return status;
00289 }
00290 
00291 msgs::ErrorStatus FootstepPlanner::updateFeet(msgs::Feet& feet, uint8_t mode, bool transform) const
00292 {
00293   msgs::ErrorStatus status;
00294 
00295   if (mode & msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID)
00296   {
00297     State left(feet.left);
00298     State right(feet.right);
00299     if (findNearestValidState(left) && findNearestValidState(right) && RobotModel::instance().isReachable(left, right))
00300     {
00301       left.getFoot(feet.left);
00302       right.getFoot(feet.right);
00303     }
00304     else
00305       status += ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "updateFeet: Couldn't determine valid position!");
00306 
00307     mode -= msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID;
00308   }
00309 
00310   status += updateFoot(feet.left, mode, transform);
00311   status += updateFoot(feet.right, mode, transform);
00312 
00313   return status;
00314 }
00315 
00316 msgs::ErrorStatus FootstepPlanner::updateStepPlan(msgs::StepPlan& step_plan, uint8_t mode, const std::string& /*param_set_name*/, bool transform) const
00317 {
00318   if (step_plan.steps.empty())
00319     return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "[FootstepPlanner]", "updateStepPlan: Can't process empty step plan!");
00320   if (step_plan.start.header.frame_id.empty())
00321     return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "[FootstepPlanner]", "updateStepPlan: Can't process step plan due to missing start feet poses!");
00322 
00323   // lock entire planning system
00324   boost::recursive_mutex::scoped_lock lock(planner_mutex);
00325 
00326   // transform to sole frame
00327   if (transform)
00328     foot_pose_transformer.transformToPlannerFrame(step_plan);
00329 
00330   msgs::ErrorStatus status;
00331 
00332   if (mode & msgs::UpdateMode::UPDATE_MODE_REPLAN)
00333   {
00334     ROS_WARN("UPDATE_MODE_REPLAN isn't implemented yet!");
00335   }
00336   else
00337   {
00338     std::vector<msgs::Step>::iterator itr = step_plan.steps.begin();
00339 
00340     State left_state(step_plan.start.left);
00341     State right_state(step_plan.start.right);
00342     State prev_state(*itr);
00343 
00344     itr++;
00345     for (; itr != step_plan.steps.end(); itr++)
00346     {
00347       msgs::Step& cur_step = *itr;
00348       State cur_state = State(cur_step);
00349 
00350       // update feet
00351       status += updateFoot(cur_step.foot, mode, false);
00352 
00353       // check reachability
00354       if (mode & msgs::UpdateMode::UPDATE_MODE_CHECK_VALIDITY)
00355       {
00356         cur_step.valid = RobotModel::instance().isReachable(left_state, right_state, cur_state);
00357       }
00358 
00359       // check collision
00360       if (mode & msgs::UpdateMode::UPDATE_MODE_CHECK_COLLISION)
00361       {
00362         cur_step.colliding = !WorldModel::instance().isAccessible(cur_state, prev_state);
00363       }
00364 
00365       // recompute cost
00366       if (mode & msgs::UpdateMode::UPDATE_MODE_COST)
00367       {
00368         double c, r;
00369         if (StepCostEstimator::instance().getCost(left_state, right_state, cur_state, c, r))
00370         {
00371           cur_step.cost = c;
00372           cur_step.risk = r;
00373         }
00374         else
00375           status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateStepPlan: Couldn't determine cost for step " + boost::lexical_cast<std::string>(cur_step.step_index) + "!");
00376       }
00377 
00378       // prepare next iteration
00379       if (cur_state.getLeg() == LEFT)
00380         left_state = cur_state;
00381       else
00382         right_state = cur_state;
00383 
00384       prev_state = cur_state;
00385     }
00386   }
00387 
00388   // transform back to robot frame
00389   if (transform)
00390     foot_pose_transformer.transformToRobotFrame(step_plan);
00391 
00392   return msgs::ErrorStatus();
00393 }
00394 
00395 void FootstepPlanner::reset()
00396 {
00397   boost::recursive_mutex::scoped_lock lock(planner_mutex);
00398 
00399   Heuristic::mutableInstance().resetPlugins();
00400 
00401   // reset the previously calculated paths
00402   ivPath.clear();
00403   ivPlanningStatesIds.clear();
00404   ivCheckedFootContactSupport->clear();
00405   // reset the planner
00406   // INFO: force_planning_from_scratch was not working properly the last time
00407   // checked; therefore instead of using this function the planner is manually
00408   // reset
00409   //ivPlannerPtr->force_planning_from_scratch();
00410   ivPlannerEnvironmentPtr->reset();
00411   setPlanner();
00412 }
00413 
00414 
00415 void FootstepPlanner::resetTotally()
00416 {
00417   boost::recursive_mutex::scoped_lock lock(planner_mutex);
00418 
00419   // reset plugins
00420   StepPlanMsgPlugin::Ptr plugin;
00421   if (vigir_pluginlib::PluginManager::getPlugin(plugin))
00422     plugin->reset();
00423 
00424   StateGenerator::mutableInstance().resetPlugins();
00425   RobotModel::mutableInstance().resetPlugins();
00426   PostProcessor::mutableInstance().resetPlugins();
00427   StepCostEstimator::mutableInstance().resetPlugins();
00428   Heuristic::mutableInstance().resetPlugins();
00429 
00430   // reset the previously calculated paths
00431   ivPath.clear();
00432   ivPlanningStatesIds.clear();
00433   ivCheckedFootContactSupport->clear();
00434   // reinitialize the planner environment
00435   ivPlannerEnvironmentPtr.reset(new FootstepPlannerEnvironment(*env_params, foot_pose_transformer, feedback_cb));
00436   setPlanner();
00437 }
00438 
00439 msgs::ErrorStatus FootstepPlanner::planSteps(msgs::StepPlanRequestService::Request& req)
00440 {
00441   // set start foot poses
00442   if (!setStart(req.plan_request, true)) 
00443     return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_START, "FootstepPlanner", "planSteps: Couldn't set start pose! Please check if poses are set!");
00444 
00445   // set goal foot poses
00446   if (!setGoal(req.plan_request))
00447     return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_GOAL, "FootstepPlanner", "planSteps: Couldn't set goal pose! Please check if poses are set!");
00448 
00449   reset();
00450 
00451   ReplanParams params(req.plan_request.max_planning_time > 0 ? req.plan_request.max_planning_time : env_params->max_planning_time);
00452   params.initial_eps = env_params->initial_eps;
00453   params.final_eps = 1.0;
00454   params.dec_eps = env_params->decrease_eps;
00455   params.return_first_solution = env_params->ivSearchUntilFirstSolution;
00456   params.repair_time = -1;
00457 
00458   // start the planning and return success
00459   if (!plan(params))
00460     return ErrorStatusError(msgs::ErrorStatus::ERR_NO_SOLUTION, "FootstepPlanner", "planSteps: No solution found!");
00461 
00462   return msgs::ErrorStatus();
00463 }
00464 
00465 msgs::ErrorStatus FootstepPlanner::planPattern(msgs::StepPlanRequestService::Request& req)
00466 {
00467   double cell_size = 0.0001;
00468   int num_angle_bins = 2048;
00469   double angle_bin_size = (2.0*M_PI / num_angle_bins);
00470 
00471   // set start foot poses
00472   if (!setStart(req.plan_request, true))
00473     return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_START, "FootstepPlanner", "planPattern: Couldn't set start pose! Please check if poses are set!");
00474 
00475   boost::shared_ptr<Footstep> footstep;
00476   boost::shared_ptr<Footstep> footstep_left;
00477   boost::shared_ptr<Footstep> footstep_right;
00478 
00479   unsigned int num_steps = req.plan_request.pattern_parameters.steps;
00480   bool close_step = req.plan_request.pattern_parameters.close_step && num_steps > 0;
00481   bool single_step_mode = false;
00482 
00483   bool change_z = true;
00484   double step_up_height = std::abs(req.plan_request.pattern_parameters.dz);
00485   double extra_seperation_factor = req.plan_request.pattern_parameters.extra_seperation ? 1.25 : 1.0;
00486 
00487   ROS_INFO("Start planning stepping (mode: %u, steps: %u)\n", req.plan_request.pattern_parameters.mode, num_steps);
00488 
00489   State previous_state;
00490   State current_state;
00491 
00492   msgs::ErrorStatus status;
00493 
00494   switch (req.plan_request.pattern_parameters.mode)
00495   {
00496     case msgs::PatternParameters::STEP_UP:
00497     case msgs::PatternParameters::STEP_DOWN:
00498     case msgs::PatternParameters::STEP_OVER:
00499       change_z = false; // as dz is used for step up/down motion
00500     case msgs::PatternParameters::FORWARD:
00501     {
00502       footstep = boost::shared_ptr<Footstep>(
00503                    new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
00504                                 0.0,
00505                                 cell_size,
00506                                 num_angle_bins,
00507                                 env_params->hash_table_size));
00508       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00509       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00510       break;
00511     }
00512     case msgs::PatternParameters::BACKWARD:
00513     {
00514       footstep = boost::shared_ptr<Footstep>(
00515                    new Footstep(-req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
00516                                 0.0,
00517                                 cell_size,
00518                                 num_angle_bins,
00519                                 env_params->hash_table_size));
00520       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00521       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00522       break;
00523     }
00524     case msgs::PatternParameters::STRAFE_LEFT:
00525     {
00526       footstep = boost::shared_ptr<Footstep>(
00527                    new Footstep(0.0, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, 0.0,
00528                                 0.0,
00529                                 cell_size,
00530                                 num_angle_bins,
00531                                 env_params->hash_table_size));
00532       previous_state = ivStartFootLeft;
00533       current_state = ivStartFootRight;
00534       single_step_mode = true;
00535       break;
00536     }
00537     case msgs::PatternParameters::STRAFE_RIGHT:
00538     {
00539       footstep = boost::shared_ptr<Footstep>(
00540                    new Footstep(0.0, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, 0.0,
00541                                 0.0,
00542                                 cell_size,
00543                                 num_angle_bins,
00544                                 env_params->hash_table_size));
00545       previous_state = ivStartFootRight;
00546       current_state = ivStartFootLeft;
00547       single_step_mode = true;
00548       break;
00549     }
00550     case msgs::PatternParameters::ROTATE_LEFT:
00551     {
00552       footstep = boost::shared_ptr<Footstep>(
00553                    new Footstep(-sin(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2,
00554                                 cos(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2+(env_params->foot_seperation*extra_seperation_factor)/2,
00555                                 req.plan_request.pattern_parameters.turn_angle,
00556                                 0.0,
00557                                 cell_size,
00558                                 num_angle_bins,
00559                                 env_params->hash_table_size));
00560       previous_state = ivStartFootLeft;
00561       current_state = ivStartFootRight;
00562       single_step_mode = true;
00563       break;
00564     }
00565     case msgs::PatternParameters::ROTATE_RIGHT:
00566     {
00567       footstep = boost::shared_ptr<Footstep>(
00568                    new Footstep(-sin(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2,
00569                                 cos(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2+(env_params->foot_seperation*extra_seperation_factor)/2,
00570                                 req.plan_request.pattern_parameters.turn_angle,
00571                                 0.0,
00572                                 cell_size,
00573                                 num_angle_bins,
00574                                 env_params->hash_table_size));
00575       previous_state = ivStartFootRight;
00576       current_state = ivStartFootLeft;
00577       single_step_mode = true;
00578       break;
00579     }
00580     case msgs::PatternParameters::SAMPLING:
00581     {
00582       // determine start foot
00583       unsigned int start_foot;
00584 
00585       if (req.plan_request.start_foot_selection != msgs::StepPlanRequest::AUTO)
00586         start_foot = req.plan_request.start_foot_selection;
00587       else
00588       {
00589         if (req.plan_request.pattern_parameters.step_distance_sideward < 0.0 || (req.plan_request.pattern_parameters.step_distance_sideward == 0.0 && req.plan_request.pattern_parameters.turn_angle < 0.0))
00590           start_foot = msgs::StepPlanRequest::RIGHT;
00591         else
00592           start_foot = msgs::StepPlanRequest::LEFT;
00593       }
00594 
00595       // generate footstep
00596       if (req.plan_request.pattern_parameters.step_distance_sideward == 0.0 && req.plan_request.pattern_parameters.turn_angle == 0.0)
00597       {
00598         footstep_left = boost::shared_ptr<Footstep>(
00599                           new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle,
00600                                        0.0,
00601                                        cell_size,
00602                                        num_angle_bins,
00603                                        env_params->hash_table_size));
00604         footstep_right = boost::shared_ptr<Footstep>(
00605                            new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation-req.plan_request.pattern_parameters.step_distance_sideward, -req.plan_request.pattern_parameters.turn_angle,
00606                                         0.0,
00607                                         cell_size,
00608                                         num_angle_bins,
00609                                         env_params->hash_table_size));
00610       }
00611       else if (start_foot == msgs::StepPlanRequest::LEFT)
00612       {
00613         footstep_left = boost::shared_ptr<Footstep>(
00614                           new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle,
00615                                        0.0,
00616                                        cell_size,
00617                                        num_angle_bins,
00618                                        env_params->hash_table_size));
00619         footstep_right = boost::shared_ptr<Footstep>(
00620                            new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
00621                                         0.0,
00622                                         cell_size,
00623                                         num_angle_bins,
00624                                         env_params->hash_table_size));
00625       }
00626       else
00627       {
00628         footstep_left = boost::shared_ptr<Footstep>(
00629                           new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
00630                                        0.0,
00631                                        cell_size,
00632                                        num_angle_bins,
00633                                        env_params->hash_table_size));
00634         footstep_right = boost::shared_ptr<Footstep>(
00635                            new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation-req.plan_request.pattern_parameters.step_distance_sideward, -req.plan_request.pattern_parameters.turn_angle,
00636                                         0.0,
00637                                         cell_size,
00638                                         num_angle_bins,
00639                                         env_params->hash_table_size));
00640       }
00641 
00642       // setup pattern generation
00643       previous_state = start_foot == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00644       current_state = start_foot == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00645       break;
00646     }
00647     case msgs::PatternParameters::FEET_REALIGN_ON_CENTER:
00648     {
00649       State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
00650                         0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
00651                         0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
00652                         0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
00653                         0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
00654                         0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
00655                         NOLEG);
00656 
00657       // first add start foot
00658       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00659       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00660       status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
00661       if (hasError(status))
00662         return status;
00663 
00664       // add pattern directly
00665       if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
00666       {
00667         State temp = getFootPose(feet_center, RIGHT);
00668         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00669 
00670         temp = getFootPose(feet_center, LEFT);
00671         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00672       }
00673       else
00674       {
00675         State temp = getFootPose(feet_center, LEFT);
00676         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00677 
00678         temp = getFootPose(feet_center, RIGHT);
00679         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00680       }
00681 
00682       return status;
00683     }
00684     case msgs::PatternParameters::FEET_REALIGN_ON_LEFT:
00685     {
00686       previous_state = ivStartFootRight;
00687       current_state = ivStartFootLeft;
00688       num_steps = 0;
00689       close_step = true;
00690       break;
00691     }
00692     case msgs::PatternParameters::FEET_REALIGN_ON_RIGHT:
00693     {
00694       previous_state = ivStartFootLeft;
00695       current_state = ivStartFootRight;
00696       num_steps = 0;
00697       close_step = true;
00698       break;
00699     }
00700     case msgs::PatternParameters::WIDE_STANCE:
00701     {
00702       State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
00703                         0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
00704                         0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
00705                         0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
00706                         0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
00707                         0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
00708                         NOLEG);
00709 
00710       // first add start foot
00711       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00712       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00713       status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
00714       if (hasError(status))
00715         return status;
00716 
00717       // add pattern directly
00718       if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
00719       {
00720         State temp = getFootPose(feet_center, RIGHT, req.plan_request.pattern_parameters.step_distance_forward, req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle);
00721         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00722 
00723         temp = getFootPose(feet_center, LEFT, req.plan_request.pattern_parameters.step_distance_forward, req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle);
00724         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00725       }
00726       else
00727       {
00728         State temp = getFootPose(feet_center, LEFT, req.plan_request.pattern_parameters.step_distance_forward, req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle);
00729         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00730 
00731         temp = getFootPose(feet_center, RIGHT, req.plan_request.pattern_parameters.step_distance_forward, req.plan_request.pattern_parameters.step_distance_sideward, req.plan_request.pattern_parameters.turn_angle);
00732         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00733       }
00734 
00735       return status;
00736     }
00737     default:
00738       return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "planPattern: Unknown walk mode (" + boost::lexical_cast<std::string>(req.plan_request.pattern_parameters.mode) + ") set!");
00739   }
00740 
00741   // generate common used step placements
00742   Footstep parallel_step(0.0, env_params->foot_seperation, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
00743   Footstep parallel_step_extra(0.0, env_params->foot_seperation*extra_seperation_factor, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
00744   Footstep step_up(1.4*env_params->foot_size.x, env_params->foot_seperation, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
00745   Footstep step_down(1.1*env_params->foot_size.x, env_params->foot_seperation, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
00746 
00747   // generate simple path via pattern generator
00748   PlanningState previous_pstate(previous_state, cell_size, angle_bin_size, env_params->hash_table_size);
00749   PlanningState current_pstate(current_state, cell_size, angle_bin_size, env_params->hash_table_size, &previous_pstate);
00750 
00751   // add start state
00752   status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00753   if (hasError(status))
00754     return status;
00755 
00756   // add step up motion
00757   if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_UP || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
00758   {
00759     // generate next step (temp needed due to current has pointer to previous!)
00760     PlanningState temp = step_up.performMeOnThisState(current_pstate);
00761     previous_pstate = current_pstate;
00762     current_pstate = temp;
00763 
00764     current_pstate.getState().setZ(current_pstate.getState().getZ() + step_up_height);
00765 
00766     // add next step to plan
00767     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00768     if (hasError(status))
00769       return status;
00770   }
00771 
00772   // add pattern
00773   for (unsigned int i = 0; i < num_steps; i++)
00774   {
00775     // sampling uses alternating step sequences
00776     if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::SAMPLING)
00777     {
00778       if (current_pstate.getState().getLeg() == LEFT)
00779         footstep = footstep_right;
00780       else if (current_pstate.getState().getLeg() == RIGHT)
00781         footstep = footstep_left;
00782     }
00783 
00784     // generate next step (temp needed due to current has pointer to previous!)
00785     PlanningState temp = footstep->performMeOnThisState(current_pstate);
00786     previous_pstate = current_pstate;
00787     current_pstate = temp;
00788 
00789     // add next step to plan
00790     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
00791     if (hasError(status))
00792       return status;
00793 
00794     // in single step mode, the second foot should be placed parallel after each step
00795     if (single_step_mode && (!req.plan_request.pattern_parameters.close_step || i < (num_steps-1)))
00796     {
00797       // generate next step (temp needed due to current has pointer to previous!)
00798       PlanningState temp = parallel_step_extra.performMeOnThisState(current_pstate);
00799       previous_pstate = current_pstate;
00800       current_pstate = temp;
00801 
00802       // add next step to plan
00803       status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
00804       if (hasError(status))
00805         return status;
00806       i++;
00807     }
00808   }
00809 
00810   // add step down motion
00811   if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_DOWN || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
00812   {
00813     // generate next step (temp needed due to current has pointer to previous!)
00814     PlanningState temp = step_down.performMeOnThisState(current_pstate);
00815     previous_pstate = current_pstate;
00816     current_pstate = temp;
00817 
00818     current_pstate.getState().setZ(current_pstate.getState().getZ() - step_up_height);
00819 
00820     // add next step to plan
00821     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00822     if (hasError(status))
00823       return status;
00824   }
00825 
00826   // add final step so feet are parallel
00827   if (close_step)
00828   {
00829     // generate next step (temp needed due to current has pointer to previous!)
00830     PlanningState temp = parallel_step.performMeOnThisState(current_pstate);
00831     previous_pstate = current_pstate;
00832     current_pstate = temp;
00833 
00834     // add next step to plan
00835     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00836     if (hasError(status))
00837       return status;
00838   }
00839 
00840   return status;
00841 }
00842 
00843 msgs::ErrorStatus FootstepPlanner::finalizeAndAddStepToPlan(State& s, const msgs::PatternParameters& params, bool change_z)
00844 {
00845   if (change_z)
00846     s.setZ(s.getZ() + params.dz);
00847 
00848   if (params.override)
00849   {
00850     State temp = s;
00851     temp.setRoll(params.roll);
00852     temp.setPitch(params.pitch);
00853     ivPath.push_back(temp);
00854     return msgs::ErrorStatus();
00855   }
00856   else
00857   {
00858     ivPath.push_back(s);
00859     return msgs::ErrorStatus();
00860   }
00861 
00862   return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "addStepping: Something went wrong...");
00863 }
00864 
00865 bool FootstepPlanner::finalizeStepPlan(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp, bool post_process)
00866 {
00867   resp.step_plan.header.frame_id = frame_id;
00868   resp.step_plan.header.stamp = req.plan_request.header.stamp;
00869   resp.step_plan.header.seq = step_plan_uid++;
00870 
00871   // add footstep plan
00872   msgs::Step step;
00873 
00874   // init msg
00875   StepPlanMsgPlugin::Ptr plugin;
00876   if (vigir_pluginlib::PluginManager::getPlugin(plugin))
00877   {
00878     plugin->initMsg(resp.step_plan);
00879     plugin->initMsg(step);
00880   }
00881 
00882   step.header = resp.step_plan.header;
00883   step.foot.header = resp.step_plan.header;
00884   step.valid = true;
00885   step.colliding = false;
00886 
00887   State left_foot = ivStartFootLeft;
00888   State right_foot = ivStartFootRight;
00889 
00890   int step_index = req.plan_request.start_step_index;
00891   resp.step_plan.steps.reserve(getPathSize());
00892   for (state_iter_t path_iter = getPathBegin(); path_iter != getPathEnd(); ++path_iter)
00893   {
00894     State swing_foot = *path_iter;
00895     const State& stand_foot = swing_foot.getLeg() == LEFT ? right_foot : left_foot;
00896 
00897     // post process step (needed for goal states and pattern mode)
00898     if (swing_foot == ivGoalFootLeft || swing_foot == ivGoalFootRight ||
00899         (path_iter != getPathBegin() && req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN))
00900     {
00901       if (env_params->forward_search)
00902         PostProcessor::instance().postProcessForward(left_foot, right_foot, swing_foot);
00903       else
00904         PostProcessor::instance().postProcessBackward(left_foot, right_foot, swing_foot);
00905     }
00906 
00907     // convert footstep
00908     swing_foot.getStep(step);
00909     if (swing_foot.getLeg() == LEFT)
00910       step.foot.foot_index = msgs::Foot::LEFT;
00911     else if (swing_foot.getLeg() == RIGHT)
00912       step.foot.foot_index = msgs::Foot::RIGHT;
00913     else
00914     {
00915       ROS_ERROR("Footstep pose at (%.3f, %.3f, %.3f, %.3f) is set to NOLEG!", swing_foot.getX(), swing_foot.getY(), swing_foot.getZ(), swing_foot.getYaw());
00916       continue;
00917     }
00918     step.step_index = step_index++;
00919 
00920 //    const geometry_msgs::Vector3& v0 = stand_foot.getBodyVelocity();
00921 //    double body_vel0 = sqrt(v0.x*v0.x+v0.y*v0.y+v0.z*v0.z);
00922 //    const geometry_msgs::Vector3& v1 = swing_foot.getBodyVelocity();
00923 //    double body_vel1 = sqrt(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z);
00924 //    ROS_INFO("[%i] Sway dist: %.3f, Swing dist: %.3f", step.step_index, swing_foot.getSwayDistance(), swing_foot.getSwingDistance());
00925 //    ROS_INFO("[%i] Body vel: %.3f %.3f %.3f (%.3f), acc: %.3f", step.step_index, v1.x, v1.y, v1.z, body_vel1, (body_vel1-body_vel0)/step.step_duration);
00926 //    ROS_INFO("-------------------------------------");
00927 
00928     if (std::abs(stand_foot.getZ() - swing_foot.getZ()) > 0.18)
00929       resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "finalizeStepPlan: Plan contains large lift heights");
00930 
00931     // finally add step to plan
00932     resp.step_plan.steps.push_back(step);
00933 
00934     // next step
00935     if (swing_foot.getLeg() == LEFT)
00936       left_foot = swing_foot;
00937     else if (swing_foot.getLeg() == RIGHT)
00938       right_foot = swing_foot;
00939   }
00940 
00941   // perform post processing on entire plan
00942   PostProcessor::instance().postProcess(resp.step_plan);
00943 
00944   // add start and goal configuration
00945   resp.step_plan.start.header = resp.step_plan.header;
00946 
00947   ivStartFootLeft.getFoot(resp.step_plan.start.left);
00948   resp.step_plan.start.left.foot_index = msgs::Foot::LEFT;
00949   resp.step_plan.start.left.header = resp.step_plan.header;
00950 
00951   ivStartFootRight.getFoot(resp.step_plan.start.right);
00952   resp.step_plan.start.right.foot_index = msgs::Foot::RIGHT;
00953   resp.step_plan.start.right.header = resp.step_plan.header;
00954 
00955   resp.step_plan.goal.header = resp.step_plan.header;
00956 
00957   ivGoalFootLeft.getFoot(resp.step_plan.goal.left);
00958   resp.step_plan.goal.left.foot_index = msgs::Foot::LEFT;
00959   resp.step_plan.goal.left.header = resp.step_plan.header;
00960 
00961   ivGoalFootRight.getFoot(resp.step_plan.goal.right);
00962   resp.step_plan.goal.right.foot_index = msgs::Foot::RIGHT;
00963   resp.step_plan.goal.right.header = resp.step_plan.header;
00964 
00965   // plan validation and computation of final cost
00966   if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
00967     updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_CHECK_VALIDITY | msgs::UpdateMode::UPDATE_MODE_CHECK_COLLISION |  msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
00968   else
00969     updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
00970 
00971   resp.final_eps = ivPlannerPtr->get_final_epsilon();
00972   resp.planning_time = ivPlannerPtr->get_final_eps_planning_time();
00973 
00974   if (resp.status.error == msgs::ErrorStatus::NO_ERROR && resp.final_eps > 1.8)
00975     resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "stepPlanRequestService: Suboptimal plan (eps: " + boost::lexical_cast<std::string>(resp.final_eps) + ")!");
00976 
00977   // some debug outputs and visualization stuff
00978   double total_cost = 0.0;
00979   double last_cost = 0.0;
00980   for (std::vector<msgs::Step>::const_iterator itr = resp.step_plan.steps.begin(); itr != resp.step_plan.steps.end(); itr++)
00981   {
00982     step = *itr;
00983 
00984     geometry_msgs::Vector3 n;
00985     quaternionToNormal(step.foot.pose.orientation, n);
00986     ROS_INFO("[%i] x/y/z: %.3f/%.3f/%.3f - %.3f", step.step_index, step.foot.pose.position.x, step.foot.pose.position.y, step.foot.pose.position.z, tf::getYaw(step.foot.pose.orientation));
00987     ROS_INFO("[%i] n: %.3f/%.3f/%.3f", step.step_index, n.x, n.y, n.z);
00988     ROS_INFO("[%i] swing height: %.3f, sway duration: %.3f, step duration: %.3f", step.step_index, step.swing_height, step.sway_duration, step.step_duration);
00989     ROS_INFO("[%i] valid: %s, colliding: %s", step.step_index, step.valid ? "y" : "n", step.colliding ? "y" : "n");
00990     ROS_INFO("[%i] cost: %.3f risk: %.3f", step.step_index, step.cost, step.risk);
00991 
00992     total_cost += step.cost;
00993     last_cost = step.cost;
00994 
00995     if (WorldModel::instance().isTerrainModelAvailable())
00996     {
00997       double support = 0.0;
00998       WorldModel::instance().getTerrainModel()->getFootContactSupport(step.foot.pose, support, ivCheckedFootContactSupport);
00999       ROS_INFO("[%i] Ground contact support: %.3f", step.step_index, support);
01000     }
01001 
01002     ROS_INFO("-------------------------------------");
01003   }
01004   ROS_INFO("Total path cost: %f (%f)", total_cost, total_cost-last_cost);
01005 
01006   if (ivCheckedFootContactSupportPub.getNumSubscribers() > 0)
01007   {
01008     sensor_msgs::PointCloud2 msg;
01009     pcl::toROSMsg(*ivCheckedFootContactSupport, msg);
01010     msg.header.frame_id = frame_id;
01011     msg.header.stamp = ros::Time::now();
01012     ivCheckedFootContactSupportPub.publish(msg);
01013   }
01014 
01015   // transform step plan
01016   foot_pose_transformer.transformToRobotFrame(resp.step_plan);
01017 
01018   return true;
01019 }
01020 
01021 msgs::ErrorStatus FootstepPlanner::stepPlanRequest(msgs::StepPlanRequestService::Request& req, ResultCB result_cb, FeedbackCB feedback_cb, PreemptCB preempt_cb)
01022 {
01023   // preempt any planning
01024   preemptPlanning();
01025 
01026   this->result_cb = result_cb;
01027   this->feedback_cb = feedback_cb;
01028   this->preempt_cb = preempt_cb;
01029 
01030   // check input
01031   // strip '/'
01032   std::string request_frame_id = strip_const(req.plan_request.header.frame_id, '/');
01033   std::string start_frame_id = strip_const(req.plan_request.start.header.frame_id, '/');
01034   std::string goal_frame_id = strip_const(req.plan_request.goal.header.frame_id, '/');
01035 
01036   if (request_frame_id != start_frame_id)
01037     return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "stepPlanRequest: Frame IDs of plan request ('" + request_frame_id + ") and start pose ('" + start_frame_id + "') do not match!");
01038 
01039   if (req.plan_request.planning_mode != msgs::StepPlanRequest::PLANNING_MODE_PATTERN && request_frame_id != goal_frame_id)
01040     return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "stepPlanRequest: Frame IDs of plan request ('" + request_frame_id + "') and goal pose ('" + goal_frame_id + "') do not match!");
01041 
01042   // load parameter set, if given
01043   if (!req.plan_request.parameter_set_name.data.empty())
01044   {
01045     if (!ParameterManager::setActive(req.plan_request.parameter_set_name.data))
01046       return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_PARAMETERS, "FootstepPlanner", "stepPlanRequest: Can't find parameter set named '" + req.plan_request.parameter_set_name.data + "'!");
01047 
01048     setParams(ParameterManager::getActive());
01049   }
01050   else
01051   {
01052     // just reset planner
01053     reset();
01054   }
01055 
01056   // transform feet poses
01057   foot_pose_transformer.transformToPlannerFrame(req.plan_request.start);
01058   foot_pose_transformer.transformToPlannerFrame(req.plan_request.goal);
01059 
01060   // set request specific parameters
01061   start_foot_selection = req.plan_request.start_foot_selection;
01062   max_number_steps = req.plan_request.max_number_steps;
01063   max_path_length_ratio = req.plan_request.max_path_length_ratio;
01064   frame_id = req.plan_request.header.frame_id;
01065   ivPlannerEnvironmentPtr->setFrameId(frame_id);
01066 
01067   // start planning
01068   startPlanning(req);
01069 
01070   return msgs::ErrorStatus();
01071 }
01072 
01073 bool FootstepPlanner::stepPlanRequestService(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp)
01074 {
01075   // generate step plan based on request
01076   resp.status += stepPlanRequest(req);
01077 
01078   if (hasError(resp.status))
01079     return true; // return always true so the message is returned
01080 
01081   // wait for thread to terminate
01082   planning_thread.join();
01083 
01084   // finalize plan and generate response
01085   finalizeStepPlan(req, resp, true);
01086 
01087   return true; // return always true so the message is returned
01088 }
01089 
01090 void FootstepPlanner::startPlanning(msgs::StepPlanRequestService::Request& req)
01091 {
01092   // start planning in seperate thread
01093   planning_thread = boost::thread(&FootstepPlanner::doPlanning, this, req);
01094 }
01095 
01096 void FootstepPlanner::doPlanning(msgs::StepPlanRequestService::Request& req)
01097 {
01098   // lock entire planning system
01099   boost::recursive_mutex::scoped_lock lock(planner_mutex);
01100 
01101   msgs::StepPlanRequestService::Response resp;
01102 
01103   // set world model mode
01104   if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_3D)
01105     WorldModel::mutableInstance().useTerrainModel(true);
01106   else if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
01107     WorldModel::mutableInstance().useTerrainModel(req.plan_request.pattern_parameters.use_terrain_model);
01108   else
01109     WorldModel::mutableInstance().useTerrainModel(false);
01110 
01111   // dispatch planning mode and plan
01112   switch (req.plan_request.planning_mode)
01113   {
01114     case msgs::StepPlanRequest::PLANNING_MODE_2D:
01115     case msgs::StepPlanRequest::PLANNING_MODE_3D:
01116       resp.status = planSteps(req);
01117       break;
01118     case msgs::StepPlanRequest::PLANNING_MODE_PATTERN:
01119       resp.status = planPattern(req);
01120       break;
01121     default:
01122       resp.status = ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "stepPlanRequest: A not supported planning mode '" + boost::lexical_cast<std::string>(req.plan_request.planning_mode) + "' was given!");
01123       break;
01124   }
01125 
01126   // result callbacks
01127   if (!result_cb.empty())
01128   {
01129     // finalize plan and generate response
01130     if (!hasError(resp.status))
01131       finalizeStepPlan(req, resp, true);
01132     result_cb(resp);
01133   }
01134 }
01135 
01136 void FootstepPlanner::preemptPlanning()
01137 {
01138   if (!isPlanning())
01139     return;
01140 
01141   // interrupt main planning thread
01142   planning_thread.interrupt();
01143   planning_thread.join();
01144 
01145   if (!preempt_cb.empty())
01146     preempt_cb();
01147 }
01148 
01149 bool FootstepPlanner::findNearestValidState(State& s) const
01150 {
01151   if (WorldModel::instance().isAccessible(s))
01152     return true;
01153 
01154   State current_state = s;
01155   State best_state = s;
01156 
01157   double pos_diff = FLT_MAX;
01158   double yaw_diff = FLT_MAX;
01159   bool solution_found = false;
01160 
01161   // get transformation foot -> world
01162   tf::Transform t;
01163   t.setOrigin(s.getPose().getOrigin());
01164   t.setBasis(s.getPose().getBasis());
01165 
01166   tf::Vector3 orig_pos;
01167   tf::Vector3 trans_pos;
01168   orig_pos.setZ(0.0);
01169 
01170   for (double yaw = -0.2; yaw <= 0.4; yaw+=env_params->angle_bin_size)
01171   {
01172     current_state.setYaw(s.getYaw() + (s.getLeg() == LEFT ? yaw : -yaw));
01173     for (double y = -0.05; y <= 0.2; y+=env_params->cell_size)
01174     {
01175       orig_pos.setY(s.getLeg() == LEFT ? y : -y);
01176       for (double x = -0.15; x <= 0.15; x+=env_params->cell_size)
01177       {
01178         // determine point in world frame and get height at this point
01179         orig_pos.setX(x);
01180         trans_pos = t * orig_pos;
01181 
01182         current_state.setX(trans_pos.getX());
01183         current_state.setY(trans_pos.getY());
01184 
01185         if (!WorldModel::instance().update3DData(current_state))
01186           continue;
01187 
01188         if (!WorldModel::instance().isAccessible(current_state))
01189           continue;
01190 
01191         double dist = std::sqrt(x*x + y*y);
01192         if (pos_diff >= dist && yaw_diff >= std::abs(yaw))
01193         {
01194           best_state = current_state;
01195           pos_diff = dist;
01196           yaw_diff = std::abs(yaw);
01197           solution_found = true;
01198         }
01199       }
01200     }
01201   }
01202 
01203   if (solution_found)
01204     s = best_state;
01205 
01206   return solution_found;
01207 }
01208 
01209 bool FootstepPlanner::checkRobotCollision(const State& left_foot, const State& right_foot, bool& left, bool& right) const
01210 {
01211   left = !WorldModel::instance().isAccessible(left_foot);
01212   right = !WorldModel::instance().isAccessible(right_foot);
01213 
01214   if (!left && !right && !WorldModel::instance().isAccessible(left_foot, right_foot))
01215   {
01216     left = true;
01217     right = true;
01218   }
01219 
01220   return left || right;
01221 }
01222 
01223 bool FootstepPlanner::setStart(const State& left_foot, const State& right_foot, bool ignore_collision)
01224 {
01225   // check for errors
01226   if (std::isnan(left_foot.getRoll())) return false;
01227   if (std::isnan(left_foot.getPitch())) return false;
01228   if (std::isnan(left_foot.getYaw())) return false;
01229   if (std::isnan(right_foot.getRoll())) return false;
01230   if (std::isnan(right_foot.getPitch())) return false;
01231   if (std::isnan(right_foot.getYaw())) return false;
01232 
01233   bool left_collision = false;
01234   bool right_collision = false;
01235 
01236   if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
01237   {
01238     start_pose_set_up = false;
01239     return false;
01240   }
01241   else
01242     start_pose_set_up = true;
01243 
01244   ivStartFootLeft = left_foot;
01245   ivStartFootRight = right_foot;
01246 
01247   ROS_INFO("Start foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
01248            ivStartFootLeft.getX(), ivStartFootLeft.getY(), ivStartFootLeft.getZ(), ivStartFootLeft.getYaw(),
01249            ivStartFootRight.getX(), ivStartFootRight.getY(), ivStartFootRight.getZ(), ivStartFootRight.getYaw());
01250 
01251   return true;
01252 }
01253 
01254 bool FootstepPlanner::setStart(const msgs::StepPlanRequest& req, bool ignore_collision)
01255 {
01256   State left_foot(req.start.left);
01257   State right_foot(req.start.right);
01258 
01259   if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
01260   {
01261     double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
01262     left_foot.setZ(z);
01263     right_foot.setZ(z);
01264   }
01265 
01266   return setStart(left_foot, right_foot, ignore_collision);
01267 }
01268 
01269 bool FootstepPlanner::setGoal(const State& left_foot, const State& right_foot, bool ignore_collision)
01270 {
01271   // check for errors
01272   if (std::isnan(left_foot.getRoll())) return false;
01273   if (std::isnan(left_foot.getPitch())) return false;
01274   if (std::isnan(left_foot.getYaw())) return false;
01275   if (std::isnan(right_foot.getRoll())) return false;
01276   if (std::isnan(right_foot.getPitch())) return false;
01277   if (std::isnan(right_foot.getYaw())) return false;
01278 
01279   bool left_collision = false;
01280   bool right_collision = false;
01281 
01282   if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
01283   {
01284     goal_pose_set_up = false;
01285     return false;
01286   }
01287   else
01288     goal_pose_set_up = true;
01289 
01290   ivGoalFootLeft = left_foot;
01291   ivGoalFootRight = right_foot;
01292 
01293   ROS_INFO("Goal foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
01294            ivGoalFootLeft.getX(), ivGoalFootLeft.getY(), ivGoalFootLeft.getZ(), ivGoalFootLeft.getYaw(),
01295            ivGoalFootRight.getX(), ivGoalFootRight.getY(), ivGoalFootRight.getZ(), ivGoalFootRight.getYaw());
01296 
01297   return true;
01298 }
01299 
01300 bool FootstepPlanner::setGoal(const msgs::StepPlanRequest& req, bool ignore_collision)
01301 {
01302   State left_foot(req.goal.left);
01303   State right_foot(req.goal.right);
01304 
01305   if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
01306   {
01307     double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
01308     geometry_msgs::Vector3 n;
01309 
01310     left_foot.setZ(z);
01311     quaternionToNormal(req.start.left.pose.orientation, n);
01312     left_foot.setNormal(n);
01313 
01314     right_foot.setZ(z);
01315     quaternionToNormal(req.start.right.pose.orientation, n);
01316     right_foot.setNormal(n);
01317   }
01318 
01319   return setGoal(left_foot, right_foot, ignore_collision);
01320 }
01321 
01322 State FootstepPlanner::getFootPose(const State& robot, Leg leg, double dx, double dy, double dyaw)
01323 {
01324   double sign = -1.0;
01325   if (leg == LEFT)
01326     sign = 1.0;
01327 
01328   double cos_theta = cos(robot.getYaw());
01329   double sin_theta = sin(robot.getYaw());
01330   double shift_x = cos_theta * sign * dx - sin_theta * (0.5 * env_params->foot_seperation + dy);
01331   double shift_y = sin_theta * sign * dx + cos_theta * (0.5 * env_params->foot_seperation + dy);
01332 
01333   State foot(robot.getX() + sign * shift_x,
01334              robot.getY() + sign * shift_y,
01335              robot.getZ(),
01336              robot.getRoll(),
01337              robot.getPitch(),
01338              robot.getYaw() + sign * dyaw,
01339              leg);
01340 
01341   WorldModel::instance().update3DData(foot);
01342 
01343   return foot;
01344 }
01345 
01346 State FootstepPlanner::getFootPose(const State& robot, Leg leg)
01347 {
01348   return getFootPose(robot, leg, 0.0, 0.0, 0.0);
01349 }
01350 
01351 bool FootstepPlanner::pathIsNew(const std::vector<int>& new_path)
01352 {
01353   if (new_path.size() != ivPlanningStatesIds.size())
01354     return true;
01355 
01356   bool unequal = true;
01357   for (unsigned i = 0; i < new_path.size(); ++i)
01358     unequal = new_path[i] != ivPlanningStatesIds[i] && unequal;
01359 
01360   return unequal;
01361 }
01362 }


vigir_footstep_planner
Author(s): Alexander Stumpf
autogenerated on Thu Jun 6 2019 18:38:04