1#include "MotionBenchmakerDemo.h"
2#include <boost/property_tree/ptree.hpp>
3#include <boost/property_tree/json_parser.hpp>
4#include <ompl/base/spaces/RealVectorStateSpace.h>
5#include <ompl/base/ProblemDefinition.h>
6#include <ompl/base/PlannerTerminationCondition.h>
7#include <ompl/geometric/planners/rrt/RRTConnect.h>
8#include <ompl/geometric/planners/rrt/RRTstar.h>
9#include <ompl/geometric/planners/fmt/FMT.h>
10#include <ompl/geometric/planners/prm/PRM.h>
11#include <ompl/geometric/planners/rrt/RRTConnect.h>
12#include <ompl/geometric/planners/rrt/RRT.h>
13#include <ompl/geometric/planners/kpiece/KPIECE1.h>
14#include <ompl/geometric/planners/kpiece/LBKPIECE1.h>
15#include <ompl/vamp/VampStateValidityChecker.h>
16#include <ompl/vamp/VampMotionValidator.h>
17#include <ompl/geometric/SimpleSetup.h>
18#include <ompl/vamp/VampStateSpace.h>
19#include <vamp/robots/panda.hh>
20#include <vamp/vector.hh>
21#include <vamp/collision/factory.hh>
22#include <ompl/tools/benchmark/Benchmark.h>
36 const std::string &plannerName)
37 : robotName_(robotName), plannerName_(plannerName)
39 loadProblemsFromJSON(problemFile);
40 initializeStateSpace();
43void MotionBenchmakerDemo::loadProblemsFromJSON(
const std::string &filename)
45 using boost::property_tree::ptree;
50 std::ifstream file(filename);
53 throw std::runtime_error(
"Failed to open JSON file: " + filename);
55 boost::property_tree::json_parser::read_json(file, pt);
57 catch (
const std::exception &e)
59 throw std::runtime_error(std::string(
"Failed to load JSON file: ") + e.what());
63 auto problemsIt = pt.find(
"problems");
64 if (problemsIt == pt.not_found())
66 throw std::runtime_error(
"JSON file does not contain 'problems' key");
70 for (
const auto &problemEntry : pt.get_child(
"problems"))
72 std::string problemName = problemEntry.first;
73 problemNames_.push_back(problemName);
75 const auto &problemInstances = problemEntry.second;
76 std::vector<ptree> instances;
79 for (
const auto &instanceEntry : problemInstances)
81 instances.push_back(instanceEntry.second);
84 problems_[problemName] = instances;
87 std::cout <<
"Loaded " << problemNames_.size() <<
" problem types from " << filename << std::endl;
90void MotionBenchmakerDemo::initializeStateSpace()
93 using Robot = vamp::robots::Panda;
94 space_ = std::make_shared<ompl::vamp::VampStateSpace<Robot>>();
97std::shared_ptr<ompl::base::Planner>
98MotionBenchmakerDemo::createPlanner(
const std::shared_ptr<ompl::base::SpaceInformation> &si)
const
100 std::shared_ptr<ompl::base::Planner> planner;
102 if (plannerName_ ==
"RRTConnect" || plannerName_ ==
"rrtc")
104 planner = std::make_shared<og::RRTConnect>(si);
106 else if (plannerName_ ==
"RRTstar" || plannerName_ ==
"rrtstar")
108 planner = std::make_shared<og::RRTstar>(si);
110 else if (plannerName_ ==
"FMT" || plannerName_ ==
"fmt")
112 planner = std::make_shared<og::FMT>(si);
114 else if (plannerName_ ==
"PRM" || plannerName_ ==
"prm")
116 planner = std::make_shared<og::PRM>(si);
118 else if (plannerName_ ==
"KPIECE1" || plannerName_ ==
"kpiece1")
120 planner = std::make_shared<og::KPIECE1>(si);
122 else if (plannerName_ ==
"RRT" || plannerName_ ==
"rrt")
124 planner = std::make_shared<og::RRT>(si);
126 else if (plannerName_ ==
"LBKPIECE1" || plannerName_ ==
"lbkpiece1")
128 planner = std::make_shared<og::LBKPIECE1>(si);
132 std::cerr <<
"Unknown planner '" << plannerName_ <<
"', using RRTConnect" << std::endl;
133 planner = std::make_shared<og::RRTConnect>(si);
139bool MotionBenchmakerDemo::setupProblem(
const std::string &problemName,
const boost::property_tree::ptree &problemData)
142 bool valid = problemData.get<
bool>(
"valid",
true);
149 vamp::collision::Environment<float> env_float;
150 bool is_box = problemName ==
"box" ? true :
false;
153 if (problemData.find(
"sphere") != problemData.not_found())
155 for (
const auto &sphereEntry : problemData.get_child(
"sphere"))
157 const auto &s = sphereEntry.second;
158 std::array<float, 3> center;
160 const auto &posChild =
161 (s.find(
"center") != s.not_found()) ? s.get_child(
"center") : s.get_child(
"position");
162 for (
const auto &coord : posChild)
165 center[i++] = std::stof(coord.second.data());
167 float radius = s.get<
float>(
"radius");
168 env_float.spheres.emplace_back(vamp::collision::factory::sphere::array(center, radius));
173 if (problemData.find(
"cylinder") != problemData.not_found())
175 for (
const auto &cylEntry : problemData.get_child(
"cylinder"))
177 const auto &c = cylEntry.second;
178 std::array<float, 3> center, orientation;
180 const auto &posChild =
181 (c.find(
"center") != c.not_found()) ? c.get_child(
"center") : c.get_child(
"position");
182 for (
const auto &coord : posChild)
185 center[i++] = std::stof(coord.second.data());
188 for (
const auto &euler : c.get_child(
"orientation_euler_xyz"))
191 orientation[i++] = std::stof(euler.second.data());
193 float radius = c.get<
float>(
"radius");
194 float length = c.get<
float>(
"length");
197 std::array<float, 3> halfExtents = {radius, radius, length / 2.0f};
198 env_float.cuboids.emplace_back(
199 vamp::collision::factory::cuboid::array(center, orientation, halfExtents));
203 env_float.capsules.emplace_back(
204 vamp::collision::factory::capsule::center::array(center, orientation, radius, length));
210 if (problemData.find(
"box") != problemData.not_found())
212 for (
const auto &boxEntry : problemData.get_child(
"box"))
214 const auto &b = boxEntry.second;
215 std::array<float, 3> center, orientation, halfExtents;
217 const auto &posChild =
218 (b.find(
"center") != b.not_found()) ? b.get_child(
"center") : b.get_child(
"position");
219 for (
const auto &coord : posChild)
222 center[i++] = std::stof(coord.second.data());
225 for (
const auto &euler : b.get_child(
"orientation_euler_xyz"))
228 orientation[i++] = std::stof(euler.second.data());
231 for (
const auto &extent : b.get_child(
"half_extents"))
234 halfExtents[i++] = std::stof(extent.second.data());
236 env_float.cuboids.emplace_back(vamp::collision::factory::cuboid::array(center, orientation, halfExtents));
240 using Environment = vamp::collision::Environment<vamp::FloatVector<vamp::FloatVectorWidth>>;
241 currentEnv_ = std::make_shared<Environment>(env_float);
243 using Robot = vamp::robots::Panda;
244 auto space_info = ss_->getSpaceInformation();
247 space_info->setStateValidityChecker(
248 std::make_shared<ompl::vamp::VampStateValidityChecker<Robot>>(space_info, *currentEnv_));
249 space_info->setMotionValidator(std::make_shared<ompl::vamp::VampMotionValidator<Robot>>(space_info, *currentEnv_));
252 ob::ScopedState<> start(space_);
253 ob::ScopedState<> goal(space_);
256 std::vector<double> startVec;
257 if (problemData.find(
"start") != problemData.not_found())
259 for (
const auto &val : problemData.get_child(
"start"))
261 startVec.push_back(std::stod(val.second.data()));
265 for (
size_t i = 0; i < startVec.size() && i < space_->getDimension(); ++i)
267 start[i] = startVec[i];
271 std::vector<double> goalVec;
272 if (problemData.find(
"goal") != problemData.not_found())
274 for (
const auto &val : problemData.get_child(
"goal"))
276 goalVec.push_back(std::stod(val.second.data()));
279 else if (problemData.find(
"goals") != problemData.not_found())
282 auto goalsChild = problemData.get_child(
"goals");
283 if (goalsChild.size() > 0)
285 auto firstGoal = goalsChild.begin()->second;
286 for (
const auto &val : firstGoal)
288 goalVec.push_back(std::stod(val.second.data()));
293 for (
size_t i = 0; i < goalVec.size() && i < space_->getDimension(); ++i)
295 goal[i] = goalVec[i];
312 ss_->setStartAndGoalStates(start, goal);
316PlanningResult MotionBenchmakerDemo::solveInstance(
const std::string &problemName,
317 const boost::property_tree::ptree &problemData,
318 double timeoutSeconds)
320 PlanningResult result;
321 ss_ = std::make_shared<og::SimpleSetup>(space_);
323 auto space_info = ss_->getSpaceInformation();
325 if (!setupProblem(problemName, problemData))
329 space_info = ss_->getSpaceInformation();
331 auto planner = createPlanner(space_info);
332 ss_->setPlanner(planner);
337 result.planningTime = ss_->getLastPlanComputationTime();
338 result.simplificationTime = ss_->getLastSimplificationTime();
342 result.solved =
true;
343 auto path = ss_->getSolutionPath();
344 result.pathVertices = path.getStateCount();
345 result.pathCost = path.length();
349 ob::PlannerData plannerData(space_info);
350 ss_->getPlanner()->getPlannerData(plannerData);
351 result.planningIterations = plannerData.numVertices();
359PlanningResult MotionBenchmakerDemo::benchmarkInstance(
const std::string &problemName,
360 const boost::property_tree::ptree &problemData,
361 unsigned int benchmarkTrials,
double timeoutSeconds)
363 PlanningResult result;
364 ss_ = std::make_shared<og::SimpleSetup>(space_);
366 if (!setupProblem(problemName, problemData))
370 auto space_info = ss_->getSpaceInformation();
372 double memoryLimit = 1000;
374 std::string benchmarkName = robotName_ +
"_" + problemName;
375 ot::Benchmark b(*ss_, benchmarkName);
376 ot::Benchmark::Request request(timeoutSeconds, memoryLimit, benchmarkTrials);
378 b.addPlanner(std::make_shared<og::RRTConnect>(space_info));
379 b.addPlanner(std::make_shared<og::PRM>(space_info));
380 b.addPlanner(std::make_shared<og::KPIECE1>(space_info));
381 b.addPlanner(std::make_shared<og::LBKPIECE1>(space_info));
383 b.benchmark(request);
384 b.saveResultsToFile(
"vamp_mbm_cpp.log");
385 result.solved =
true;
392 unsigned int benchmarkTrials,
double timeoutSeconds)
394 std::vector<PlanningResult> allResults;
396 if (problems_.find(problemName) == problems_.end())
398 std::cerr <<
"Problem '" << problemName <<
"' not found" << std::endl;
402 const auto &instances = problems_[problemName];
403 std::cout <<
"Benchmarking '" << problemName <<
"' with " << instances.size() <<
" instances..." << std::endl;
405 for (
size_t i = 0; i < instances.size(); ++i)
407 std::cout <<
" Instance " << i + 1 <<
"/" << instances.size() <<
"... ";
410 if (benchmarkTrials == 0)
412 auto result = solveInstance(problemName, instances[i], timeoutSeconds);
413 allResults.push_back(result);
417 auto result = benchmarkInstance(problemName, instances[i], benchmarkTrials, timeoutSeconds);
418 allResults.push_back(result);
427 double timeoutSeconds,
430 std::map<std::string, std::vector<PlanningResult>> allResults;
432 for (
const auto &problemName : problemNames_)
438 auto results =
benchmarkProblem(problemName, benchmarkTrials, timeoutSeconds);
439 allResults[problemName] = results;
443 unsigned int failures = 0;
444 for (
const auto &result : results)
453 std::cout <<
" Failed: " << failures <<
"/" << results.size() << std::endl;
465 std::cout <<
"No results for problem '" << problemName <<
"'" << std::endl;
470 unsigned int successes = 0;
471 std::vector<double> planningTimes;
472 std::vector<double> pathCosts;
473 std::vector<unsigned int> iterations;
474 std::vector<unsigned int> vertices;
476 for (
const auto &result : results)
481 planningTimes.push_back(result.planningTime);
482 pathCosts.push_back(result.pathCost);
483 iterations.push_back(result.planningIterations);
484 vertices.push_back(result.pathVertices);
488 std::cout <<
"\n=== Statistics for '" << problemName <<
"' ===" << std::endl;
489 std::cout <<
"Success Rate: " << successes <<
"/" << results.size() << std::endl;
494 auto minMaxTime = std::minmax_element(planningTimes.begin(), planningTimes.end());
495 double meanTime = std::accumulate(planningTimes.begin(), planningTimes.end(), 0.0) / planningTimes.size();
497 auto minMaxCost = std::minmax_element(pathCosts.begin(), pathCosts.end());
498 double meanCost = std::accumulate(pathCosts.begin(), pathCosts.end(), 0.0) / pathCosts.size();
500 std::cout << std::fixed << std::setprecision(4);
501 std::cout <<
"Planning Time (s): min=" << *minMaxTime.first <<
", max=" << *minMaxTime.second
502 <<
", mean=" << meanTime << std::endl;
504 std::cout <<
"Path Cost (m): min=" << *minMaxCost.first <<
", max=" << *minMaxCost.second
505 <<
", mean=" << meanCost << std::endl;
507 unsigned int meanIter = std::accumulate(iterations.begin(), iterations.end(), 0u) / iterations.size();
508 unsigned int meanVert = std::accumulate(vertices.begin(), vertices.end(), 0u) / vertices.size();
510 std::cout <<
"Mean Iterations: " << meanIter << std::endl;
511 std::cout <<
"Mean Path Vertices: " << meanVert << std::endl;
513 std::cout << std::endl;
std::map< std::string, std::vector< PlanningResult > > benchmarkAll(unsigned int numTrials=1, double timeoutSeconds=5.0, bool print_failures=false)
Run benchmarks on all problems in the loaded file.
static void printStatistics(const std::string &problemName, const std::vector< PlanningResult > &results)
Print summary statistics for a set of results.
MotionBenchmakerDemo(const std::string &robotName, const std::string &problemFile, const std::string &plannerName="RRTConnect")
Initialize with a robot type and JSON problem file.
std::vector< PlanningResult > benchmarkProblem(const std::string &problemName, unsigned int numTrials=1, double timeoutSeconds=5.0)
Run a benchmark on a specific problem.
This namespace contains sampling based planning routines shared by both planning under geometric cons...
PlannerTerminationCondition timedPlannerTerminationCondition(double duration)
Return a termination condition that will become true duration seconds in the future (wall-time).
This namespace contains code that is specific to planning under geometric constraints.
Results from a single planning trial.
@ EXACT_SOLUTION
The planner found an exact solution.
@ APPROXIMATE_SOLUTION
The planner found an approximate solution.