ompl::base::StateStoragePtr ompl_interface::ConstraintsLibrary::constructConstraintApproximation( const ModelBasedPlanningContextPtr& pcontext, const moveit_msgs::Constraints& constr_sampling, const moveit_msgs::Constraints& constr_hard, const ConstraintApproximationConstructionOptions& options, ConstraintApproximationConstructionResults& result) { // state storage structure ConstraintApproximationStateStorage* cass = new ConstraintApproximationStateStorage(pcontext->getOMPLStateSpace()); ob::StateStoragePtr sstor(cass); // construct a sampler for the sampling constraints kinematic_constraints::KinematicConstraintSet kset(pcontext->getRobotModel()); robot_state::Transforms no_transforms(pcontext->getRobotModel()->getModelFrame()); kset.add(constr_hard, no_transforms); const robot_state::RobotState& default_state = pcontext->getCompleteInitialRobotState(); unsigned int attempts = 0; double bounds_val = std::numeric_limits<double>::max() / 2.0 - 1.0; pcontext->getOMPLStateSpace()->setPlanningVolume(-bounds_val, bounds_val, -bounds_val, bounds_val, -bounds_val, bounds_val); pcontext->getOMPLStateSpace()->setup(); // construct the constrained states robot_state::RobotState robot_state(default_state); const constraint_samplers::ConstraintSamplerManagerPtr& csmng = pcontext->getConstraintSamplerManager(); ConstrainedSampler* csmp = nullptr; if (csmng) { constraint_samplers::ConstraintSamplerPtr cs = csmng->selectSampler(pcontext->getPlanningScene(), pcontext->getJointModelGroup()->getName(), constr_sampling); if (cs) csmp = new ConstrainedSampler(pcontext.get(), cs); } ob::StateSamplerPtr ss(csmp ? ob::StateSamplerPtr(csmp) : pcontext->getOMPLStateSpace()->allocDefaultStateSampler()); ompl::base::ScopedState<> temp(pcontext->getOMPLStateSpace()); int done = -1; bool slow_warn = false; ompl::time::point start = ompl::time::now(); while (sstor->size() < options.samples) { ++attempts; int done_now = 100 * sstor->size() / options.samples; if (done != done_now) { done = done_now; ROS_INFO_NAMED("constraints_library", "%d%% complete (kept %0.1lf%% sampled states)", done, 100.0 * (double)sstor->size() / (double)attempts); } if (!slow_warn && attempts > 10 && attempts > sstor->size() * 100) { slow_warn = true; ROS_WARN_NAMED("constraints_library", "Computation of valid state database is very slow..."); } if (attempts > options.samples && sstor->size() == 0) { ROS_ERROR_NAMED("constraints_library", "Unable to generate any samples"); break; } ss->sampleUniform(temp.get()); pcontext->getOMPLStateSpace()->copyToRobotState(robot_state, temp.get()); if (kset.decide(robot_state).satisfied) { if (sstor->size() < options.samples) { temp->as<ModelBasedStateSpace::StateType>()->tag = sstor->size(); sstor->addState(temp.get()); } } } result.state_sampling_time = ompl::time::seconds(ompl::time::now() - start); ROS_INFO_NAMED("constraints_library", "Generated %u states in %lf seconds", (unsigned int)sstor->size(), result.state_sampling_time); if (csmp) { result.sampling_success_rate = csmp->getConstrainedSamplingRate(); ROS_INFO_NAMED("constraints_library", "Constrained sampling rate: %lf", result.sampling_success_rate); } result.milestones = sstor->size(); if (options.edges_per_sample > 0) { ROS_INFO_NAMED("constraints_library", "Computing graph connections (max %u edges per sample) ...", options.edges_per_sample); // construct connexions const ob::StateSpacePtr& space = pcontext->getOMPLSimpleSetup()->getStateSpace(); unsigned int milestones = sstor->size(); std::vector<ob::State*> int_states(options.max_explicit_points, nullptr); pcontext->getOMPLSimpleSetup()->getSpaceInformation()->allocStates(int_states); ompl::time::point start = ompl::time::now(); int good = 0; int done = -1; for (std::size_t j = 0; j < milestones; ++j) { int done_now = 100 * j / milestones; if (done != done_now) { done = done_now; ROS_INFO_NAMED("constraints_library", "%d%% complete", done); } if (cass->getMetadata(j).first.size() >= options.edges_per_sample) continue; const ob::State* sj = sstor->getState(j); for (std::size_t i = j + 1; i < milestones; ++i) { if (cass->getMetadata(i).first.size() >= options.edges_per_sample) continue; double d = space->distance(sstor->getState(i), sj); if (d >= options.max_edge_length) continue; unsigned int isteps = std::min<unsigned int>(options.max_explicit_points, d / options.explicit_points_resolution); double step = 1.0 / (double)isteps; bool ok = true; space->interpolate(sstor->getState(i), sj, step, int_states[0]); for (unsigned int k = 1; k < isteps; ++k) { double this_step = step / (1.0 - (k - 1) * step); space->interpolate(int_states[k - 1], sj, this_step, int_states[k]); pcontext->getOMPLStateSpace()->copyToRobotState(robot_state, int_states[k]); if (!kset.decide(robot_state).satisfied) { ok = false; break; } } if (ok) { cass->getMetadata(i).first.push_back(j); cass->getMetadata(j).first.push_back(i); if (options.explicit_motions) { cass->getMetadata(i).second[j].first = sstor->size(); for (unsigned int k = 0; k < isteps; ++k) { int_states[k]->as<ModelBasedStateSpace::StateType>()->tag = -1; sstor->addState(int_states[k]); } cass->getMetadata(i).second[j].second = sstor->size(); cass->getMetadata(j).second[i] = cass->getMetadata(i).second[j]; } good++; if (cass->getMetadata(j).first.size() >= options.edges_per_sample) break; } } } result.state_connection_time = ompl::time::seconds(ompl::time::now() - start); ROS_INFO_NAMED("constraints_library", "Computed possible connexions in %lf seconds. Added %d connexions", result.state_connection_time, good); pcontext->getOMPLSimpleSetup()->getSpaceInformation()->freeStates(int_states); return sstor; } // TODO(davetcoleman): this function did not originally return a value, causing compiler warnings in ROS Melodic // Update with more intelligent logic as needed ROS_ERROR_NAMED("constraints_library", "No StateStoragePtr found - implement better solution here."); return sstor; }
ompl::base::StateStoragePtr ompl_interface::ConstraintsLibrary::constructConstraintApproximation(const ModelBasedPlanningContextPtr &pcontext, const moveit_msgs::Constraints &constr_sampling, const moveit_msgs::Constraints &constr_hard, const ConstraintStateStorageOrderFn &order, unsigned int samples, unsigned int edges_per_sample, ConstraintApproximationConstructionResults &result) { // state storage structure ConstraintApproximationStateStorage *cass = new ConstraintApproximationStateStorage(pcontext->getOMPLStateSpace()); ob::StateStoragePtr sstor(cass); // construct a sampler for the sampling constraints kinematic_constraints::KinematicConstraintSet kset(pcontext->getRobotModel(), robot_state::TransformsConstPtr(new robot_state::Transforms(pcontext->getRobotModel()->getModelFrame()))); kset.add(constr_hard); const robot_state::RobotState &default_state = pcontext->getCompleteInitialRobotState(); int nthreads = 0; unsigned int attempts = 0; double bounds_val = std::numeric_limits<double>::max() / 2.0 - 1.0; pcontext->getOMPLStateSpace()->setPlanningVolume(-bounds_val, bounds_val, -bounds_val, bounds_val, -bounds_val, bounds_val); pcontext->getOMPLStateSpace()->setup(); // construct the constrained states #pragma omp parallel { #pragma omp master { nthreads = omp_get_num_threads(); } robot_state::RobotState kstate(default_state); const constraint_samplers::ConstraintSamplerManagerPtr &csmng = pcontext->getConstraintSamplerManager(); ConstrainedSampler *csmp = NULL; if (csmng) { constraint_samplers::ConstraintSamplerPtr cs = csmng->selectSampler(pcontext->getPlanningScene(), pcontext->getJointModelGroup()->getName(), constr_sampling); if (cs) csmp = new ConstrainedSampler(pcontext.get(), cs); } ob::StateSamplerPtr ss(csmp ? ob::StateSamplerPtr(csmp) : pcontext->getOMPLStateSpace()->allocDefaultStateSampler()); ompl::base::ScopedState<> temp(pcontext->getOMPLStateSpace()); int done = -1; bool slow_warn = false; ompl::time::point start = ompl::time::now(); while (sstor->size() < samples) { ++attempts; #pragma omp master { int done_now = 100 * sstor->size() / samples; if (done != done_now) { done = done_now; logInform("%d%% complete (kept %0.1lf%% sampled states)", done, 100.0 * (double)sstor->size() / (double)attempts); } if (!slow_warn && attempts > 10 && attempts > sstor->size() * 100) { slow_warn = true; logWarn("Computation of valid state database is very slow..."); } } if (attempts > samples && sstor->size() == 0) { logError("Unable to generate any samples"); break; } ss->sampleUniform(temp.get()); pcontext->getOMPLStateSpace()->copyToRobotState(kstate, temp.get()); if (kset.decide(kstate).satisfied) { #pragma omp critical { if (sstor->size() < samples) { temp->as<ModelBasedStateSpace::StateType>()->tag = sstor->size(); sstor->addState(temp.get()); } } } } #pragma omp master { result.state_sampling_time = ompl::time::seconds(ompl::time::now() - start); logInform("Generated %u states in %lf seconds", (unsigned int)sstor->size(), result.state_sampling_time); if (csmp) { result.sampling_success_rate = csmp->getConstrainedSamplingRate(); logInform("Constrained sampling rate: %lf", result.sampling_success_rate); } } } if (order) { logInform("Sorting states..."); sstor->sort(order); } if (edges_per_sample > 0) { logInform("Computing graph connections (max %u edges per sample) ...", edges_per_sample); ompl::tools::SelfConfig sc(pcontext->getOMPLSimpleSetup().getSpaceInformation()); double range = 0.0; sc.configurePlannerRange(range); // construct connexions const ob::StateSpacePtr &space = pcontext->getOMPLSimpleSetup().getStateSpace(); std::vector<robot_state::RobotState> kstates(nthreads, default_state); const std::vector<const ompl::base::State*> &states = sstor->getStates(); std::vector<ompl::base::ScopedState<> > temps(nthreads, ompl::base::ScopedState<>(space)); ompl::time::point start = ompl::time::now(); int good = 0; int done = -1; #pragma omp parallel for schedule(dynamic) for (std::size_t j = 0 ; j < sstor->size() ; ++j) { int threadid = omp_get_thread_num(); robot_state::RobotState &kstate = kstates[threadid]; robot_state::JointStateGroup *jsg = kstate.getJointStateGroup(pcontext->getJointModelGroup()->getName()); ompl::base::State *temp = temps[threadid].get(); int done_now = 100 * j / sstor->size(); if (done != done_now) { done = done_now; logInform("%d%% complete", done); } for (std::size_t i = j + 1 ; i < sstor->size() ; ++i) { double d = space->distance(states[j], states[i]); if (d > range * 3.0 || d < range / 100.0) continue; space->interpolate(states[j], states[i], 0.5, temp); pcontext->getOMPLStateSpace()->copyToRobotState(kstate, temp); if (kset.decide(kstate).satisfied) { space->interpolate(states[j], states[i], 0.25, temp); pcontext->getOMPLStateSpace()->copyToRobotState(kstate, temp); if (kset.decide(kstate).satisfied) { space->interpolate(states[j], states[i], 0.75, temp); pcontext->getOMPLStateSpace()->copyToRobotState(kstate, temp); if (kset.decide(kstate).satisfied) { #pragma omp critical { cass->getMetadata(i).push_back(j); cass->getMetadata(j).push_back(i); good++; } if (cass->getMetadata(j).size() >= edges_per_sample) break; } } } } } result.state_connection_time = ompl::time::seconds(ompl::time::now() - start); logInform("Computed possible connexions in %lf seconds. Added %d connexions", result.state_connection_time, good); } return sstor; }