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\n");
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       footstep_left = boost::shared_ptr<Footstep>(
00583                         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,
00584                                      0.0,
00585                                      cell_size,
00586                                      num_angle_bins,
00587                                      env_params->hash_table_size));
00588       footstep_right = boost::shared_ptr<Footstep>(
00589                          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,
00590                                       0.0,
00591                                       cell_size,
00592                                       num_angle_bins,
00593                                       env_params->hash_table_size));
00594       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00595       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00596       single_step_mode = std::abs(req.plan_request.pattern_parameters.step_distance_sideward) > 0.0;
00597       break;
00598     }
00599     case msgs::PatternParameters::FEET_REALIGN_ON_CENTER:
00600     {
00601       State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
00602                         0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
00603                         0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
00604                         0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
00605                         0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
00606                         0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
00607                         NOLEG);
00608 
00609       // first add start foot
00610       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00611       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00612       status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
00613       if (hasError(status))
00614         return status;
00615 
00616       // add pattern directly
00617       if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
00618       {
00619         State temp = getFootPose(feet_center, RIGHT);
00620         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00621 
00622         temp = getFootPose(feet_center, LEFT);
00623         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00624       }
00625       else
00626       {
00627         State temp = getFootPose(feet_center, LEFT);
00628         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00629 
00630         temp = getFootPose(feet_center, RIGHT);
00631         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00632       }
00633 
00634       return status;
00635     }
00636     case msgs::PatternParameters::FEET_REALIGN_ON_LEFT:
00637     {
00638       previous_state = ivStartFootRight;
00639       current_state = ivStartFootLeft;
00640       num_steps = 0;
00641       close_step = true;
00642       break;
00643     }
00644     case msgs::PatternParameters::FEET_REALIGN_ON_RIGHT:
00645     {
00646       previous_state = ivStartFootLeft;
00647       current_state = ivStartFootRight;
00648       num_steps = 0;
00649       close_step = true;
00650       break;
00651     }
00652     case msgs::PatternParameters::WIDE_STANCE:
00653     {
00654       State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
00655                         0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
00656                         0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
00657                         0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
00658                         0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
00659                         0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
00660                         NOLEG);
00661 
00662       // first add start foot
00663       previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
00664       current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
00665       status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
00666       if (hasError(status))
00667         return status;
00668 
00669       // add pattern directly
00670       if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
00671       {
00672         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);
00673         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00674 
00675         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);
00676         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00677       }
00678       else
00679       {
00680         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);
00681         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00682 
00683         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);
00684         finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
00685       }
00686 
00687       return status;
00688     }
00689     default:
00690       return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "planPattern: Unknown walk mode (" + boost::lexical_cast<std::string>(req.plan_request.pattern_parameters.mode) + ") set!");
00691   }
00692 
00693   // generate common used step placements
00694   Footstep parallel_step(0.0, env_params->foot_seperation, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
00695   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);
00696   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);
00697   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);
00698 
00699   // generate simple path via pattern generator
00700   PlanningState previous_pstate(previous_state, cell_size, angle_bin_size, env_params->hash_table_size);
00701   PlanningState current_pstate(current_state, cell_size, angle_bin_size, env_params->hash_table_size, &previous_pstate);
00702 
00703   // add start state
00704   status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00705   if (hasError(status))
00706     return status;
00707 
00708   // add step up motion
00709   if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_UP || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
00710   {
00711     // generate next step (temp needed due to current has pointer to previous!)
00712     PlanningState temp = step_up.performMeOnThisState(current_pstate);
00713     previous_pstate = current_pstate;
00714     current_pstate = temp;
00715 
00716     current_pstate.getState().setZ(current_pstate.getState().getZ() + step_up_height);
00717 
00718     // add next step to plan
00719     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00720     if (hasError(status))
00721       return status;
00722   }
00723 
00724   // add pattern
00725   for (unsigned int i = 0; i < num_steps; i++)
00726   {
00727     // sampling uses alternating step sequences
00728     if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::SAMPLING)
00729     {
00730       if (current_pstate.getState().getLeg() == LEFT)
00731         footstep = footstep_right;
00732       else if (current_pstate.getState().getLeg() == RIGHT)
00733         footstep = footstep_left;
00734     }
00735 
00736     // generate next step (temp needed due to current has pointer to previous!)
00737     PlanningState temp = footstep->performMeOnThisState(current_pstate);
00738     previous_pstate = current_pstate;
00739     current_pstate = temp;
00740 
00741     // add next step to plan
00742     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
00743     if (hasError(status))
00744       return status;
00745 
00746     // in single step mode, the second foot should be placed parallel after each step
00747     if (single_step_mode && (!req.plan_request.pattern_parameters.close_step || i < (num_steps-1)))
00748     {
00749       // generate next step (temp needed due to current has pointer to previous!)
00750       PlanningState temp = parallel_step_extra.performMeOnThisState(current_pstate);
00751       previous_pstate = current_pstate;
00752       current_pstate = temp;
00753 
00754       // add next step to plan
00755       status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
00756       if (hasError(status))
00757         return status;
00758       i++;
00759     }
00760   }
00761 
00762   // add step down motion
00763   if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_DOWN || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
00764   {
00765     // generate next step (temp needed due to current has pointer to previous!)
00766     PlanningState temp = step_down.performMeOnThisState(current_pstate);
00767     previous_pstate = current_pstate;
00768     current_pstate = temp;
00769 
00770     current_pstate.getState().setZ(current_pstate.getState().getZ() - step_up_height);
00771 
00772     // add next step to plan
00773     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00774     if (hasError(status))
00775       return status;
00776   }
00777 
00778   // add final step so feet are parallel
00779   if (close_step)
00780   {
00781     // generate next step (temp needed due to current has pointer to previous!)
00782     PlanningState temp = parallel_step.performMeOnThisState(current_pstate);
00783     previous_pstate = current_pstate;
00784     current_pstate = temp;
00785 
00786     // add next step to plan
00787     status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
00788     if (hasError(status))
00789       return status;
00790   }
00791 
00792   return status;
00793 }
00794 
00795 msgs::ErrorStatus FootstepPlanner::finalizeAndAddStepToPlan(State& s, const msgs::PatternParameters& params, bool change_z)
00796 {
00797   if (change_z)
00798     s.setZ(s.getZ() + params.dz);
00799 
00800   if (params.override)
00801   {
00802     State temp = s;
00803     temp.setRoll(params.roll);
00804     temp.setPitch(params.pitch);
00805     ivPath.push_back(temp);
00806     return msgs::ErrorStatus();
00807   }
00808   else
00809   {
00810     ivPath.push_back(s);
00811     return msgs::ErrorStatus();
00812   }
00813 
00814   return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "addStepping: Something went wrong...");
00815 }
00816 
00817 bool FootstepPlanner::finalizeStepPlan(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp, bool post_process)
00818 {
00819   resp.step_plan.header.frame_id = frame_id;
00820   resp.step_plan.header.stamp = req.plan_request.header.stamp;
00821   resp.step_plan.header.seq = step_plan_uid++;
00822 
00823   // add footstep plan
00824   msgs::Step step;
00825 
00826   // init msg
00827   StepPlanMsgPlugin::Ptr plugin;
00828   if (vigir_pluginlib::PluginManager::getPlugin(plugin))
00829   {
00830     plugin->initMsg(resp.step_plan);
00831     plugin->initMsg(step);
00832   }
00833 
00834   step.header = resp.step_plan.header;
00835   step.foot.header = resp.step_plan.header;
00836   step.valid = true;
00837   step.colliding = false;
00838 
00839   State left_foot = ivStartFootLeft;
00840   State right_foot = ivStartFootRight;
00841 
00842   int step_index = req.plan_request.start_step_index;
00843   resp.step_plan.steps.reserve(getPathSize());
00844   for (state_iter_t path_iter = getPathBegin(); path_iter != getPathEnd(); ++path_iter)
00845   {
00846     State swing_foot = *path_iter;
00847     const State& stand_foot = swing_foot.getLeg() == LEFT ? right_foot : left_foot;
00848 
00849     // post process step (needed for goal states and pattern mode)
00850     if (swing_foot == ivGoalFootLeft || swing_foot == ivGoalFootRight ||
00851         (path_iter != getPathBegin() && req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN))
00852     {
00853       if (env_params->forward_search)
00854         PostProcessor::instance().postProcessForward(left_foot, right_foot, swing_foot);
00855       else
00856         PostProcessor::instance().postProcessBackward(left_foot, right_foot, swing_foot);
00857     }
00858 
00859     // convert footstep
00860     swing_foot.getStep(step);
00861     if (swing_foot.getLeg() == LEFT)
00862       step.foot.foot_index = msgs::Foot::LEFT;
00863     else if (swing_foot.getLeg() == RIGHT)
00864       step.foot.foot_index = msgs::Foot::RIGHT;
00865     else
00866     {
00867       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());
00868       continue;
00869     }
00870     step.step_index = step_index++;
00871 
00872 //    const geometry_msgs::Vector3& v0 = stand_foot.getBodyVelocity();
00873 //    double body_vel0 = sqrt(v0.x*v0.x+v0.y*v0.y+v0.z*v0.z);
00874 //    const geometry_msgs::Vector3& v1 = swing_foot.getBodyVelocity();
00875 //    double body_vel1 = sqrt(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z);
00876 //    ROS_INFO("[%i] Sway dist: %.3f, Swing dist: %.3f", step.step_index, swing_foot.getSwayDistance(), swing_foot.getSwingDistance());
00877 //    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);
00878 //    ROS_INFO("-------------------------------------");
00879 
00880     if (std::abs(stand_foot.getZ() - swing_foot.getZ()) > 0.18)
00881       resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "finalizeStepPlan: Plan contains large lift heights");
00882 
00883     // finally add step to plan
00884     resp.step_plan.steps.push_back(step);
00885 
00886     // next step
00887     if (swing_foot.getLeg() == LEFT)
00888       left_foot = swing_foot;
00889     else if (swing_foot.getLeg() == RIGHT)
00890       right_foot = swing_foot;
00891   }
00892 
00893   // perform post processing on entire plan
00894   PostProcessor::instance().postProcess(resp.step_plan);
00895 
00896   // add start and goal configuration
00897   resp.step_plan.start.header = resp.step_plan.header;
00898 
00899   ivStartFootLeft.getFoot(resp.step_plan.start.left);
00900   resp.step_plan.start.left.foot_index = msgs::Foot::LEFT;
00901   resp.step_plan.start.left.header = resp.step_plan.header;
00902 
00903   ivStartFootRight.getFoot(resp.step_plan.start.right);
00904   resp.step_plan.start.right.foot_index = msgs::Foot::RIGHT;
00905   resp.step_plan.start.right.header = resp.step_plan.header;
00906 
00907   resp.step_plan.goal.header = resp.step_plan.header;
00908 
00909   ivGoalFootLeft.getFoot(resp.step_plan.goal.left);
00910   resp.step_plan.goal.left.foot_index = msgs::Foot::LEFT;
00911   resp.step_plan.goal.left.header = resp.step_plan.header;
00912 
00913   ivGoalFootRight.getFoot(resp.step_plan.goal.right);
00914   resp.step_plan.goal.right.foot_index = msgs::Foot::RIGHT;
00915   resp.step_plan.goal.right.header = resp.step_plan.header;
00916 
00917   // plan validation and computation of final cost
00918   if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
00919     updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_CHECK_VALIDITY | msgs::UpdateMode::UPDATE_MODE_CHECK_COLLISION |  msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
00920   else
00921     updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
00922 
00923   resp.final_eps = ivPlannerPtr->get_final_epsilon();
00924   resp.planning_time = ivPlannerPtr->get_final_eps_planning_time();
00925 
00926   if (resp.status.error == msgs::ErrorStatus::NO_ERROR && resp.final_eps > 1.8)
00927     resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "stepPlanRequestService: Suboptimal plan (eps: " + boost::lexical_cast<std::string>(resp.final_eps) + ")!");
00928 
00929   // some debug outputs and visualization stuff
00930   double total_cost = 0.0;
00931   double last_cost = 0.0;
00932   for (std::vector<msgs::Step>::const_iterator itr = resp.step_plan.steps.begin(); itr != resp.step_plan.steps.end(); itr++)
00933   {
00934     step = *itr;
00935 
00936     geometry_msgs::Vector3 n;
00937     quaternionToNormal(step.foot.pose.orientation, n);
00938     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));
00939     ROS_INFO("[%i] n: %.3f/%.3f/%.3f", step.step_index, n.x, n.y, n.z);
00940     ROS_INFO("[%i] swing height: %.3f, sway duration: %.3f, step duration: %.3f", step.step_index, step.swing_height, step.sway_duration, step.step_duration);
00941     ROS_INFO("[%i] valid: %s, colliding: %s", step.step_index, step.valid ? "y" : "n", step.colliding ? "y" : "n");
00942     ROS_INFO("[%i] cost: %.3f risk: %.3f", step.step_index, step.cost, step.risk);
00943 
00944     total_cost += step.cost;
00945     last_cost = step.cost;
00946 
00947     if (WorldModel::instance().isTerrainModelAvailable())
00948     {
00949       double support = 0.0;
00950       WorldModel::instance().getTerrainModel()->getFootContactSupport(step.foot.pose, support, ivCheckedFootContactSupport);
00951       ROS_INFO("[%i] Ground contact support: %.3f", step.step_index, support);
00952     }
00953 
00954     ROS_INFO("-------------------------------------");
00955   }
00956   ROS_INFO("Total path cost: %f (%f)", total_cost, total_cost-last_cost);
00957 
00958   if (ivCheckedFootContactSupportPub.getNumSubscribers() > 0)
00959   {
00960     sensor_msgs::PointCloud2 msg;
00961     pcl::toROSMsg(*ivCheckedFootContactSupport, msg);
00962     msg.header.frame_id = frame_id;
00963     msg.header.stamp = ros::Time::now();
00964     ivCheckedFootContactSupportPub.publish(msg);
00965   }
00966 
00967   // transform step plan
00968   foot_pose_transformer.transformToRobotFrame(resp.step_plan);
00969 
00970   return true;
00971 }
00972 
00973 msgs::ErrorStatus FootstepPlanner::stepPlanRequest(msgs::StepPlanRequestService::Request& req, ResultCB result_cb, FeedbackCB feedback_cb, PreemptCB preempt_cb)
00974 {
00975   // preempt any planning
00976   preemptPlanning();
00977 
00978   this->result_cb = result_cb;
00979   this->feedback_cb = feedback_cb;
00980   this->preempt_cb = preempt_cb;
00981 
00982   // check input
00983   // strip '/'
00984   std::string request_frame_id = strip_const(req.plan_request.header.frame_id, '/');
00985   std::string start_frame_id = strip_const(req.plan_request.start.header.frame_id, '/');
00986   std::string goal_frame_id = strip_const(req.plan_request.goal.header.frame_id, '/');
00987 
00988   if (request_frame_id != start_frame_id)
00989     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!");
00990 
00991   if (req.plan_request.planning_mode != msgs::StepPlanRequest::PLANNING_MODE_PATTERN && request_frame_id != goal_frame_id)
00992     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!");
00993 
00994   // load parameter set, if given
00995   if (!req.plan_request.parameter_set_name.data.empty())
00996   {
00997     if (!ParameterManager::setActive(req.plan_request.parameter_set_name.data))
00998       return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_PARAMETERS, "FootstepPlanner", "stepPlanRequest: Can't find parameter set named '" + req.plan_request.parameter_set_name.data + "'!");
00999 
01000     setParams(ParameterManager::getActive());
01001   }
01002   else
01003   {
01004     // just reset planner
01005     reset();
01006   }
01007 
01008   // transform feet poses
01009   foot_pose_transformer.transformToPlannerFrame(req.plan_request.start);
01010   foot_pose_transformer.transformToPlannerFrame(req.plan_request.goal);
01011 
01012   // set request specific parameters
01013   start_foot_selection = req.plan_request.start_foot_selection;
01014   max_number_steps = req.plan_request.max_number_steps;
01015   max_path_length_ratio = req.plan_request.max_path_length_ratio;
01016   frame_id = req.plan_request.header.frame_id;
01017   ivPlannerEnvironmentPtr->setFrameId(frame_id);
01018 
01019   // start planning
01020   startPlanning(req);
01021 
01022   return msgs::ErrorStatus();
01023 }
01024 
01025 bool FootstepPlanner::stepPlanRequestService(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp)
01026 {
01027   // generate step plan based on request
01028   resp.status += stepPlanRequest(req);
01029 
01030   if (hasError(resp.status))
01031     return true; // return always true so the message is returned
01032 
01033   // wait for thread to terminate
01034   planning_thread.join();
01035 
01036   // finalize plan and generate response
01037   finalizeStepPlan(req, resp, true);
01038 
01039   return true; // return always true so the message is returned
01040 }
01041 
01042 void FootstepPlanner::startPlanning(msgs::StepPlanRequestService::Request& req)
01043 {
01044   // start planning in seperate thread
01045   planning_thread = boost::thread(&FootstepPlanner::doPlanning, this, req);
01046 }
01047 
01048 void FootstepPlanner::doPlanning(msgs::StepPlanRequestService::Request& req)
01049 {
01050   // lock entire planning system
01051   boost::recursive_mutex::scoped_lock lock(planner_mutex);
01052 
01053   msgs::StepPlanRequestService::Response resp;
01054 
01055   // set world model mode
01056   if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_3D)
01057     WorldModel::mutableInstance().useTerrainModel(true);
01058   else if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
01059     WorldModel::mutableInstance().useTerrainModel(req.plan_request.pattern_parameters.use_terrain_model);
01060   else
01061     WorldModel::mutableInstance().useTerrainModel(false);
01062 
01063   // dispatch planning mode and plan
01064   switch (req.plan_request.planning_mode)
01065   {
01066     case msgs::StepPlanRequest::PLANNING_MODE_2D:
01067     case msgs::StepPlanRequest::PLANNING_MODE_3D:
01068       resp.status = planSteps(req);
01069       break;
01070     case msgs::StepPlanRequest::PLANNING_MODE_PATTERN:
01071       resp.status = planPattern(req);
01072       break;
01073     default:
01074       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!");
01075       break;
01076   }
01077 
01078   // result callbacks
01079   if (!result_cb.empty())
01080   {
01081     // finalize plan and generate response
01082     if (!hasError(resp.status))
01083       finalizeStepPlan(req, resp, true);
01084     result_cb(resp);
01085   }
01086 }
01087 
01088 void FootstepPlanner::preemptPlanning()
01089 {
01090   if (!isPlanning())
01091     return;
01092 
01093   // interrupt main planning thread
01094   planning_thread.interrupt();
01095   planning_thread.join();
01096 
01097   if (!preempt_cb.empty())
01098     preempt_cb();
01099 }
01100 
01101 bool FootstepPlanner::findNearestValidState(State& s) const
01102 {
01103   if (WorldModel::instance().isAccessible(s))
01104     return true;
01105 
01106   State current_state = s;
01107   State best_state = s;
01108 
01109   double pos_diff = FLT_MAX;
01110   double yaw_diff = FLT_MAX;
01111   bool solution_found = false;
01112 
01113   // get transformation foot -> world
01114   tf::Transform t;
01115   t.setOrigin(s.getPose().getOrigin());
01116   t.setBasis(s.getPose().getBasis());
01117 
01118   tf::Vector3 orig_pos;
01119   tf::Vector3 trans_pos;
01120   orig_pos.setZ(0.0);
01121 
01122   for (double yaw = -0.2; yaw <= 0.4; yaw+=env_params->angle_bin_size)
01123   {
01124     current_state.setYaw(s.getYaw() + (s.getLeg() == LEFT ? yaw : -yaw));
01125     for (double y = -0.05; y <= 0.2; y+=env_params->cell_size)
01126     {
01127       orig_pos.setY(s.getLeg() == LEFT ? y : -y);
01128       for (double x = -0.15; x <= 0.15; x+=env_params->cell_size)
01129       {
01130         // determine point in world frame and get height at this point
01131         orig_pos.setX(x);
01132         trans_pos = t * orig_pos;
01133 
01134         current_state.setX(trans_pos.getX());
01135         current_state.setY(trans_pos.getY());
01136 
01137         if (!WorldModel::instance().update3DData(current_state))
01138           continue;
01139 
01140         if (!WorldModel::instance().isAccessible(current_state))
01141           continue;
01142 
01143         double dist = std::sqrt(x*x + y*y);
01144         if (pos_diff >= dist && yaw_diff >= std::abs(yaw))
01145         {
01146           best_state = current_state;
01147           pos_diff = dist;
01148           yaw_diff = std::abs(yaw);
01149           solution_found = true;
01150         }
01151       }
01152     }
01153   }
01154 
01155   if (solution_found)
01156     s = best_state;
01157 
01158   return solution_found;
01159 }
01160 
01161 bool FootstepPlanner::checkRobotCollision(const State& left_foot, const State& right_foot, bool& left, bool& right) const
01162 {
01163   left = !WorldModel::instance().isAccessible(left_foot);
01164   right = !WorldModel::instance().isAccessible(right_foot);
01165 
01166   if (!left && !right && !WorldModel::instance().isAccessible(left_foot, right_foot))
01167   {
01168     left = true;
01169     right = true;
01170   }
01171 
01172   return left || right;
01173 }
01174 
01175 bool FootstepPlanner::setStart(const State& left_foot, const State& right_foot, bool ignore_collision)
01176 {
01177   // check for errors
01178   if (std::isnan(left_foot.getRoll())) return false;
01179   if (std::isnan(left_foot.getPitch())) return false;
01180   if (std::isnan(left_foot.getYaw())) return false;
01181   if (std::isnan(right_foot.getRoll())) return false;
01182   if (std::isnan(right_foot.getPitch())) return false;
01183   if (std::isnan(right_foot.getYaw())) return false;
01184 
01185   bool left_collision = false;
01186   bool right_collision = false;
01187 
01188   if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
01189   {
01190     start_pose_set_up = false;
01191     return false;
01192   }
01193   else
01194     start_pose_set_up = true;
01195 
01196   ivStartFootLeft = left_foot;
01197   ivStartFootRight = right_foot;
01198 
01199   ROS_INFO("Start foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
01200            ivStartFootLeft.getX(), ivStartFootLeft.getY(), ivStartFootLeft.getZ(), ivStartFootLeft.getYaw(),
01201            ivStartFootRight.getX(), ivStartFootRight.getY(), ivStartFootRight.getZ(), ivStartFootRight.getYaw());
01202 
01203   return true;
01204 }
01205 
01206 bool FootstepPlanner::setStart(const msgs::StepPlanRequest& req, bool ignore_collision)
01207 {
01208   State left_foot(req.start.left);
01209   State right_foot(req.start.right);
01210 
01211   if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
01212   {
01213     double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
01214     left_foot.setZ(z);
01215     right_foot.setZ(z);
01216   }
01217 
01218   return setStart(left_foot, right_foot, ignore_collision);
01219 }
01220 
01221 bool FootstepPlanner::setGoal(const State& left_foot, const State& right_foot, bool ignore_collision)
01222 {
01223   // check for errors
01224   if (std::isnan(left_foot.getRoll())) return false;
01225   if (std::isnan(left_foot.getPitch())) return false;
01226   if (std::isnan(left_foot.getYaw())) return false;
01227   if (std::isnan(right_foot.getRoll())) return false;
01228   if (std::isnan(right_foot.getPitch())) return false;
01229   if (std::isnan(right_foot.getYaw())) return false;
01230 
01231   bool left_collision = false;
01232   bool right_collision = false;
01233 
01234   if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
01235   {
01236     goal_pose_set_up = false;
01237     return false;
01238   }
01239   else
01240     goal_pose_set_up = true;
01241 
01242   ivGoalFootLeft = left_foot;
01243   ivGoalFootRight = right_foot;
01244 
01245   ROS_INFO("Goal foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
01246            ivGoalFootLeft.getX(), ivGoalFootLeft.getY(), ivGoalFootLeft.getZ(), ivGoalFootLeft.getYaw(),
01247            ivGoalFootRight.getX(), ivGoalFootRight.getY(), ivGoalFootRight.getZ(), ivGoalFootRight.getYaw());
01248 
01249   return true;
01250 }
01251 
01252 bool FootstepPlanner::setGoal(const msgs::StepPlanRequest& req, bool ignore_collision)
01253 {
01254   State left_foot(req.goal.left);
01255   State right_foot(req.goal.right);
01256 
01257   if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
01258   {
01259     double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
01260     geometry_msgs::Vector3 n;
01261 
01262     left_foot.setZ(z);
01263     quaternionToNormal(req.start.left.pose.orientation, n);
01264     left_foot.setNormal(n);
01265 
01266     right_foot.setZ(z);
01267     quaternionToNormal(req.start.right.pose.orientation, n);
01268     right_foot.setNormal(n);
01269   }
01270 
01271   return setGoal(left_foot, right_foot, ignore_collision);
01272 }
01273 
01274 State FootstepPlanner::getFootPose(const State& robot, Leg leg, double dx, double dy, double dyaw)
01275 {
01276   double sign = -1.0;
01277   if (leg == LEFT)
01278     sign = 1.0;
01279 
01280   double cos_theta = cos(robot.getYaw());
01281   double sin_theta = sin(robot.getYaw());
01282   double shift_x = cos_theta * sign * dx - sin_theta * (0.5 * env_params->foot_seperation + dy);
01283   double shift_y = sin_theta * sign * dx + cos_theta * (0.5 * env_params->foot_seperation + dy);
01284 
01285   State foot(robot.getX() + sign * shift_x,
01286              robot.getY() + sign * shift_y,
01287              robot.getZ(),
01288              robot.getRoll(),
01289              robot.getPitch(),
01290              robot.getYaw() + sign * dyaw,
01291              leg);
01292 
01293   WorldModel::instance().update3DData(foot);
01294 
01295   return foot;
01296 }
01297 
01298 State FootstepPlanner::getFootPose(const State& robot, Leg leg)
01299 {
01300   return getFootPose(robot, leg, 0.0, 0.0, 0.0);
01301 }
01302 
01303 bool FootstepPlanner::pathIsNew(const std::vector<int>& new_path)
01304 {
01305   if (new_path.size() != ivPlanningStatesIds.size())
01306     return true;
01307 
01308   bool unequal = true;
01309   for (unsigned i = 0; i < new_path.size(); ++i)
01310     unequal = new_path[i] != ivPlanningStatesIds[i] && unequal;
01311 
01312   return unequal;
01313 }
01314 }


vigir_footstep_planner
Author(s): Alexander Stumpf
autogenerated on Fri Apr 7 2017 02:59:36