footstep_planner.cpp
Go to the documentation of this file.
2 
4 {
6  : foot_pose_transformer(FootPoseTransformer(nh))
7  , start_foot_selection(msgs::StepPlanRequest::AUTO)
8  , start_pose_set_up(false)
9  , goal_pose_set_up(false)
10  , max_number_steps(0.0)
11  , max_path_length_ratio(0.0)
12  , ivPathCost(0)
13  , ivCheckedFootContactSupport(new pcl::PointCloud<pcl::PointXYZI>())
14  , step_plan_uid(0)
15 {
16  nh.getParam("world_frame_id", frame_id);
17 
18  // publish topics
19  ivCheckedFootContactSupportPub = nh.advertise<sensor_msgs::PointCloud2>("foot_contact_support", 1);
20 
21  // initialize the planner environment
22  if (!ParameterManager::empty())
23  setParams(ParameterManager::getActive());
24  else
25  ROS_ERROR("[FootstepPlanner] Can't initialize environment due to missing parameters!");
26 }
27 
29 {
30  boost::recursive_mutex::scoped_lock lock(planner_mutex);
31 
32  planning_thread.interrupt();
33  planning_thread.join();
34 }
35 
37 {
38  if (env_params->ivPlannerType == "ARAPlanner" ||
39  env_params->ivPlannerType == "ADPlanner" ||
40  env_params->ivPlannerType == "RSTARPlanner" )
41  {
42  ROS_INFO_STREAM("Planning with " << env_params->ivPlannerType);
43  }
44  else
45  {
46  ROS_ERROR_STREAM("Planner " << env_params->ivPlannerType << " not available / untested.");
47  exit(1);
48  }
49  if (env_params->forward_search)
50  {
51  ROS_INFO_STREAM("Search direction: forward planning");
52  }
53  else
54  {
55  ROS_INFO_STREAM("Search direction: backward planning");
56  }
57 
58  if (env_params->ivPlannerType == "ARAPlanner")
59  {
60  ivPlannerPtr.reset(
61  new ARAPlanner(ivPlannerEnvironmentPtr.get(),
62  env_params->forward_search));
63  }
64  else if (env_params->ivPlannerType == "ADPlanner")
65  {
66  ivPlannerPtr.reset(
67  new ADPlanner(ivPlannerEnvironmentPtr.get(),
68  env_params->forward_search));
69  }
70  else if (env_params->ivPlannerType == "RSTARPlanner")
71  {
72  RSTARPlanner* p =
73  new RSTARPlanner(ivPlannerEnvironmentPtr.get(),
74  env_params->forward_search);
75  // new options, require patched SBPL
76  // p->set_local_expand_thres(500);
77  // p->set_eps_step(1.0);
78  ivPlannerPtr.reset(p);
79  }
80  // else if (env_params->ivPlannerType == "ANAPlanner")
81  // ivPlannerPtr.reset(new anaPlanner(ivPlannerEnvironmentPtr.get(),
82  // ivForwardSearch));
83 }
84 
86 {
87  return planning_thread.joinable();
88 }
89 
90 bool FootstepPlanner::plan(ReplanParams& params)
91 {
92  bool path_existed = (bool)ivPath.size();
93  int ret = 0;
94  MDPConfig mdp_config;
95  std::vector<int> solution_state_ids;
96 
97  // commit start/goal poses to the environment
99  ivPlannerEnvironmentPtr->getStateSpace()->updateStart(ivStartFootLeft, ivStartFootRight);
100  ivPlannerEnvironmentPtr->getStateSpace()->updateGoal(ivGoalFootLeft, ivGoalFootRight);
101  ivPlannerEnvironmentPtr->getStateSpace()->setPlannerStartAndGoal(start_foot_selection);
102  ivPlannerEnvironmentPtr->updateHeuristicValues();
103  ivPlannerEnvironmentPtr->InitializeEnv(NULL);
104  ivPlannerEnvironmentPtr->InitializeMDPCfg(&mdp_config);
105 
106  // inform AD planner about changed (start) states for replanning
107  if (path_existed &&
108  !env_params->forward_search &&
109  env_params->ivPlannerType == "ADPlanner")
110  {
111  std::vector<int> changed_edges;
112  changed_edges.push_back(mdp_config.startstateid);
113  // update the AD planner
114  boost::shared_ptr<ADPlanner> ad_planner =
115  boost::dynamic_pointer_cast<ADPlanner>(ivPlannerPtr);
116  ad_planner->update_preds_of_changededges(&changed_edges);
117  }
118 
119  // set up SBPL
120  if (ivPlannerPtr->set_start(mdp_config.startstateid) == 0)
121  {
122  ROS_ERROR("Failed to set start state.");
123  return false;
124  }
125  if (ivPlannerPtr->set_goal(mdp_config.goalstateid) == 0)
126  {
127  ROS_ERROR("Failed to set goal state");
128  return false;
129  }
130 
131  int path_cost;
132  ros::WallTime startTime = ros::WallTime::now();
133  try
134  {
135  ROS_INFO("Start planning (max time: %f, eps_0: %.2f, d_eps: %.2f, h(start, goal): %.3f (l) - %.3f (r))",
136  params.max_time, params.initial_eps, params.dec_eps,
137  (double)ivPlannerEnvironmentPtr->GetGoalHeuristic(ivPlannerEnvironmentPtr->getStateSpace()->ivIdStartFootLeft)/(double)cvMmScale,
138  (double)ivPlannerEnvironmentPtr->GetGoalHeuristic(ivPlannerEnvironmentPtr->getStateSpace()->ivIdStartFootRight)/(double)cvMmScale);
139  ret = ivPlannerPtr->replan(&solution_state_ids, params, &path_cost);
140  }
141  catch (const SBPL_Exception* e)
142  {
143  ROS_ERROR("SBPL planning failed (%s)", e->what());
144  return false;
145  }
146  ivPathCost = double(path_cost) / cvMmScale;
147 
148  bool path_is_new = pathIsNew(solution_state_ids);
149  if (ret && solution_state_ids.size() > 0 && path_is_new)
150  {
151  ROS_INFO("Solution of size %zu found after %f s",
152  solution_state_ids.size(),
153  (ros::WallTime::now()-startTime).toSec());
154 
155  if (extractPath(solution_state_ids))
156  {
157  ROS_INFO("Expanded states: %i total / %i new",
158  ivPlannerEnvironmentPtr->getNumExpandedStates(),
159  ivPlannerPtr->get_n_expands());
160  ROS_INFO("Final eps: %f", ivPlannerPtr->get_final_epsilon());
161  ROS_INFO("Path cost: %f (%i)\n", ivPathCost, path_cost);
162 
163  ivPlanningStatesIds = solution_state_ids;
164  return true;
165  }
166  else
167  {
168  ROS_ERROR("extracting path failed\n\n");
169  return false;
170  }
171  }
172  else if (!path_is_new)
173  {
174  ROS_ERROR("Solution found by SBPL is the same as the old solution. Replanning failed.");
175  return false;
176  }
177  else
178  {
179  ROS_ERROR("No solution found");
180  return false;
181  }
182 }
183 
184 bool FootstepPlanner::extractPath(const std::vector<int>& state_ids)
185 {
186  ivPath.clear();
187 
188  for(std::vector<int>::const_iterator state_ids_iter = state_ids.begin(); state_ids_iter != state_ids.end(); ++state_ids_iter)
189  {
190  State s;
191  if (!ivPlannerEnvironmentPtr->getStateSpace()->getState(*state_ids_iter, s))
192  {
193  ivPath.clear();
194  return false;
195  }
196  ivPath.push_back(s);
197  }
198 
199  // add last neutral step
200  if (ivPath.back().getLeg() == RIGHT)
201  ivPath.push_back(ivGoalFootLeft);
202  else // last_leg == LEFT
203  ivPath.push_back(ivGoalFootRight);
204 
205  return true;
206 }
207 
208 bool FootstepPlanner::setParams(const vigir_generic_params::ParameterSet& params)
209 {
210  boost::recursive_mutex::scoped_lock lock(planner_mutex);
211 
212  // reinitialize the planner environment parameters
213  env_params.reset(new EnvironmentParameters(params));
214 
215  std::string plugin_set;
216  if (params.getParam("plugin_set", plugin_set))
217  vigir_pluginlib::PluginManager::loadPluginSet(plugin_set);
218  else
219  ROS_WARN("[FootstepPlanner] setParams: No plugin set was given by parameter set '%s'", params.getName().c_str());
220 
221  // reinitialize step plan msg plugin
222  StepPlanMsgPlugin::Ptr plugin;
223  if (vigir_pluginlib::PluginManager::getPlugin(plugin))
224  plugin->loadParams(params);
225 
226  // reinitialize state generator
227  StateGenerator::mutableInstance().loadPlugins();
228  StateGenerator::mutableInstance().loadParams(params);
229 
230  // reinitialize robot model
231  RobotModel::mutableInstance().loadPlugins();
232  RobotModel::mutableInstance().loadParams(params);
233 
234  // reinitialize post processor
235  PostProcessor::mutableInstance().loadPlugins();
236  PostProcessor::mutableInstance().loadParams(params);
237 
238  // reinitialize world model
239  WorldModel::mutableInstance().loadPlugins();
240  WorldModel::mutableInstance().loadParams(params);
241 
242  // reinitialize step cost estimators
243  StepCostEstimator::mutableInstance().loadPlugins();
244  StepCostEstimator::mutableInstance().loadParams(params);
245 
246  // reinitialize heuristics
247  Heuristic::mutableInstance().loadPlugins();
248  Heuristic::mutableInstance().loadParams(params);
249 
250  resetTotally();
251 
252  return true;
253 }
254 
255 msgs::ErrorStatus FootstepPlanner::updateFoot(msgs::Foot& foot, uint8_t mode, bool transform) const
256 {
257  msgs::ErrorStatus status;
258 
259  // transform to sole frame
260  if (transform)
262 
263  if (mode & msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID)
264  {
265  State s(foot);
266  if (findNearestValidState(s))
267  s.getFoot(foot);
268  else
269  status += ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't determine valid position!");
270  }
271  else if (mode & msgs::UpdateMode::UPDATE_MODE_3D)
272  {
273  if (!WorldModel::instance().isTerrainModelAvailable() || !WorldModel::instance().getTerrainModel()->update3DData(foot.pose))
274  status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't update 3D data.", false);
275  }
276  else if (mode & msgs::UpdateMode::UPDATE_MODE_Z)
277  {
278  if (!WorldModel::instance().isTerrainModelAvailable() || !WorldModel::instance().getTerrainModel()->getHeight(foot.pose.position.x, foot.pose.position.y, foot.pose.position.z))
279  status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateFoot: Couldn't update z.", false);
280  }
281 
282  // transform back to robot frame
283  if (transform)
285 
286  foot.header.stamp = ros::Time::now();
287 
288  return status;
289 }
290 
291 msgs::ErrorStatus FootstepPlanner::updateFeet(msgs::Feet& feet, uint8_t mode, bool transform) const
292 {
293  msgs::ErrorStatus status;
294 
295  if (mode & msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID)
296  {
297  State left(feet.left);
298  State right(feet.right);
299  if (findNearestValidState(left) && findNearestValidState(right) && RobotModel::instance().isReachable(left, right))
300  {
301  left.getFoot(feet.left);
302  right.getFoot(feet.right);
303  }
304  else
305  status += ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "updateFeet: Couldn't determine valid position!");
306 
307  mode -= msgs::UpdateMode::UPDATE_MODE_MOVE_TO_VALID;
308  }
309 
310  status += updateFoot(feet.left, mode, transform);
311  status += updateFoot(feet.right, mode, transform);
312 
313  return status;
314 }
315 
316 msgs::ErrorStatus FootstepPlanner::updateStepPlan(msgs::StepPlan& step_plan, uint8_t mode, const std::string& /*param_set_name*/, bool transform) const
317 {
318  if (step_plan.steps.empty())
319  return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "[FootstepPlanner]", "updateStepPlan: Can't process empty step plan!");
320  if (step_plan.start.header.frame_id.empty())
321  return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "[FootstepPlanner]", "updateStepPlan: Can't process step plan due to missing start feet poses!");
322 
323  // lock entire planning system
324  boost::recursive_mutex::scoped_lock lock(planner_mutex);
325 
326  // transform to sole frame
327  if (transform)
329 
330  msgs::ErrorStatus status;
331 
332  if (mode & msgs::UpdateMode::UPDATE_MODE_REPLAN)
333  {
334  ROS_WARN("UPDATE_MODE_REPLAN isn't implemented yet!");
335  }
336  else
337  {
338  std::vector<msgs::Step>::iterator itr = step_plan.steps.begin();
339 
340  State left_state(step_plan.start.left);
341  State right_state(step_plan.start.right);
342  State prev_state(*itr);
343 
344  itr++;
345  for (; itr != step_plan.steps.end(); itr++)
346  {
347  msgs::Step& cur_step = *itr;
348  State cur_state = State(cur_step);
349 
350  // update feet
351  status += updateFoot(cur_step.foot, mode, false);
352 
353  // check reachability
354  if (mode & msgs::UpdateMode::UPDATE_MODE_CHECK_VALIDITY)
355  {
356  cur_step.valid = RobotModel::instance().isReachable(left_state, right_state, cur_state);
357  }
358 
359  // check collision
360  if (mode & msgs::UpdateMode::UPDATE_MODE_CHECK_COLLISION)
361  {
362  cur_step.colliding = !WorldModel::instance().isAccessible(cur_state, prev_state);
363  }
364 
365  // recompute cost
366  if (mode & msgs::UpdateMode::UPDATE_MODE_COST)
367  {
368  double c, r;
369  if (StepCostEstimator::instance().getCost(left_state, right_state, cur_state, c, r))
370  {
371  cur_step.cost = c;
372  cur_step.risk = r;
373  }
374  else
375  status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "updateStepPlan: Couldn't determine cost for step " + boost::lexical_cast<std::string>(cur_step.step_index) + "!");
376  }
377 
378  // prepare next iteration
379  if (cur_state.getLeg() == LEFT)
380  left_state = cur_state;
381  else
382  right_state = cur_state;
383 
384  prev_state = cur_state;
385  }
386  }
387 
388  // transform back to robot frame
389  if (transform)
391 
392  return msgs::ErrorStatus();
393 }
394 
396 {
397  boost::recursive_mutex::scoped_lock lock(planner_mutex);
398 
399  Heuristic::mutableInstance().resetPlugins();
400 
401  // reset the previously calculated paths
402  ivPath.clear();
403  ivPlanningStatesIds.clear();
405  // reset the planner
406  // INFO: force_planning_from_scratch was not working properly the last time
407  // checked; therefore instead of using this function the planner is manually
408  // reset
409  //ivPlannerPtr->force_planning_from_scratch();
410  ivPlannerEnvironmentPtr->reset();
411  setPlanner();
412 }
413 
414 
416 {
417  boost::recursive_mutex::scoped_lock lock(planner_mutex);
418 
419  // reset plugins
420  StepPlanMsgPlugin::Ptr plugin;
421  if (vigir_pluginlib::PluginManager::getPlugin(plugin))
422  plugin->reset();
423 
424  StateGenerator::mutableInstance().resetPlugins();
425  RobotModel::mutableInstance().resetPlugins();
426  PostProcessor::mutableInstance().resetPlugins();
427  StepCostEstimator::mutableInstance().resetPlugins();
428  Heuristic::mutableInstance().resetPlugins();
429 
430  // reset the previously calculated paths
431  ivPath.clear();
432  ivPlanningStatesIds.clear();
434  // reinitialize the planner environment
436  setPlanner();
437 }
438 
439 msgs::ErrorStatus FootstepPlanner::planSteps(msgs::StepPlanRequestService::Request& req)
440 {
441  // set start foot poses
442  if (!setStart(req.plan_request, true))
443  return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_START, "FootstepPlanner", "planSteps: Couldn't set start pose! Please check if poses are set!");
444 
445  // set goal foot poses
446  if (!setGoal(req.plan_request))
447  return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_GOAL, "FootstepPlanner", "planSteps: Couldn't set goal pose! Please check if poses are set!");
448 
449  reset();
450 
451  ReplanParams params(req.plan_request.max_planning_time > 0 ? req.plan_request.max_planning_time : env_params->max_planning_time);
452  params.initial_eps = env_params->initial_eps;
453  params.final_eps = 1.0;
454  params.dec_eps = env_params->decrease_eps;
455  params.return_first_solution = env_params->ivSearchUntilFirstSolution;
456  params.repair_time = -1;
457 
458  // start the planning and return success
459  if (!plan(params))
460  return ErrorStatusError(msgs::ErrorStatus::ERR_NO_SOLUTION, "FootstepPlanner", "planSteps: No solution found!");
461 
462  return msgs::ErrorStatus();
463 }
464 
465 msgs::ErrorStatus FootstepPlanner::planPattern(msgs::StepPlanRequestService::Request& req)
466 {
467  double cell_size = 0.0001;
468  int num_angle_bins = 2048;
469  double angle_bin_size = (2.0*M_PI / num_angle_bins);
470 
471  // set start foot poses
472  if (!setStart(req.plan_request, true))
473  return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_START, "FootstepPlanner", "planPattern: Couldn't set start pose! Please check if poses are set!");
474 
476  boost::shared_ptr<Footstep> footstep_left;
477  boost::shared_ptr<Footstep> footstep_right;
478 
479  unsigned int num_steps = req.plan_request.pattern_parameters.steps;
480  bool close_step = req.plan_request.pattern_parameters.close_step && num_steps > 0;
481  bool single_step_mode = false;
482 
483  bool change_z = true;
484  double step_up_height = std::abs(req.plan_request.pattern_parameters.dz);
485  double extra_seperation_factor = req.plan_request.pattern_parameters.extra_seperation ? 1.25 : 1.0;
486 
487  ROS_INFO("Start planning stepping (mode: %u, steps: %u)\n", req.plan_request.pattern_parameters.mode, num_steps);
488 
489  State previous_state;
490  State current_state;
491 
492  msgs::ErrorStatus status;
493 
494  switch (req.plan_request.pattern_parameters.mode)
495  {
496  case msgs::PatternParameters::STEP_UP:
497  case msgs::PatternParameters::STEP_DOWN:
498  case msgs::PatternParameters::STEP_OVER:
499  change_z = false; // as dz is used for step up/down motion
500  case msgs::PatternParameters::FORWARD:
501  {
502  footstep = boost::shared_ptr<Footstep>(
503  new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
504  0.0,
505  cell_size,
506  num_angle_bins,
507  env_params->hash_table_size));
508  previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
509  current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
510  break;
511  }
512  case msgs::PatternParameters::BACKWARD:
513  {
514  footstep = boost::shared_ptr<Footstep>(
515  new Footstep(-req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
516  0.0,
517  cell_size,
518  num_angle_bins,
519  env_params->hash_table_size));
520  previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
521  current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
522  break;
523  }
524  case msgs::PatternParameters::STRAFE_LEFT:
525  {
526  footstep = boost::shared_ptr<Footstep>(
527  new Footstep(0.0, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, 0.0,
528  0.0,
529  cell_size,
530  num_angle_bins,
531  env_params->hash_table_size));
532  previous_state = ivStartFootLeft;
533  current_state = ivStartFootRight;
534  single_step_mode = true;
535  break;
536  }
537  case msgs::PatternParameters::STRAFE_RIGHT:
538  {
539  footstep = boost::shared_ptr<Footstep>(
540  new Footstep(0.0, env_params->foot_seperation+req.plan_request.pattern_parameters.step_distance_sideward, 0.0,
541  0.0,
542  cell_size,
543  num_angle_bins,
544  env_params->hash_table_size));
545  previous_state = ivStartFootRight;
546  current_state = ivStartFootLeft;
547  single_step_mode = true;
548  break;
549  }
550  case msgs::PatternParameters::ROTATE_LEFT:
551  {
552  footstep = boost::shared_ptr<Footstep>(
553  new Footstep(-sin(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2,
554  cos(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2+(env_params->foot_seperation*extra_seperation_factor)/2,
555  req.plan_request.pattern_parameters.turn_angle,
556  0.0,
557  cell_size,
558  num_angle_bins,
559  env_params->hash_table_size));
560  previous_state = ivStartFootLeft;
561  current_state = ivStartFootRight;
562  single_step_mode = true;
563  break;
564  }
565  case msgs::PatternParameters::ROTATE_RIGHT:
566  {
567  footstep = boost::shared_ptr<Footstep>(
568  new Footstep(-sin(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2,
569  cos(req.plan_request.pattern_parameters.turn_angle)*(env_params->foot_seperation*extra_seperation_factor)/2+(env_params->foot_seperation*extra_seperation_factor)/2,
570  req.plan_request.pattern_parameters.turn_angle,
571  0.0,
572  cell_size,
573  num_angle_bins,
574  env_params->hash_table_size));
575  previous_state = ivStartFootRight;
576  current_state = ivStartFootLeft;
577  single_step_mode = true;
578  break;
579  }
580  case msgs::PatternParameters::SAMPLING:
581  {
582  // determine start foot
583  unsigned int start_foot;
584 
585  if (req.plan_request.start_foot_selection != msgs::StepPlanRequest::AUTO)
586  start_foot = req.plan_request.start_foot_selection;
587  else
588  {
589  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))
590  start_foot = msgs::StepPlanRequest::RIGHT;
591  else
592  start_foot = msgs::StepPlanRequest::LEFT;
593  }
594 
595  // generate footstep
596  if (req.plan_request.pattern_parameters.step_distance_sideward == 0.0 && req.plan_request.pattern_parameters.turn_angle == 0.0)
597  {
598  footstep_left = boost::shared_ptr<Footstep>(
599  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,
600  0.0,
601  cell_size,
602  num_angle_bins,
603  env_params->hash_table_size));
604  footstep_right = boost::shared_ptr<Footstep>(
605  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,
606  0.0,
607  cell_size,
608  num_angle_bins,
609  env_params->hash_table_size));
610  }
611  else if (start_foot == msgs::StepPlanRequest::LEFT)
612  {
613  footstep_left = boost::shared_ptr<Footstep>(
614  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,
615  0.0,
616  cell_size,
617  num_angle_bins,
618  env_params->hash_table_size));
619  footstep_right = boost::shared_ptr<Footstep>(
620  new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
621  0.0,
622  cell_size,
623  num_angle_bins,
624  env_params->hash_table_size));
625  }
626  else
627  {
628  footstep_left = boost::shared_ptr<Footstep>(
629  new Footstep(req.plan_request.pattern_parameters.step_distance_forward, env_params->foot_seperation, 0.0,
630  0.0,
631  cell_size,
632  num_angle_bins,
633  env_params->hash_table_size));
634  footstep_right = boost::shared_ptr<Footstep>(
635  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,
636  0.0,
637  cell_size,
638  num_angle_bins,
639  env_params->hash_table_size));
640  }
641 
642  // setup pattern generation
643  previous_state = start_foot == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
644  current_state = start_foot == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
645  break;
646  }
647  case msgs::PatternParameters::FEET_REALIGN_ON_CENTER:
648  {
649  State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
650  0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
651  0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
652  0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
653  0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
654  0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
655  NOLEG);
656 
657  // first add start foot
658  previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
659  current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
660  status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
661  if (hasError(status))
662  return status;
663 
664  // add pattern directly
665  if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
666  {
667  State temp = getFootPose(feet_center, RIGHT);
668  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
669 
670  temp = getFootPose(feet_center, LEFT);
671  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
672  }
673  else
674  {
675  State temp = getFootPose(feet_center, LEFT);
676  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
677 
678  temp = getFootPose(feet_center, RIGHT);
679  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
680  }
681 
682  return status;
683  }
684  case msgs::PatternParameters::FEET_REALIGN_ON_LEFT:
685  {
686  previous_state = ivStartFootRight;
687  current_state = ivStartFootLeft;
688  num_steps = 0;
689  close_step = true;
690  break;
691  }
692  case msgs::PatternParameters::FEET_REALIGN_ON_RIGHT:
693  {
694  previous_state = ivStartFootLeft;
695  current_state = ivStartFootRight;
696  num_steps = 0;
697  close_step = true;
698  break;
699  }
700  case msgs::PatternParameters::WIDE_STANCE:
701  {
702  State feet_center(0.5*(ivStartFootLeft.getX()+ivStartFootRight.getX()),
703  0.5*(ivStartFootLeft.getY()+ivStartFootRight.getY()),
704  0.5*(ivStartFootLeft.getZ()+ivStartFootRight.getZ()),
705  0.5*(ivStartFootLeft.getRoll()+ivStartFootRight.getRoll()),
706  0.5*(ivStartFootLeft.getPitch()+ivStartFootRight.getPitch()),
707  0.5*(ivStartFootLeft.getYaw()+ivStartFootRight.getYaw()),
708  NOLEG);
709 
710  // first add start foot
711  previous_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootRight : ivStartFootLeft;
712  current_state = req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT ? ivStartFootLeft : ivStartFootRight;
713  status += finalizeAndAddStepToPlan(current_state, req.plan_request.pattern_parameters, false);
714  if (hasError(status))
715  return status;
716 
717  // add pattern directly
718  if (req.plan_request.start_foot_selection == msgs::StepPlanRequest::RIGHT)
719  {
720  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);
721  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
722 
723  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);
724  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
725  }
726  else
727  {
728  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);
729  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
730 
731  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);
732  finalizeAndAddStepToPlan(temp, req.plan_request.pattern_parameters, false);
733  }
734 
735  return status;
736  }
737  default:
738  return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "planPattern: Unknown walk mode (" + boost::lexical_cast<std::string>(req.plan_request.pattern_parameters.mode) + ") set!");
739  }
740 
741  // generate common used step placements
742  Footstep parallel_step(0.0, env_params->foot_seperation, 0.0, 0.0, cell_size, num_angle_bins, env_params->hash_table_size);
743  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);
744  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);
745  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);
746 
747  // generate simple path via pattern generator
748  PlanningState previous_pstate(previous_state, cell_size, angle_bin_size, env_params->hash_table_size);
749  PlanningState current_pstate(current_state, cell_size, angle_bin_size, env_params->hash_table_size, &previous_pstate);
750 
751  // add start state
752  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
753  if (hasError(status))
754  return status;
755 
756  // add step up motion
757  if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_UP || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
758  {
759  // generate next step (temp needed due to current has pointer to previous!)
760  PlanningState temp = step_up.performMeOnThisState(current_pstate);
761  previous_pstate = current_pstate;
762  current_pstate = temp;
763 
764  current_pstate.getState().setZ(current_pstate.getState().getZ() + step_up_height);
765 
766  // add next step to plan
767  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
768  if (hasError(status))
769  return status;
770  }
771 
772  // add pattern
773  for (unsigned int i = 0; i < num_steps; i++)
774  {
775  // sampling uses alternating step sequences
776  if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::SAMPLING)
777  {
778  if (current_pstate.getState().getLeg() == LEFT)
779  footstep = footstep_right;
780  else if (current_pstate.getState().getLeg() == RIGHT)
781  footstep = footstep_left;
782  }
783 
784  // generate next step (temp needed due to current has pointer to previous!)
785  PlanningState temp = footstep->performMeOnThisState(current_pstate);
786  previous_pstate = current_pstate;
787  current_pstate = temp;
788 
789  // add next step to plan
790  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
791  if (hasError(status))
792  return status;
793 
794  // in single step mode, the second foot should be placed parallel after each step
795  if (single_step_mode && (!req.plan_request.pattern_parameters.close_step || i < (num_steps-1)))
796  {
797  // generate next step (temp needed due to current has pointer to previous!)
798  PlanningState temp = parallel_step_extra.performMeOnThisState(current_pstate);
799  previous_pstate = current_pstate;
800  current_pstate = temp;
801 
802  // add next step to plan
803  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, change_z);
804  if (hasError(status))
805  return status;
806  i++;
807  }
808  }
809 
810  // add step down motion
811  if (req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_DOWN || req.plan_request.pattern_parameters.mode == msgs::PatternParameters::STEP_OVER)
812  {
813  // generate next step (temp needed due to current has pointer to previous!)
814  PlanningState temp = step_down.performMeOnThisState(current_pstate);
815  previous_pstate = current_pstate;
816  current_pstate = temp;
817 
818  current_pstate.getState().setZ(current_pstate.getState().getZ() - step_up_height);
819 
820  // add next step to plan
821  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
822  if (hasError(status))
823  return status;
824  }
825 
826  // add final step so feet are parallel
827  if (close_step)
828  {
829  // generate next step (temp needed due to current has pointer to previous!)
830  PlanningState temp = parallel_step.performMeOnThisState(current_pstate);
831  previous_pstate = current_pstate;
832  current_pstate = temp;
833 
834  // add next step to plan
835  status += finalizeAndAddStepToPlan(current_pstate.getState(), req.plan_request.pattern_parameters, false);
836  if (hasError(status))
837  return status;
838  }
839 
840  return status;
841 }
842 
843 msgs::ErrorStatus FootstepPlanner::finalizeAndAddStepToPlan(State& s, const msgs::PatternParameters& params, bool change_z)
844 {
845  if (change_z)
846  s.setZ(s.getZ() + params.dz);
847 
848  if (params.override)
849  {
850  State temp = s;
851  temp.setRoll(params.roll);
852  temp.setPitch(params.pitch);
853  ivPath.push_back(temp);
854  return msgs::ErrorStatus();
855  }
856  else
857  {
858  ivPath.push_back(s);
859  return msgs::ErrorStatus();
860  }
861 
862  return ErrorStatusError(msgs::ErrorStatus::ERR_UNKNOWN, "FootstepPlanner", "addStepping: Something went wrong...");
863 }
864 
865 bool FootstepPlanner::finalizeStepPlan(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp, bool post_process)
866 {
867  resp.step_plan.header.frame_id = frame_id;
868  resp.step_plan.header.stamp = req.plan_request.header.stamp;
869  resp.step_plan.header.seq = step_plan_uid++;
870 
871  // add footstep plan
872  msgs::Step step;
873 
874  // init msg
875  StepPlanMsgPlugin::Ptr plugin;
876  if (vigir_pluginlib::PluginManager::getPlugin(plugin))
877  {
878  plugin->initMsg(resp.step_plan);
879  plugin->initMsg(step);
880  }
881 
882  step.header = resp.step_plan.header;
883  step.foot.header = resp.step_plan.header;
884  step.valid = true;
885  step.colliding = false;
886 
887  State left_foot = ivStartFootLeft;
888  State right_foot = ivStartFootRight;
889 
890  int step_index = req.plan_request.start_step_index;
891  resp.step_plan.steps.reserve(getPathSize());
892  for (state_iter_t path_iter = getPathBegin(); path_iter != getPathEnd(); ++path_iter)
893  {
894  State swing_foot = *path_iter;
895  const State& stand_foot = swing_foot.getLeg() == LEFT ? right_foot : left_foot;
896 
897  // post process step (needed for goal states and pattern mode)
898  if (swing_foot == ivGoalFootLeft || swing_foot == ivGoalFootRight ||
899  (path_iter != getPathBegin() && req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN))
900  {
901  if (env_params->forward_search)
902  PostProcessor::instance().postProcessForward(left_foot, right_foot, swing_foot);
903  else
904  PostProcessor::instance().postProcessBackward(left_foot, right_foot, swing_foot);
905  }
906 
907  // convert footstep
908  swing_foot.getStep(step);
909  if (swing_foot.getLeg() == LEFT)
910  step.foot.foot_index = msgs::Foot::LEFT;
911  else if (swing_foot.getLeg() == RIGHT)
912  step.foot.foot_index = msgs::Foot::RIGHT;
913  else
914  {
915  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());
916  continue;
917  }
918  step.step_index = step_index++;
919 
920 // const geometry_msgs::Vector3& v0 = stand_foot.getBodyVelocity();
921 // double body_vel0 = sqrt(v0.x*v0.x+v0.y*v0.y+v0.z*v0.z);
922 // const geometry_msgs::Vector3& v1 = swing_foot.getBodyVelocity();
923 // double body_vel1 = sqrt(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z);
924 // ROS_INFO("[%i] Sway dist: %.3f, Swing dist: %.3f", step.step_index, swing_foot.getSwayDistance(), swing_foot.getSwingDistance());
925 // 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);
926 // ROS_INFO("-------------------------------------");
927 
928  if (std::abs(stand_foot.getZ() - swing_foot.getZ()) > 0.18)
929  resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "finalizeStepPlan: Plan contains large lift heights");
930 
931  // finally add step to plan
932  resp.step_plan.steps.push_back(step);
933 
934  // next step
935  if (swing_foot.getLeg() == LEFT)
936  left_foot = swing_foot;
937  else if (swing_foot.getLeg() == RIGHT)
938  right_foot = swing_foot;
939  }
940 
941  // perform post processing on entire plan
942  PostProcessor::instance().postProcess(resp.step_plan);
943 
944  // add start and goal configuration
945  resp.step_plan.start.header = resp.step_plan.header;
946 
947  ivStartFootLeft.getFoot(resp.step_plan.start.left);
948  resp.step_plan.start.left.foot_index = msgs::Foot::LEFT;
949  resp.step_plan.start.left.header = resp.step_plan.header;
950 
951  ivStartFootRight.getFoot(resp.step_plan.start.right);
952  resp.step_plan.start.right.foot_index = msgs::Foot::RIGHT;
953  resp.step_plan.start.right.header = resp.step_plan.header;
954 
955  resp.step_plan.goal.header = resp.step_plan.header;
956 
957  ivGoalFootLeft.getFoot(resp.step_plan.goal.left);
958  resp.step_plan.goal.left.foot_index = msgs::Foot::LEFT;
959  resp.step_plan.goal.left.header = resp.step_plan.header;
960 
961  ivGoalFootRight.getFoot(resp.step_plan.goal.right);
962  resp.step_plan.goal.right.foot_index = msgs::Foot::RIGHT;
963  resp.step_plan.goal.right.header = resp.step_plan.header;
964 
965  // plan validation and computation of final cost
966  if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
967  updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_CHECK_VALIDITY | msgs::UpdateMode::UPDATE_MODE_CHECK_COLLISION | msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
968  else
969  updateStepPlan(resp.step_plan, msgs::UpdateMode::UPDATE_MODE_COST, std::string(), false);
970 
971  resp.final_eps = ivPlannerPtr->get_final_epsilon();
972  resp.planning_time = ivPlannerPtr->get_final_eps_planning_time();
973 
974  if (resp.status.error == msgs::ErrorStatus::NO_ERROR && resp.final_eps > 1.8)
975  resp.status += ErrorStatusWarning(msgs::ErrorStatus::WARN_UNKNOWN, "FootstepPlanner", "stepPlanRequestService: Suboptimal plan (eps: " + boost::lexical_cast<std::string>(resp.final_eps) + ")!");
976 
977  // some debug outputs and visualization stuff
978  double total_cost = 0.0;
979  double last_cost = 0.0;
980  for (std::vector<msgs::Step>::const_iterator itr = resp.step_plan.steps.begin(); itr != resp.step_plan.steps.end(); itr++)
981  {
982  step = *itr;
983 
984  geometry_msgs::Vector3 n;
985  quaternionToNormal(step.foot.pose.orientation, n);
986  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));
987  ROS_INFO("[%i] n: %.3f/%.3f/%.3f", step.step_index, n.x, n.y, n.z);
988  ROS_INFO("[%i] swing height: %.3f, sway duration: %.3f, step duration: %.3f", step.step_index, step.swing_height, step.sway_duration, step.step_duration);
989  ROS_INFO("[%i] valid: %s, colliding: %s", step.step_index, step.valid ? "y" : "n", step.colliding ? "y" : "n");
990  ROS_INFO("[%i] cost: %.3f risk: %.3f", step.step_index, step.cost, step.risk);
991 
992  total_cost += step.cost;
993  last_cost = step.cost;
994 
995  if (WorldModel::instance().isTerrainModelAvailable())
996  {
997  double support = 0.0;
998  WorldModel::instance().getTerrainModel()->getFootContactSupport(step.foot.pose, support, ivCheckedFootContactSupport);
999  ROS_INFO("[%i] Ground contact support: %.3f", step.step_index, support);
1000  }
1001 
1002  ROS_INFO("-------------------------------------");
1003  }
1004  ROS_INFO("Total path cost: %f (%f)", total_cost, total_cost-last_cost);
1005 
1007  {
1008  sensor_msgs::PointCloud2 msg;
1010  msg.header.frame_id = frame_id;
1011  msg.header.stamp = ros::Time::now();
1013  }
1014 
1015  // transform step plan
1017 
1018  return true;
1019 }
1020 
1021 msgs::ErrorStatus FootstepPlanner::stepPlanRequest(msgs::StepPlanRequestService::Request& req, ResultCB result_cb, FeedbackCB feedback_cb, PreemptCB preempt_cb)
1022 {
1023  // preempt any planning
1024  preemptPlanning();
1025 
1026  this->result_cb = result_cb;
1027  this->feedback_cb = feedback_cb;
1028  this->preempt_cb = preempt_cb;
1029 
1030  // check input
1031  // strip '/'
1032  std::string request_frame_id = strip_const(req.plan_request.header.frame_id, '/');
1033  std::string start_frame_id = strip_const(req.plan_request.start.header.frame_id, '/');
1034  std::string goal_frame_id = strip_const(req.plan_request.goal.header.frame_id, '/');
1035 
1036  if (request_frame_id != start_frame_id)
1037  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!");
1038 
1039  if (req.plan_request.planning_mode != msgs::StepPlanRequest::PLANNING_MODE_PATTERN && request_frame_id != goal_frame_id)
1040  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!");
1041 
1042  // load parameter set, if given
1043  if (!req.plan_request.parameter_set_name.data.empty())
1044  {
1045  if (!ParameterManager::setActive(req.plan_request.parameter_set_name.data))
1046  return ErrorStatusError(msgs::ErrorStatus::ERR_INVALID_PARAMETERS, "FootstepPlanner", "stepPlanRequest: Can't find parameter set named '" + req.plan_request.parameter_set_name.data + "'!");
1047 
1048  setParams(ParameterManager::getActive());
1049  }
1050  else
1051  {
1052  // just reset planner
1053  reset();
1054  }
1055 
1056  // transform feet poses
1057  foot_pose_transformer.transformToPlannerFrame(req.plan_request.start);
1058  foot_pose_transformer.transformToPlannerFrame(req.plan_request.goal);
1059 
1060  // set request specific parameters
1061  start_foot_selection = req.plan_request.start_foot_selection;
1062  max_number_steps = req.plan_request.max_number_steps;
1063  max_path_length_ratio = req.plan_request.max_path_length_ratio;
1064  frame_id = req.plan_request.header.frame_id;
1065  ivPlannerEnvironmentPtr->setFrameId(frame_id);
1066 
1067  // start planning
1068  startPlanning(req);
1069 
1070  return msgs::ErrorStatus();
1071 }
1072 
1073 bool FootstepPlanner::stepPlanRequestService(msgs::StepPlanRequestService::Request& req, msgs::StepPlanRequestService::Response& resp)
1074 {
1075  // generate step plan based on request
1076  resp.status += stepPlanRequest(req);
1077 
1078  if (hasError(resp.status))
1079  return true; // return always true so the message is returned
1080 
1081  // wait for thread to terminate
1082  planning_thread.join();
1083 
1084  // finalize plan and generate response
1085  finalizeStepPlan(req, resp, true);
1086 
1087  return true; // return always true so the message is returned
1088 }
1089 
1090 void FootstepPlanner::startPlanning(msgs::StepPlanRequestService::Request& req)
1091 {
1092  // start planning in seperate thread
1093  planning_thread = boost::thread(&FootstepPlanner::doPlanning, this, req);
1094 }
1095 
1096 void FootstepPlanner::doPlanning(msgs::StepPlanRequestService::Request& req)
1097 {
1098  // lock entire planning system
1099  boost::recursive_mutex::scoped_lock lock(planner_mutex);
1100 
1101  msgs::StepPlanRequestService::Response resp;
1102 
1103  // set world model mode
1104  if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_3D)
1105  WorldModel::mutableInstance().useTerrainModel(true);
1106  else if (req.plan_request.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_PATTERN)
1107  WorldModel::mutableInstance().useTerrainModel(req.plan_request.pattern_parameters.use_terrain_model);
1108  else
1109  WorldModel::mutableInstance().useTerrainModel(false);
1110 
1111  // dispatch planning mode and plan
1112  switch (req.plan_request.planning_mode)
1113  {
1114  case msgs::StepPlanRequest::PLANNING_MODE_2D:
1115  case msgs::StepPlanRequest::PLANNING_MODE_3D:
1116  resp.status = planSteps(req);
1117  break;
1118  case msgs::StepPlanRequest::PLANNING_MODE_PATTERN:
1119  resp.status = planPattern(req);
1120  break;
1121  default:
1122  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!");
1123  break;
1124  }
1125 
1126  // result callbacks
1127  if (!result_cb.empty())
1128  {
1129  // finalize plan and generate response
1130  if (!hasError(resp.status))
1131  finalizeStepPlan(req, resp, true);
1132  result_cb(resp);
1133  }
1134 }
1135 
1137 {
1138  if (!isPlanning())
1139  return;
1140 
1141  // interrupt main planning thread
1142  planning_thread.interrupt();
1143  planning_thread.join();
1144 
1145  if (!preempt_cb.empty())
1146  preempt_cb();
1147 }
1148 
1150 {
1151  if (WorldModel::instance().isAccessible(s))
1152  return true;
1153 
1154  State current_state = s;
1155  State best_state = s;
1156 
1157  double pos_diff = FLT_MAX;
1158  double yaw_diff = FLT_MAX;
1159  bool solution_found = false;
1160 
1161  // get transformation foot -> world
1162  tf::Transform t;
1163  t.setOrigin(s.getPose().getOrigin());
1164  t.setBasis(s.getPose().getBasis());
1165 
1166  tf::Vector3 orig_pos;
1167  tf::Vector3 trans_pos;
1168  orig_pos.setZ(0.0);
1169 
1170  for (double yaw = -0.2; yaw <= 0.4; yaw+=env_params->angle_bin_size)
1171  {
1172  current_state.setYaw(s.getYaw() + (s.getLeg() == LEFT ? yaw : -yaw));
1173  for (double y = -0.05; y <= 0.2; y+=env_params->cell_size)
1174  {
1175  orig_pos.setY(s.getLeg() == LEFT ? y : -y);
1176  for (double x = -0.15; x <= 0.15; x+=env_params->cell_size)
1177  {
1178  // determine point in world frame and get height at this point
1179  orig_pos.setX(x);
1180  trans_pos = t * orig_pos;
1181 
1182  current_state.setX(trans_pos.getX());
1183  current_state.setY(trans_pos.getY());
1184 
1185  if (!WorldModel::instance().update3DData(current_state))
1186  continue;
1187 
1188  if (!WorldModel::instance().isAccessible(current_state))
1189  continue;
1190 
1191  double dist = std::sqrt(x*x + y*y);
1192  if (pos_diff >= dist && yaw_diff >= std::abs(yaw))
1193  {
1194  best_state = current_state;
1195  pos_diff = dist;
1196  yaw_diff = std::abs(yaw);
1197  solution_found = true;
1198  }
1199  }
1200  }
1201  }
1202 
1203  if (solution_found)
1204  s = best_state;
1205 
1206  return solution_found;
1207 }
1208 
1209 bool FootstepPlanner::checkRobotCollision(const State& left_foot, const State& right_foot, bool& left, bool& right) const
1210 {
1211  left = !WorldModel::instance().isAccessible(left_foot);
1212  right = !WorldModel::instance().isAccessible(right_foot);
1213 
1214  if (!left && !right && !WorldModel::instance().isAccessible(left_foot, right_foot))
1215  {
1216  left = true;
1217  right = true;
1218  }
1219 
1220  return left || right;
1221 }
1222 
1223 bool FootstepPlanner::setStart(const State& left_foot, const State& right_foot, bool ignore_collision)
1224 {
1225  // check for errors
1226  if (std::isnan(left_foot.getRoll())) return false;
1227  if (std::isnan(left_foot.getPitch())) return false;
1228  if (std::isnan(left_foot.getYaw())) return false;
1229  if (std::isnan(right_foot.getRoll())) return false;
1230  if (std::isnan(right_foot.getPitch())) return false;
1231  if (std::isnan(right_foot.getYaw())) return false;
1232 
1233  bool left_collision = false;
1234  bool right_collision = false;
1235 
1236  if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
1237  {
1238  start_pose_set_up = false;
1239  return false;
1240  }
1241  else
1242  start_pose_set_up = true;
1243 
1244  ivStartFootLeft = left_foot;
1245  ivStartFootRight = right_foot;
1246 
1247  ROS_INFO("Start foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
1248  ivStartFootLeft.getX(), ivStartFootLeft.getY(), ivStartFootLeft.getZ(), ivStartFootLeft.getYaw(),
1249  ivStartFootRight.getX(), ivStartFootRight.getY(), ivStartFootRight.getZ(), ivStartFootRight.getYaw());
1250 
1251  return true;
1252 }
1253 
1254 bool FootstepPlanner::setStart(const msgs::StepPlanRequest& req, bool ignore_collision)
1255 {
1256  State left_foot(req.start.left);
1257  State right_foot(req.start.right);
1258 
1259  if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
1260  {
1261  double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
1262  left_foot.setZ(z);
1263  right_foot.setZ(z);
1264  }
1265 
1266  return setStart(left_foot, right_foot, ignore_collision);
1267 }
1268 
1269 bool FootstepPlanner::setGoal(const State& left_foot, const State& right_foot, bool ignore_collision)
1270 {
1271  // check for errors
1272  if (std::isnan(left_foot.getRoll())) return false;
1273  if (std::isnan(left_foot.getPitch())) return false;
1274  if (std::isnan(left_foot.getYaw())) return false;
1275  if (std::isnan(right_foot.getRoll())) return false;
1276  if (std::isnan(right_foot.getPitch())) return false;
1277  if (std::isnan(right_foot.getYaw())) return false;
1278 
1279  bool left_collision = false;
1280  bool right_collision = false;
1281 
1282  if (!ignore_collision && checkRobotCollision(left_foot, right_foot, left_collision, right_collision))
1283  {
1284  goal_pose_set_up = false;
1285  return false;
1286  }
1287  else
1288  goal_pose_set_up = true;
1289 
1290  ivGoalFootLeft = left_foot;
1291  ivGoalFootRight = right_foot;
1292 
1293  ROS_INFO("Goal foot poses set to (left: %f %f %f %f) and (right: %f %f %f %f)",
1294  ivGoalFootLeft.getX(), ivGoalFootLeft.getY(), ivGoalFootLeft.getZ(), ivGoalFootLeft.getYaw(),
1295  ivGoalFootRight.getX(), ivGoalFootRight.getY(), ivGoalFootRight.getZ(), ivGoalFootRight.getYaw());
1296 
1297  return true;
1298 }
1299 
1300 bool FootstepPlanner::setGoal(const msgs::StepPlanRequest& req, bool ignore_collision)
1301 {
1302  State left_foot(req.goal.left);
1303  State right_foot(req.goal.right);
1304 
1305  if (req.planning_mode == msgs::StepPlanRequest::PLANNING_MODE_2D)
1306  {
1307  double z = 0.5*(req.start.left.pose.position.z + req.start.right.pose.position.z);
1308  geometry_msgs::Vector3 n;
1309 
1310  left_foot.setZ(z);
1311  quaternionToNormal(req.start.left.pose.orientation, n);
1312  left_foot.setNormal(n);
1313 
1314  right_foot.setZ(z);
1315  quaternionToNormal(req.start.right.pose.orientation, n);
1316  right_foot.setNormal(n);
1317  }
1318 
1319  return setGoal(left_foot, right_foot, ignore_collision);
1320 }
1321 
1322 State FootstepPlanner::getFootPose(const State& robot, Leg leg, double dx, double dy, double dyaw)
1323 {
1324  double sign = -1.0;
1325  if (leg == LEFT)
1326  sign = 1.0;
1327 
1328  double cos_theta = cos(robot.getYaw());
1329  double sin_theta = sin(robot.getYaw());
1330  double shift_x = cos_theta * sign * dx - sin_theta * (0.5 * env_params->foot_seperation + dy);
1331  double shift_y = sin_theta * sign * dx + cos_theta * (0.5 * env_params->foot_seperation + dy);
1332 
1333  State foot(robot.getX() + sign * shift_x,
1334  robot.getY() + sign * shift_y,
1335  robot.getZ(),
1336  robot.getRoll(),
1337  robot.getPitch(),
1338  robot.getYaw() + sign * dyaw,
1339  leg);
1340 
1341  WorldModel::instance().update3DData(foot);
1342 
1343  return foot;
1344 }
1345 
1346 State FootstepPlanner::getFootPose(const State& robot, Leg leg)
1347 {
1348  return getFootPose(robot, leg, 0.0, 0.0, 0.0);
1349 }
1350 
1351 bool FootstepPlanner::pathIsNew(const std::vector<int>& new_path)
1352 {
1353  if (new_path.size() != ivPlanningStatesIds.size())
1354  return true;
1355 
1356  bool unequal = true;
1357  for (unsigned i = 0; i < new_path.size(); ++i)
1358  unequal = new_path[i] != ivPlanningStatesIds[i] && unequal;
1359 
1360  return unequal;
1361 }
1362 }
bool pathIsNew(const std::vector< int > &new_path)
std::vector< State >::const_iterator state_iter_t
void preemptPlanning()
stops thread running planning
void publish(const boost::shared_ptr< M > &message) const
TFSIMD_FORCE_INLINE void setX(tfScalar x)
msgs::ErrorStatus planPattern(msgs::StepPlanRequestService::Request &req)
plans stepping
TFSIMD_FORCE_INLINE void setY(tfScalar y)
bool checkRobotCollision(const State &left_foot, const State &right_foot, bool &left, bool &right) const
boost::function< void(msgs::PlanningFeedback)> FeedbackCB
static double getYaw(const Quaternion &bt_q)
boost::shared_ptr< SBPLPlanner > ivPlannerPtr
State getFootPose(const State &robot, Leg leg, double dx, double dy, double dyaw)
Returns the foot pose of a leg for a given robot pose.
XmlRpcServer s
TFSIMD_FORCE_INLINE void setZ(tfScalar z)
bool extractPath(const std::vector< int > &state_ids)
Extracts the path (list of foot poses) from a list of state IDs calculated by the SBPL...
msgs::ErrorStatus updateFeet(msgs::Feet &feet, uint8_t mode, bool transform=true) const
TFSIMD_FORCE_INLINE const tfScalar & getY() const
msgs::ErrorStatus updateFoot(msgs::Foot &foot, uint8_t mode, bool transform=true) const
boost::function< void(msgs::StepPlanRequestService::Response)> ResultCB
#define ROS_WARN(...)
void reset()
Reset the previous planning information.
msgs::ErrorStatus transformToRobotFrame(T &p) const
msgs::ErrorStatus updateStepPlan(msgs::StepPlan &result, uint8_t mode, const std::string &param_set_name=std::string(), bool transform=true) const
bool setStart(const State &left_foot, const State &right_foot, bool ignore_collision=false)
Sets the start pose as position of left and right footsteps.
bool setParams(const vigir_generic_params::ParameterSet &params)
#define ROS_INFO(...)
bool finalizeStepPlan(msgs::StepPlanRequestService::Request &req, msgs::StepPlanRequestService::Response &resp, bool post_process)
extracts step plan response from planning result
bool setGoal(const State &left_foot, const State &right_foot, bool ignore_collision=false)
Sets the goal pose as position of left and right footsteps.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
TFSIMD_FORCE_INLINE void setBasis(const Matrix3x3 &basis)
msgs::ErrorStatus planSteps(msgs::StepPlanRequestService::Request &req)
Start a planning task from scratch (will delete information of previous planning tasks). Map and start, goal poses need to be set beforehand.
void resetTotally()
Reset and reinitialize the environment.
TFSIMD_FORCE_INLINE const tfScalar & z() const
unsigned int step
uint32_t getNumSubscribers() const
msgs::ErrorStatus stepPlanRequest(msgs::StepPlanRequestService::Request &req, ResultCB result_cb=ResultCB(), FeedbackCB feedback_cb=FeedbackCB(), PreemptCB preempt_cb=PreemptCB())
void setPlanner()
Sets the planning algorithm used by SBPL.
#define ROS_INFO_STREAM(args)
static WallTime now()
boost::shared_ptr< FootstepPlannerEnvironment > ivPlannerEnvironmentPtr
bool getParam(const std::string &key, std::string &s) const
msgs::ErrorStatus transformToPlannerFrame(T &p) const
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
TFSIMD_FORCE_INLINE const tfScalar & getX() const
A class defining a footstep planner environment for humanoid robots used by the SBPL to perform plann...
static Time now()
void startPlanning(msgs::StepPlanRequestService::Request &req)
: starts planning in a new thread
msgs::ErrorStatus finalizeAndAddStepToPlan(State &s, const msgs::PatternParameters &env_params, bool change_z=true)
#define ROS_ERROR_STREAM(args)
bool stepPlanRequestService(msgs::StepPlanRequestService::Request &req, msgs::StepPlanRequestService::Response &resp)
Service handle to plan footsteps.
#define ROS_ERROR(...)
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
bool plan(ReplanParams &params)
Starts the planning task in the underlying SBPL.
pcl::PointCloud< pcl::PointXYZI >::Ptr ivCheckedFootContactSupport
void doPlanning(msgs::StepPlanRequestService::Request &req)
: method used in seperate thread


vigir_footstep_planner
Author(s): Alexander Stumpf
autogenerated on Sun Nov 17 2019 03:29:59