37 #include <moveit/benchmarks/benchmark_execution.h> 38 #include <moveit/benchmarks/benchmarks_utils.h> 43 #include <boost/regex.hpp> 44 #include <boost/tokenizer.hpp> 45 #include <boost/lexical_cast.hpp> 46 #include <boost/program_options/parsers.hpp> 47 #include <boost/program_options/variables_map.hpp> 48 #include <boost/algorithm/string/case_conv.hpp> 49 #include <boost/algorithm/string.hpp> 50 #include <boost/math/constants/constants.hpp> 51 #include <boost/progress.hpp> 52 #include <boost/date_time/posix_time/posix_time.hpp> 56 #include <Eigen/Geometry> 66 void checkConstrainedLink(moveit_msgs::Constraints& c,
const std::string& link_name)
68 for (std::size_t i = 0; i < c.position_constraints.size(); ++i)
69 if (c.position_constraints[i].link_name.empty())
70 c.position_constraints[i].link_name = link_name;
71 for (std::size_t i = 0; i < c.orientation_constraints.size(); ++i)
72 if (c.orientation_constraints[i].link_name.empty())
73 c.orientation_constraints[i].link_name = link_name;
76 void checkHeader(moveit_msgs::Constraints& c,
const std::string& header_frame)
78 for (std::size_t i = 0; i < c.position_constraints.size(); ++i)
79 if (c.position_constraints[i].header.frame_id.empty())
81 c.position_constraints[i].header.frame_id = header_frame;
84 for (std::size_t i = 0; i < c.orientation_constraints.size(); ++i)
85 if (c.orientation_constraints[i].header.frame_id.empty())
87 c.orientation_constraints[i].header.frame_id = header_frame;
94 moveit_benchmarks::BenchmarkExecution::BenchmarkExecution(
const planning_scene::PlanningScenePtr& scene,
96 : planning_scene_(scene), pss_(conn), psws_(conn), cs_(conn), tcs_(conn), rs_(conn)
102 "moveit_core",
"planning_interface::PlannerManager"));
106 ROS_FATAL_STREAM(
"Exception while creating planning plugin loader " << ex.what());
110 const std::vector<std::string>& classes = planner_plugin_loader_->getDeclaredClasses();
111 for (std::size_t i = 0; i < classes.size(); ++i)
113 ROS_INFO(
"Attempting to load and configure %s", classes[i].c_str());
116 planning_interface::PlannerManagerPtr p = planner_plugin_loader_->createUniqueInstance(classes[i]);
117 p->initialize(planning_scene_->getRobotModel(),
"");
118 planner_interfaces_[classes[i]] = p;
122 ROS_ERROR_STREAM(
"Exception while loading planner '" << classes[i] <<
"': " << ex.what());
127 if (planner_interfaces_.empty())
128 ROS_ERROR(
"No planning plugins have been loaded. Nothing to do for the benchmarking service.");
131 std::stringstream ss;
132 for (std::map<std::string, planning_interface::PlannerManagerPtr>::const_iterator it = planner_interfaces_.begin();
133 it != planner_interfaces_.end(); ++it)
134 ss << it->first <<
" ";
135 ROS_INFO(
"Available planner instances: %s", ss.str().c_str());
139 void moveit_benchmarks::BenchmarkExecution::runAllBenchmarks(BenchmarkType type)
143 bool world_only =
false;
146 if (!pss_.hasPlanningScene(options_.scene))
148 if (psws_.hasPlanningSceneWorld(options_.scene))
153 ok = psws_.getPlanningSceneWorld(pswwm, options_.scene);
155 catch (std::exception& ex)
165 std::stringstream ss;
166 std::vector<std::string> names;
167 pss_.getPlanningSceneNames(names);
168 for (std::size_t i = 0; i < names.size(); ++i)
169 ss << names[i] <<
" ";
170 ROS_ERROR(
"Scene '%s' not found in warehouse. Available names: %s", options_.scene.c_str(), ss.str().c_str());
179 ok = pss_.getPlanningScene(pswm, options_.scene);
181 catch (std::exception& ex)
188 ROS_ERROR(
"Scene '%s' not found in warehouse", options_.scene.c_str());
194 BenchmarkRequest req;
195 req.benchmark_type = type;
199 req.scene.world =
static_cast<const moveit_msgs::PlanningSceneWorld&
>(*pswwm);
200 req.scene.robot_model_name =
201 "NO ROBOT INFORMATION. ONLY WORLD GEOMETRY";
204 req.scene =
static_cast<const moveit_msgs::PlanningScene&
>(*pswm);
207 req.scene.name = options_.scene;
208 std::vector<std::string> planning_queries_names;
211 pss_.getPlanningQueriesNames(options_.query_regex, planning_queries_names, options_.scene);
213 catch (std::exception& ex)
217 if (planning_queries_names.empty())
218 ROS_DEBUG(
"Scene '%s' has no associated queries", options_.scene.c_str());
221 req.plugins = options_.plugins;
225 std::vector<std::string> start_states;
226 if (!options_.start_regex.empty())
228 boost::regex start_regex(options_.start_regex);
229 std::vector<std::string> state_names;
230 rs_.getKnownRobotStates(state_names);
231 for (std::size_t i = 0; i < state_names.size(); ++i)
234 if (boost::regex_match(state_names[i].c_str(), match, start_regex))
235 start_states.push_back(state_names[i]);
237 if (start_states.empty())
239 ROS_WARN(
"No stored states matched the provided regex: '%s'", options_.start_regex.c_str());
243 ROS_INFO(
"Running benchmark using %u start states.", (
unsigned int)start_states.size());
246 ROS_INFO(
"No specified start state. Running benchmark once with the default start state.");
248 unsigned int n_call = 0;
249 bool have_more_start_states =
true;
250 std::unique_ptr<moveit_msgs::RobotState> start_state_to_use;
251 while (have_more_start_states)
253 start_state_to_use.reset();
256 if (options_.start_regex.empty())
257 have_more_start_states =
false;
261 std::string state_name = start_states.back();
262 start_states.pop_back();
263 have_more_start_states = !start_states.empty();
265 bool got_robot_state =
false;
268 got_robot_state = rs_.getRobotState(robot_state, state_name);
270 catch (std::exception& ex)
277 start_state_to_use.reset(
new moveit_msgs::RobotState(*robot_state));
278 ROS_INFO(
"Loaded start state '%s'", state_name.c_str());
287 if (!options_.query_regex.empty())
289 for (std::size_t i = 0; i < planning_queries_names.size(); ++i)
292 pss_.getPlanningQuery(planning_query, options_.scene, planning_queries_names[i]);
295 req.goal_name = planning_queries_names[i];
298 req.motion_plan_request =
static_cast<const moveit_msgs::MotionPlanRequest&
>(*planning_query);
301 req.motion_plan_request.workspace_parameters = options_.workspace_parameters;
304 if (start_state_to_use)
305 req.motion_plan_request.start_state = *start_state_to_use;
306 req.filename = options_.output +
"." + boost::lexical_cast<std::string>(++n_call) +
".log";
307 if (!options_.group_override.empty())
308 req.motion_plan_request.group_name = options_.group_override;
310 if (options_.timeout > 0.0)
311 req.motion_plan_request.allowed_planning_time = options_.timeout;
313 if (!options_.default_constrained_link.empty())
315 checkConstrainedLink(req.motion_plan_request.path_constraints, options_.default_constrained_link);
316 for (std::size_t j = 0; j < req.motion_plan_request.goal_constraints.size(); ++j)
317 checkConstrainedLink(req.motion_plan_request.goal_constraints[j], options_.default_constrained_link);
319 if (!options_.planning_frame.empty())
321 checkHeader(req.motion_plan_request.path_constraints, options_.planning_frame);
322 for (std::size_t j = 0; j < req.motion_plan_request.goal_constraints.size(); ++j)
323 checkHeader(req.motion_plan_request.goal_constraints[j], options_.planning_frame);
326 ROS_INFO(
"Benckmarking query '%s' (%d of %d)", planning_queries_names[i].c_str(), (
int)i + 1,
327 (
int)planning_queries_names.size());
335 if (!options_.goal_regex.empty())
337 std::vector<std::string> cnames;
338 cs_.getKnownConstraints(options_.goal_regex, cnames);
339 for (std::size_t i = 0; i < cnames.size(); ++i)
342 bool got_constraints =
false;
345 got_constraints = cs_.getConstraints(constr, cnames[i]);
347 catch (std::exception& ex)
355 req.goal_name = cnames[i];
358 req.motion_plan_request = moveit_msgs::MotionPlanRequest();
359 req.motion_plan_request.goal_constraints.resize(1);
360 if (start_state_to_use)
361 req.motion_plan_request.start_state = *start_state_to_use;
362 req.motion_plan_request.goal_constraints[0] = *constr;
365 req.motion_plan_request.workspace_parameters = options_.workspace_parameters;
368 if (constr->position_constraints.size() == 1 && constr->orientation_constraints.size() == 1 &&
370 constr->position_constraints[0].constraint_region.primitive_poses.size() == 1 &&
371 constr->position_constraints[0].constraint_region.mesh_poses.empty())
373 geometry_msgs::Pose wMc_msg;
374 wMc_msg.position = constr->position_constraints[0].constraint_region.primitive_poses[0].position;
375 wMc_msg.orientation = constr->orientation_constraints[0].orientation;
379 Eigen::Affine3d offset_tf(Eigen::AngleAxis<double>(options_.offsets[3], Eigen::Vector3d::UnitX()) *
380 Eigen::AngleAxis<double>(options_.offsets[4], Eigen::Vector3d::UnitY()) *
381 Eigen::AngleAxis<double>(options_.offsets[5], Eigen::Vector3d::UnitZ()));
382 offset_tf.translation() = Eigen::Vector3d(options_.offsets[0], options_.offsets[1], options_.offsets[2]);
384 Eigen::Affine3d wMnc = wMc * offset_tf;
385 geometry_msgs::Pose wMnc_msg;
388 req.motion_plan_request.goal_constraints[0]
389 .position_constraints[0]
390 .constraint_region.primitive_poses[0]
391 .position = wMnc_msg.position;
392 req.motion_plan_request.goal_constraints[0].orientation_constraints[0].orientation = wMnc_msg.orientation;
395 if (!options_.group_override.empty())
396 req.motion_plan_request.group_name = options_.group_override;
397 if (options_.timeout > 0.0)
398 req.motion_plan_request.allowed_planning_time = options_.timeout;
399 if (!options_.default_constrained_link.empty())
400 checkConstrainedLink(req.motion_plan_request.goal_constraints[0], options_.default_constrained_link);
401 if (!options_.planning_frame.empty())
402 checkHeader(req.motion_plan_request.goal_constraints[0], options_.planning_frame);
403 req.filename = options_.output +
"." + boost::lexical_cast<std::string>(++n_call) +
".log";
405 ROS_INFO(
"Benckmarking goal '%s' (%d of %d)", cnames[i].c_str(), (
int)i + 1, (
int)cnames.size());
414 if (!options_.trajectory_regex.empty())
416 std::vector<std::string> cnames;
417 tcs_.getKnownTrajectoryConstraints(options_.trajectory_regex, cnames);
418 for (std::size_t i = 0; i < cnames.size(); ++i)
421 bool got_constraints =
false;
424 got_constraints = tcs_.getTrajectoryConstraints(constr, cnames[i]);
426 catch (std::exception& ex)
432 req.goal_name = cnames[i];
437 req.motion_plan_request = moveit_msgs::MotionPlanRequest();
438 if (start_state_to_use)
439 req.motion_plan_request.start_state = *start_state_to_use;
440 req.motion_plan_request.trajectory_constraints = *constr;
443 req.motion_plan_request.workspace_parameters = options_.workspace_parameters;
445 Eigen::Affine3d offset_tf(Eigen::AngleAxis<double>(options_.offsets[3], Eigen::Vector3d::UnitX()) *
446 Eigen::AngleAxis<double>(options_.offsets[4], Eigen::Vector3d::UnitY()) *
447 Eigen::AngleAxis<double>(options_.offsets[5], Eigen::Vector3d::UnitZ()));
448 offset_tf.translation() = Eigen::Vector3d(options_.offsets[0], options_.offsets[1], options_.offsets[2]);
451 for (std::size_t tc = 0; tc < constr->constraints.size(); ++tc)
454 if (constr->constraints[tc].position_constraints.size() == 1 &&
455 constr->constraints[tc].orientation_constraints.size() == 1 &&
457 constr->constraints[tc].position_constraints[0].constraint_region.primitive_poses.size() == 1 &&
458 constr->constraints[tc].position_constraints[0].constraint_region.mesh_poses.empty())
460 geometry_msgs::Pose wMc_msg;
461 wMc_msg.position = req.motion_plan_request.trajectory_constraints.constraints[tc]
462 .position_constraints[0]
463 .constraint_region.primitive_poses[0]
465 wMc_msg.orientation =
466 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation;
470 Eigen::Affine3d wMnc = wMc * offset_tf;
471 geometry_msgs::Pose wMnc_msg;
474 req.motion_plan_request.trajectory_constraints.constraints[tc]
475 .position_constraints[0]
476 .constraint_region.primitive_poses[0]
477 .position = wMnc_msg.position;
478 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation =
479 wMnc_msg.orientation;
481 if (!options_.default_constrained_link.empty())
482 checkConstrainedLink(req.motion_plan_request.trajectory_constraints.constraints[tc],
483 options_.default_constrained_link);
484 if (!options_.planning_frame.empty())
485 checkHeader(req.motion_plan_request.trajectory_constraints.constraints[tc], options_.planning_frame);
488 if (!options_.group_override.empty())
489 req.motion_plan_request.group_name = options_.group_override;
490 if (options_.timeout > 0.0)
491 req.motion_plan_request.allowed_planning_time = options_.timeout;
492 req.filename = options_.output +
".trajectory." + boost::lexical_cast<std::string>(i + 1) +
".log";
494 ROS_INFO(
"Benckmarking trajectory '%s' (%d of %d)", cnames[i].c_str(), (
int)i + 1, (
int)cnames.size());
502 bool moveit_benchmarks::BenchmarkExecution::readOptions(
const std::string&
filename)
504 ROS_INFO(
"Loading '%s'...", filename.c_str());
506 std::ifstream cfg(filename.c_str());
516 boost::program_options::options_description desc;
519 (
"scene.name", boost::program_options::value<std::string>(),
"Scene name")
520 (
"scene.runs", boost::program_options::value<std::string>()->
default_value(
"1"),
"Number of runs")
521 (
"scene.timeout", boost::program_options::value<std::string>()->default_value(
""),
"Timeout for planning (s)")
522 (
"scene.start", boost::program_options::value<std::string>()->default_value(
""),
"Regex for the start states to use")
523 (
"scene.query", boost::program_options::value<std::string>()->default_value(
".*"),
"Regex for the queries to execute")
524 (
"scene.goal", boost::program_options::value<std::string>()->default_value(
""),
"Regex for the names of constraints to use as goals")
525 (
"scene.trajectory", boost::program_options::value<std::string>()->default_value(
""),
"Regex for the names of constraints to use as trajectories")
526 (
"scene.group", boost::program_options::value<std::string>()->default_value(
""),
"Override the group to plan for")
527 (
"scene.planning_frame", boost::program_options::value<std::string>()->default_value(
""),
"Override the planning frame to use")
528 (
"scene.default_constrained_link", boost::program_options::value<std::string>()->default_value(
""),
529 "Specify the default link to consider as constrained when one is not specified in a moveit_msgs::Constraints message")
530 (
"scene.goal_offset_x", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in x")
531 (
"scene.goal_offset_y", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in y")
532 (
"scene.goal_offset_z", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in z")
533 (
"scene.goal_offset_roll", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in roll")
534 (
"scene.goal_offset_pitch", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in pitch")
535 (
"scene.goal_offset_yaw", boost::program_options::value<std::string>()->default_value(
"0.0"),
"Goal offset in yaw")
536 (
"scene.output", boost::program_options::value<std::string>(),
"Location of benchmark log file")
537 (
"scene.workspace", boost::program_options::value<std::string>(),
"Bounding box of workspace to plan in - min_x, min_y, min_z, max_x, max_y, max_z")
538 (
"scene.workspace_frame", boost::program_options::value<std::string>(),
"Frame id of bounding box of workspace to plan in");
541 boost::program_options::variables_map vm;
542 boost::program_options::parsed_options po = boost::program_options::parse_config_file(cfg, desc,
true);
545 boost::program_options::store(po, vm);
547 std::map<std::string, std::string> declared_options;
548 for (boost::program_options::variables_map::iterator it = vm.begin(); it != vm.end(); ++it)
549 declared_options[it->first] = boost::any_cast<std::string>(vm[it->first].value());
551 options_.scene = declared_options[
"scene.name"];
552 options_.start_regex = declared_options[
"scene.start"];
553 options_.query_regex = declared_options[
"scene.query"];
554 options_.goal_regex = declared_options[
"scene.goal"];
555 options_.trajectory_regex = declared_options[
"scene.trajectory"];
556 options_.group_override = declared_options[
"scene.group"];
557 options_.default_constrained_link = declared_options[
"scene.default_constrained_link"];
558 options_.planning_frame = declared_options[
"scene.planning_frame"];
561 memset(options_.offsets, 0, 6 *
sizeof(
double));
562 if (!declared_options[
"scene.goal_offset_x"].empty())
563 options_.offsets[0] = boost::lexical_cast<
double>(declared_options[
"scene.goal_offset_x"]);
564 if (!declared_options[
"scene.goal_offset_y"].empty())
565 options_.offsets[1] = boost::lexical_cast<double>(declared_options[
"scene.goal_offset_y"]);
566 if (!declared_options[
"scene.goal_offset_z"].empty())
567 options_.offsets[2] = boost::lexical_cast<double>(declared_options[
"scene.goal_offset_z"]);
568 if (!declared_options[
"scene.goal_offset_roll"].empty())
569 options_.offsets[3] = boost::lexical_cast<double>(declared_options[
"scene.goal_offset_roll"]);
570 if (!declared_options[
"scene.goal_offset_pitch"].empty())
571 options_.offsets[4] = boost::lexical_cast<double>(declared_options[
"scene.goal_offset_pitch"]);
572 if (!declared_options[
"scene.goal_offset_yaw"].empty())
573 options_.offsets[5] = boost::lexical_cast<double>(declared_options[
"scene.goal_offset_yaw"]);
575 catch (boost::bad_lexical_cast& ex)
581 if (!declared_options[
"scene.workspace"].empty())
583 std::vector<std::string> strings;
584 boost::split(strings, declared_options[
"scene.workspace"], boost::is_any_of(
","));
586 if (strings.size() != 6)
588 ROS_WARN_STREAM(
"Invalid number of workspace parameters. Expected 6, received " << strings.size());
590 else if (declared_options[
"scene.workspace_frame"].empty())
592 ROS_WARN_STREAM(
"No workspace_frame parameter provided, required with the workspace frame");
599 options_.workspace_parameters.header.frame_id = declared_options[
"scene.workspace_frame"];
601 options_.workspace_parameters.min_corner.x = boost::lexical_cast<
double>(strings[0]);
602 options_.workspace_parameters.min_corner.y = boost::lexical_cast<
double>(strings[1]);
603 options_.workspace_parameters.min_corner.z = boost::lexical_cast<
double>(strings[2]);
604 options_.workspace_parameters.max_corner.x = boost::lexical_cast<
double>(strings[3]);
605 options_.workspace_parameters.max_corner.y = boost::lexical_cast<
double>(strings[4]);
606 options_.workspace_parameters.max_corner.z = boost::lexical_cast<
double>(strings[5]);
608 catch (boost::bad_lexical_cast& ex)
616 options_.output = declared_options[
"scene.output"];
617 if (options_.output.empty())
618 options_.output = filename;
620 options_.plugins.clear();
623 std::size_t default_run_count = 1;
624 if (!declared_options[
"scene.runs"].empty())
628 default_run_count = boost::lexical_cast<std::size_t>(declared_options[
"scene.runs"]);
630 catch (boost::bad_lexical_cast& ex)
635 options_.default_run_count = default_run_count;
638 options_.timeout = 0.0;
639 if (!declared_options[
"scene.timeout"].empty())
643 options_.timeout = boost::lexical_cast<
double>(declared_options[
"scene.timeout"]);
645 catch (boost::bad_lexical_cast& ex)
652 std::vector<std::string> unr =
653 boost::program_options::collect_unrecognized(po.options, boost::program_options::exclude_positional);
655 std::unique_ptr<PlanningPluginOptions> bpo;
656 for (std::size_t i = 0; i < unr.size() / 2; ++i)
658 std::string key = boost::to_lower_copy(unr[i * 2]);
659 std::string val = unr[i * 2 + 1];
662 if (key.substr(0, 7) ==
"plugin.")
664 std::string k = key.substr(7);
668 options_.plugins.push_back(*bpo);
669 bpo.reset(
new PlanningPluginOptions());
671 bpo->runs = default_run_count;
673 else if (k ==
"runs")
679 bpo->runs = boost::lexical_cast<std::size_t>(val);
681 catch (boost::bad_lexical_cast& ex)
687 ROS_WARN(
"Ignoring option '%s' = '%s'. Please include plugin name first.", key.c_str(), val.c_str());
689 else if (k ==
"planners")
693 boost::char_separator<char> sep(
" ");
694 boost::tokenizer<boost::char_separator<char>> tok(val, sep);
695 for (boost::tokenizer<boost::char_separator<char>>::iterator beg = tok.begin(); beg != tok.end(); ++beg)
696 bpo->planners.push_back(*beg);
699 ROS_WARN(
"Ignoring option '%s' = '%s'. Please include plugin name first.", key.c_str(), val.c_str());
703 else if (key.substr(0, 6) ==
"sweep.")
705 std::string sweep_var = key.substr(6);
708 std::vector<std::string> strings;
709 boost::split(strings, val, boost::is_any_of(
":"));
711 if (strings.size() != 3)
714 << sweep_var <<
". Expected 3 values (start, iterator, end) but only received " 719 ParameterOptions new_sweep;
720 new_sweep.is_sweep =
true;
723 new_sweep.start = boost::lexical_cast<
double>(strings[0]);
724 new_sweep.step_size = boost::lexical_cast<
double>(strings[1]);
725 new_sweep.end = boost::lexical_cast<
double>(strings[2]);
726 new_sweep.key = sweep_var;
728 std::ostringstream ss;
729 ss <<
"param_" << sweep_var <<
" REAL";
730 new_sweep.log_key = ss.str();
732 catch (boost::bad_lexical_cast& ex)
738 if (new_sweep.start > new_sweep.end)
740 ROS_ERROR_STREAM(
"Invalid sweep parameter for key " << sweep_var <<
". Start is greater than end");
745 param_options_.push_back(new_sweep);
749 ROS_WARN(
"Unknown option: '%s' = '%s'", key.c_str(), val.c_str());
754 options_.plugins.push_back(*bpo);
766 void moveit_benchmarks::BenchmarkExecution::printOptions(std::ostream& out)
768 out <<
"Benchmark for scene '" << options_.scene <<
"' to be saved at location '" << options_.output <<
"'" 770 if (!options_.query_regex.empty())
771 out <<
"Planning requests associated to the scene that match '" << options_.query_regex <<
"' will be evaluated" 773 if (!options_.goal_regex.empty())
774 out <<
"Planning requests constructed from goal constraints that match '" << options_.goal_regex
775 <<
"' will be evaluated" << std::endl;
776 if (!options_.trajectory_regex.empty())
777 out <<
"Planning requests constructed from trajectory constraints that match '" << options_.trajectory_regex
778 <<
"' will be evaluated" << std::endl;
779 out <<
"Plugins:" << std::endl;
780 for (std::size_t i = 0; i < options_.plugins.size(); ++i)
782 out <<
" * name: " << options_.plugins[i].name <<
" (to be run " << options_.plugins[i].runs
783 <<
" times for each planner)" << std::endl;
784 out <<
" * planners:";
785 for (std::size_t j = 0; j < options_.plugins[i].planners.size(); ++j)
786 out <<
' ' << options_.plugins[i].planners[j];
791 void moveit_benchmarks::BenchmarkExecution::runBenchmark(BenchmarkRequest& req)
793 if (req.benchmark_type & BENCHMARK_PLANNERS)
794 runPlanningBenchmark(req);
795 if (req.benchmark_type & BENCHMARK_GOAL_EXISTANCE)
796 runGoalExistenceBenchmark(req);
799 void moveit_benchmarks::BenchmarkExecution::collectMetrics(RunData& rundata,
801 bool solved,
double total_time)
803 rundata[
"total_time REAL"] = boost::lexical_cast<std::string>(total_time);
804 rundata[
"solved BOOLEAN"] = boost::lexical_cast<std::string>(solved);
806 double clearance = 0.0;
807 double smoothness = 0.0;
811 double process_time = total_time;
812 for (std::size_t j = 0; j < mp_res.
trajectory_.size(); ++j)
829 planning_scene_->checkCollisionUnpadded(req, res, p.
getWayPoint(k));
834 double d = planning_scene_->distanceToCollisionUnpadded(p.
getWayPoint(k));
857 double acosValue = (a * a + b * b - cdist * cdist) / (2.0 * a * b);
858 if (acosValue > -1.0 && acosValue < 1.0)
861 double angle = (boost::math::constants::pi<double>() -
acos(acosValue));
864 double u = 2.0 * angle;
871 rundata[
"path_" + mp_res.
description_[j] +
"_correct BOOLEAN"] = boost::lexical_cast<std::string>(correct);
872 rundata[
"path_" + mp_res.
description_[j] +
"_length REAL"] = boost::lexical_cast<std::string>(L);
873 rundata[
"path_" + mp_res.
description_[j] +
"_clearance REAL"] = boost::lexical_cast<std::string>(clearance);
874 rundata[
"path_" + mp_res.
description_[j] +
"_smoothness REAL"] = boost::lexical_cast<std::string>(smoothness);
875 rundata[
"path_" + mp_res.
description_[j] +
"_time REAL"] =
879 if (process_time <= 0.0)
881 rundata[
"process_time REAL"] = boost::lexical_cast<std::string>(process_time);
888 const robot_model::JointModelGroup* group,
const double* ik_solution,
bool* reachable)
890 state->setJointGroupPositions(group, ik_solution);
900 void moveit_benchmarks::BenchmarkExecution::runPlanningBenchmark(BenchmarkRequest& req)
909 if (!req.plugins.empty())
910 for (std::size_t i = 0; i < req.plugins.size(); ++i)
911 if (planner_interfaces_.find(req.plugins[i].name) == planner_interfaces_.end())
912 ROS_ERROR(
"Planning interface '%s' was not found", req.plugins[i].name.c_str());
915 std::vector<planning_interface::PlannerManager*> planner_interfaces_to_benchmark;
918 std::vector<std::vector<std::string>> planner_ids_to_benchmark_per_planner_interface;
921 std::vector<std::size_t> runs_per_planner_interface;
926 for (std::map<std::string, planning_interface::PlannerManagerPtr>::const_iterator it = planner_interfaces_.begin();
927 it != planner_interfaces_.end(); ++it)
931 if (!req.plugins.empty())
933 for (std::size_t i = 0; i < req.plugins.size(); ++i)
935 if (req.plugins[i].name == it->first)
946 if (it->second->canServiceRequest(motion_plan_req))
949 planner_interfaces_to_benchmark.push_back(it->second.get());
952 planner_ids_to_benchmark_per_planner_interface.resize(planner_ids_to_benchmark_per_planner_interface.size() + 1);
953 runs_per_planner_interface.resize(runs_per_planner_interface.size() + 1, 1);
958 std::vector<std::string> known;
959 it->second->getPlanningAlgorithms(known);
961 if (found < 0 || req.plugins[found].planners.empty())
964 planner_ids_to_benchmark_per_planner_interface.back() = known;
968 runs_per_planner_interface.back() =
969 std::max<std::size_t>(1, req.plugins[found].runs);
972 for (std::size_t k = 0; k < req.plugins[found].planners.size(); ++k)
974 bool planner_found =
false;
975 for (std::size_t q = 0; q < known.size(); ++q)
978 if (known[q] == req.plugins[found].planners[k] ||
979 motion_plan_req.group_name +
"[" + req.plugins[found].planners[k] +
"]" == known[q])
981 planner_found =
true;
986 planner_ids_to_benchmark_per_planner_interface.back().push_back(req.plugins[found].planners[k]);
989 ROS_ERROR(
"The planner id '%s' is not known to the planning interface '%s'",
990 req.plugins[found].planners[k].c_str(), it->first.c_str());
993 for (std::size_t i = 0; i < known.size(); ++i)
1001 if (planner_ids_to_benchmark_per_planner_interface.back().empty())
1002 ROS_ERROR(
"Planning interface '%s' has no planners defined", it->first.c_str());
1005 ROS_WARN_STREAM(
"Planning interface '" << it->second->getDescription() <<
"' is not able to solve the specified " 1006 "benchmark problem.");
1010 if (planner_interfaces_to_benchmark.empty())
1012 ROS_ERROR(
"There are no planning interfaces to benchmark");
1017 std::stringstream sst;
1018 for (std::size_t i = 0; i < planner_interfaces_to_benchmark.size(); ++i)
1020 if (planner_ids_to_benchmark_per_planner_interface[i].empty())
1022 sst <<
" * " << planner_interfaces_to_benchmark[i]->getDescription() <<
" - Will execute interface " 1023 << runs_per_planner_interface[i] <<
" times:" << std::endl;
1024 for (std::size_t k = 0; k < planner_ids_to_benchmark_per_planner_interface[i].size(); ++k)
1025 sst <<
" - " << planner_ids_to_benchmark_per_planner_interface[i][k] << std::endl;
1028 ROS_INFO(
"Benchmarking Planning Interfaces:\n%s", sst.str().c_str());
1031 if (req.scene.robot_model_name != planning_scene_->getRobotModel()->getName())
1036 planning_scene_->getWorldNonConst()->clearObjects();
1037 planning_scene_->getCurrentStateNonConst().clearAttachedBodies();
1038 planning_scene_->getCurrentStateNonConst().setToDefaultValues();
1040 planning_scene_->processPlanningSceneWorldMsg(req.scene.world);
1043 planning_scene_->usePlanningSceneMsg(req.scene);
1046 std::size_t n_parameter_sets = generateParamCombinations();
1049 std::size_t total_n_planners = 0;
1050 std::size_t total_n_runs = 0;
1051 for (std::size_t i = 0; i < planner_ids_to_benchmark_per_planner_interface.size(); ++i)
1053 total_n_planners += planner_ids_to_benchmark_per_planner_interface[i].size();
1057 planner_ids_to_benchmark_per_planner_interface[i].size() * runs_per_planner_interface[i] * n_parameter_sets;
1062 boost::progress_display progress(total_n_runs, std::cout);
1063 std::vector<AlgorithmRunsData> data;
1064 std::vector<bool> first_solution_flag(planner_interfaces_to_benchmark.size(),
true);
1067 for (std::size_t i = 0; i < planner_interfaces_to_benchmark.size(); ++i)
1070 for (std::size_t j = 0; j < planner_ids_to_benchmark_per_planner_interface[i].size(); ++j)
1072 motion_plan_req.planner_id = planner_ids_to_benchmark_per_planner_interface[i][j];
1073 AlgorithmRunsData runs(runs_per_planner_interface[i] * n_parameter_sets);
1076 std::size_t param_combinations_id_ = 0;
1079 for (std::size_t param_count = 0; param_count < n_parameter_sets; ++param_count)
1086 RunData parameter_data;
1089 if (n_parameter_sets > 1)
1091 modifyPlannerConfiguration(*planner_interfaces_to_benchmark[i], motion_plan_req.planner_id,
1092 param_combinations_id_, parameter_data);
1093 ++param_combinations_id_;
1096 planning_interface::PlanningContextPtr pcontext =
1097 planner_interfaces_to_benchmark[i]->getPlanningContext(planning_scene_, motion_plan_req);
1100 for (
unsigned int run_count = 0; run_count < runs_per_planner_interface[i]; ++run_count)
1103 std::size_t run_id = run_count * n_parameter_sets + param_count;
1108 ROS_DEBUG(
"Calling %s:%s", planner_interfaces_to_benchmark[i]->getDescription().c_str(),
1109 motion_plan_req.planner_id.c_str());
1112 bool solved = pcontext->solve(mp_res);
1117 runs[run_id].insert(parameter_data.begin(), parameter_data.end());
1120 collectMetrics(runs[run_id], mp_res, solved, total_time);
1122 ROS_DEBUG(
"Spent %lf seconds collecting metrics", metrics_time);
1125 if (solved && first_solution_flag[i])
1127 first_solution_flag[i] =
false;
1132 data.push_back(runs);
1139 std::string
filename = req.filename.empty() ?
1140 (
"moveit_benchmarks_" + host +
"_" +
1141 boost::posix_time::to_iso_extended_string(startTime.
toBoost()) +
".log") :
1143 std::ofstream out(filename.c_str());
1144 out <<
"Experiment " << (planning_scene_->getName().empty() ?
"NO_NAME" : planning_scene_->getName()) << std::endl;
1145 out <<
"Running on " << (host.empty() ?
"UNKNOWN" : host) << std::endl;
1146 out <<
"Starting at " << boost::posix_time::to_iso_extended_string(startTime.
toBoost()) << std::endl;
1147 out <<
"Goal name " << (req.goal_name.empty() ?
"UNKNOWN" : req.goal_name) << std::endl;
1149 out << req.motion_plan_request.allowed_planning_time <<
" seconds per run" << std::endl;
1150 out << duration <<
" seconds spent to collect the data" << std::endl;
1151 out << total_n_planners <<
" planners" << std::endl;
1154 std::size_t run_id = 0;
1157 for (std::size_t q = 0; q < planner_interfaces_to_benchmark.size(); ++q)
1160 for (std::size_t p = 0; p < planner_ids_to_benchmark_per_planner_interface[q].size(); ++p)
1163 out << planner_interfaces_to_benchmark[q]->getDescription() +
"_" +
1164 planner_ids_to_benchmark_per_planner_interface[q][p]
1169 out <<
"0 common properties" << std::endl;
1172 std::set<std::string> properties_set;
1173 for (std::size_t j = 0; j < std::size_t(data[run_id].size()); ++j)
1175 for (RunData::const_iterator mit = data[run_id][j].begin(); mit != data[run_id][j].end(); ++mit)
1177 properties_set.insert(mit->first);
1182 std::vector<std::string> properties;
1183 for (std::set<std::string>::iterator it = properties_set.begin(); it != properties_set.end(); ++it)
1184 properties.push_back(*it);
1185 out << properties.size() <<
" properties for each run" << std::endl;
1188 for (
unsigned int j = 0; j < properties.size(); ++j)
1189 out << properties[j] << std::endl;
1190 out << data[run_id].size() <<
" runs" << std::endl;
1193 for (std::size_t j = 0; j < data[run_id].size(); ++j)
1195 for (
unsigned int k = 0; k < properties.size(); ++k)
1198 RunData::const_iterator it = data[run_id][j].find(properties[k]);
1199 if (it != data[run_id][j].end())
1207 out <<
'.' << std::endl;
1214 ROS_INFO(
"Results saved to '%s'", filename.c_str());
1217 void moveit_benchmarks::BenchmarkExecution::runGoalExistenceBenchmark(BenchmarkRequest& req)
1220 if (req.scene.robot_model_name != planning_scene_->getRobotModel()->getName())
1224 planning_scene_->getWorldNonConst()->clearObjects();
1225 planning_scene_->getCurrentStateNonConst().clearAttachedBodies();
1226 planning_scene_->getCurrentStateNonConst().setToDefaultValues();
1228 planning_scene_->processPlanningSceneWorldMsg(req.scene.world);
1229 planning_scene_->setName(req.scene.name);
1232 planning_scene_->usePlanningSceneMsg(req.scene);
1236 if (req.motion_plan_request.goal_constraints.size() == 0 &&
1237 req.motion_plan_request.goal_constraints[0].position_constraints.size() == 0 &&
1238 req.motion_plan_request.goal_constraints[0].position_constraints[0].constraint_region.primitive_poses.size() ==
1240 req.motion_plan_request.goal_constraints[0].orientation_constraints.size() == 0 &&
1241 req.motion_plan_request.trajectory_constraints.constraints.size() == 0)
1247 bool success =
false;
1248 bool reachable =
false;
1249 if (req.motion_plan_request.goal_constraints.size() > 0 &&
1250 req.motion_plan_request.goal_constraints[0].position_constraints.size() > 0 &&
1251 req.motion_plan_request.goal_constraints[0].position_constraints[0].constraint_region.primitive_poses.size() >
1253 req.motion_plan_request.goal_constraints[0].orientation_constraints.size() > 0)
1256 geometry_msgs::Pose ik_pose;
1257 ik_pose.position.x = req.motion_plan_request.goal_constraints[0]
1258 .position_constraints[0]
1259 .constraint_region.primitive_poses[0]
1261 ik_pose.position.y = req.motion_plan_request.goal_constraints[0]
1262 .position_constraints[0]
1263 .constraint_region.primitive_poses[0]
1265 ik_pose.position.z = req.motion_plan_request.goal_constraints[0]
1266 .position_constraints[0]
1267 .constraint_region.primitive_poses[0]
1269 ik_pose.orientation.x = req.motion_plan_request.goal_constraints[0].orientation_constraints[0].orientation.x;
1270 ik_pose.orientation.y = req.motion_plan_request.goal_constraints[0].orientation_constraints[0].orientation.y;
1271 ik_pose.orientation.z = req.motion_plan_request.goal_constraints[0].orientation_constraints[0].orientation.z;
1272 ik_pose.orientation.w = req.motion_plan_request.goal_constraints[0].orientation_constraints[0].orientation.w;
1274 robot_state::RobotState robot_state(planning_scene_->getCurrentState());
1275 robot_state::robotStateMsgToRobotState(req.motion_plan_request.start_state, robot_state);
1278 ROS_INFO_STREAM(
"Processing goal " << req.motion_plan_request.goal_constraints[0].name <<
" ...");
1280 success = robot_state.setFromIK(
1281 robot_state.getJointModelGroup(req.motion_plan_request.group_name), ik_pose,
1282 req.motion_plan_request.num_planning_attempts, req.motion_plan_request.allowed_planning_time,
1283 boost::bind(&isIKSolutionCollisionFree, planning_scene_.get(), _1, _2, _3, &reachable));
1290 ROS_INFO(
" Reachable, but in collision");
1299 std::string
filename = req.filename.empty() ?
1300 (
"moveit_benchmarks_" + host +
"_" +
1301 boost::posix_time::to_iso_extended_string(startTime.
toBoost()) +
".log") :
1303 std::ofstream out(filename.c_str());
1304 out <<
"Experiment " << (planning_scene_->getName().empty() ?
"NO_NAME" : planning_scene_->getName()) << std::endl;
1305 out <<
"Running on " << (host.empty() ?
"UNKNOWN" : host) << std::endl;
1306 out <<
"Starting at " << boost::posix_time::to_iso_extended_string(startTime.
toBoost()) << std::endl;
1307 out <<
"<<<|" << std::endl <<
"ROS" << std::endl << req.motion_plan_request << std::endl <<
"|>>>" << std::endl;
1308 out << req.motion_plan_request.allowed_planning_time <<
" seconds per run" << std::endl;
1309 out << duration <<
" seconds spent to collect the data" << std::endl;
1310 out <<
"reachable BOOLEAN" << std::endl;
1311 out <<
"collision_free BOOLEAN" << std::endl;
1312 out <<
"total_time REAL" << std::endl;
1313 out << reachable <<
"; " << success <<
"; " << duration << std::endl;
1315 ROS_INFO(
"Results saved to '%s'", filename.c_str());
1318 if (req.motion_plan_request.trajectory_constraints.constraints.size() > 0)
1324 std::string
filename = req.filename.empty() ?
1325 (
"moveit_benchmarks_" + host +
"_" +
1326 boost::posix_time::to_iso_extended_string(startTime.
toBoost()) +
".log") :
1328 std::ofstream out(filename.c_str());
1329 out <<
"Experiment " << (planning_scene_->getName().empty() ?
"NO_NAME" : planning_scene_->getName()) << std::endl;
1330 out <<
"Running on " << (host.empty() ?
"UNKNOWN" : host) << std::endl;
1331 out <<
"Starting at " << boost::posix_time::to_iso_extended_string(startTime.
toBoost()) << std::endl;
1332 out <<
"<<<|" << std::endl <<
"ROS" << std::endl << req.motion_plan_request << std::endl <<
"|>>>" << std::endl;
1333 out << req.motion_plan_request.allowed_planning_time <<
" seconds per run" << std::endl;
1334 out <<
"reachable BOOLEAN" << std::endl;
1335 out <<
"collision_free BOOLEAN" << std::endl;
1336 out <<
"total_time REAL" << std::endl;
1338 for (std::size_t tc = 0; tc < req.motion_plan_request.trajectory_constraints.constraints.size(); ++tc)
1340 geometry_msgs::Pose ik_pose;
1341 ik_pose.position.x = req.motion_plan_request.trajectory_constraints.constraints[tc]
1342 .position_constraints[0]
1343 .constraint_region.primitive_poses[0]
1345 ik_pose.position.y = req.motion_plan_request.trajectory_constraints.constraints[tc]
1346 .position_constraints[0]
1347 .constraint_region.primitive_poses[0]
1349 ik_pose.position.z = req.motion_plan_request.trajectory_constraints.constraints[tc]
1350 .position_constraints[0]
1351 .constraint_region.primitive_poses[0]
1353 ik_pose.orientation.x =
1354 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation.x;
1355 ik_pose.orientation.y =
1356 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation.y;
1357 ik_pose.orientation.z =
1358 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation.z;
1359 ik_pose.orientation.w =
1360 req.motion_plan_request.trajectory_constraints.constraints[tc].orientation_constraints[0].orientation.w;
1362 robot_state::RobotState robot_state(planning_scene_->getCurrentState());
1363 robot_state::robotStateMsgToRobotState(req.motion_plan_request.start_state, robot_state);
1367 << req.motion_plan_request.trajectory_constraints.constraints[tc].name <<
" ...");
1369 success = robot_state.setFromIK(
1370 robot_state.getJointModelGroup(req.motion_plan_request.group_name), ik_pose,
1371 req.motion_plan_request.num_planning_attempts, req.motion_plan_request.allowed_planning_time,
1372 boost::bind(&isIKSolutionCollisionFree, planning_scene_.get(), _1, _2, _3, &reachable));
1381 ROS_INFO(
" Reachable, but in collision");
1388 out << reachable <<
"; " << success <<
"; " << duration << std::endl;
1391 ROS_INFO(
"Results saved to '%s'", filename.c_str());
1396 const std::string& planner_id,
1397 std::size_t param_combinations_id_,
1398 RunData& parameter_data)
1404 planning_interface::PlannerConfigurationMap::iterator settings_it = settings.find(planner_id);
1405 if (settings_it != settings.end())
1408 std::string str_parameter_value;
1409 for (std::size_t i = 0; i < param_options_.size(); ++i)
1414 double value = param_combinations_[param_combinations_id_][param_options_[i].key];
1415 str_parameter_value = boost::lexical_cast<std::string>(value);
1417 catch (boost::bad_lexical_cast& ex)
1423 parameter_data[param_options_[i].log_key] = str_parameter_value;
1426 settings_it->second.config[param_options_[i].key] = str_parameter_value;
1431 ROS_ERROR_STREAM(
"Settings for " << planner_id <<
" do not exist. This should not happen.");
1438 std::size_t moveit_benchmarks::BenchmarkExecution::generateParamCombinations()
1440 if (!param_options_.size())
1444 ParameterInstance param_instance;
1445 for (std::size_t i = 0; i < param_options_.size(); ++i)
1448 param_instance[param_options_[i].key] = param_options_[i].start;
1452 int initial_options_id = 0;
1453 recursiveParamCombinations(initial_options_id, param_instance);
1467 return param_combinations_.size();
1470 void moveit_benchmarks::BenchmarkExecution::recursiveParamCombinations(
int options_id, ParameterInstance param_instance)
1473 const ParameterOptions& param_option = param_options_[options_id];
1478 if (param_options_.size() > options_id + 1)
1480 recursiveParamCombinations(options_id + 1, param_instance);
1484 param_combinations_.push_back(param_instance);
1488 param_instance[param_option.key] += param_option.step_size;
1491 }
while (param_instance[param_option.key] <= param_option.end + 0.00001);
1497 void moveit_benchmarks::BenchmarkExecution::printConfigurationSettings(
1501 for (planning_interface::PlannerConfigurationMap::const_iterator it = settings.begin(); it != settings.end(); ++it)
1503 out <<
" - " << it->first <<
" => " << it->second.name <<
"/" << it->second.group << std::endl;
1505 for (std::map<std::string, std::string>::const_iterator config_it = it->second.config.begin();
1506 config_it != it->second.config.end(); ++config_it)
1507 out <<
" - " << config_it->first <<
" => " << config_it->second << std::endl;
static std::string getHostname()
std::vector< std::string > description_
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
void poseMsgToEigen(const geometry_msgs::Pose &m, Eigen::Affine3d &e)
std::size_t countIndividualConstraints(const moveit_msgs::Constraints &constr)
std::map< std::string, PlannerConfigurationSettings > PlannerConfigurationMap
const PlannerConfigurationMap & getPlannerConfigurations() const
#define ROS_FATAL_STREAM(args)
std::vector< double > processing_time_
#define ROS_WARN_STREAM(args)
virtual void setPlannerConfigurations(const PlannerConfigurationMap &pcs)
moveit_msgs::MotionPlanRequest MotionPlanRequest
const robot_state::RobotState & getWayPoint(std::size_t index) const
std::size_t getWayPointCount() const
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
#define ROS_INFO_STREAM(args)
std::vector< robot_trajectory::RobotTrajectoryPtr > trajectory_
boost::posix_time::ptime toBoost() const
#define ROS_ERROR_STREAM(args)
bool isStateColliding(const std::string &group="", bool verbose=false)