00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <moveit/ompl_interface/constraints_library.h>
00038 #include <moveit/ompl_interface/detail/constrained_sampler.h>
00039 #include <moveit/profiler/profiler.h>
00040 #include <ompl/tools/config/SelfConfig.h>
00041 #include <boost/date_time/posix_time/posix_time.hpp>
00042 #include <boost/filesystem.hpp>
00043 #include <fstream>
00044
00045 namespace ompl_interface
00046 {
00047 namespace
00048 {
00049 template <typename T>
00050 void msgToHex(const T& msg, std::string& hex)
00051 {
00052 static const char symbol[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
00053 const size_t serial_size_arg = ros::serialization::serializationLength(msg);
00054
00055 boost::shared_array<uint8_t> buffer_arg(new uint8_t[serial_size_arg]);
00056 ros::serialization::OStream stream_arg(buffer_arg.get(), serial_size_arg);
00057 ros::serialization::serialize(stream_arg, msg);
00058 hex.resize(serial_size_arg * 2);
00059 for (std::size_t i = 0; i < serial_size_arg; ++i)
00060 {
00061 hex[i * 2] = symbol[buffer_arg[i] / 16];
00062 hex[i * 2 + 1] = symbol[buffer_arg[i] % 16];
00063 }
00064 }
00065
00066 template <typename T>
00067 void hexToMsg(const std::string& hex, T& msg)
00068 {
00069 const size_t serial_size_arg = hex.length() / 2;
00070 boost::shared_array<uint8_t> buffer_arg(new uint8_t[serial_size_arg]);
00071 for (std::size_t i = 0; i < serial_size_arg; ++i)
00072 {
00073 buffer_arg[i] = (hex[i * 2] <= '9' ? (hex[i * 2] - '0') : (hex[i * 2] - 'A' + 10)) * 16 +
00074 (hex[i * 2 + 1] <= '9' ? (hex[i * 2 + 1] - '0') : (hex[i * 2 + 1] - 'A' + 10));
00075 }
00076 ros::serialization::IStream stream_arg(buffer_arg.get(), serial_size_arg);
00077 ros::serialization::deserialize(stream_arg, msg);
00078 }
00079 }
00080
00081 class ConstraintApproximationStateSampler : public ob::StateSampler
00082 {
00083 public:
00084 ConstraintApproximationStateSampler(const ob::StateSpace* space,
00085 const ConstraintApproximationStateStorage* state_storage, std::size_t milestones)
00086 : ob::StateSampler(space), state_storage_(state_storage)
00087 {
00088 max_index_ = milestones - 1;
00089 inv_dim_ = space->getDimension() > 0 ? 1.0 / (double)space->getDimension() : 1.0;
00090 }
00091
00092 virtual void sampleUniform(ob::State* state)
00093 {
00094 space_->copyState(state, state_storage_->getState(rng_.uniformInt(0, max_index_)));
00095 }
00096
00097 virtual void sampleUniformNear(ob::State* state, const ob::State* near, const double distance)
00098 {
00099 int index = -1;
00100 int tag = near->as<ModelBasedStateSpace::StateType>()->tag;
00101
00102 if (tag >= 0)
00103 {
00104 const ConstrainedStateMetadata& md = state_storage_->getMetadata(tag);
00105 if (!md.first.empty())
00106 {
00107 std::size_t matt = md.first.size() / 3;
00108 std::size_t att = 0;
00109 do
00110 {
00111 index = md.first[rng_.uniformInt(0, md.first.size() - 1)];
00112 } while (dirty_.find(index) != dirty_.end() && ++att < matt);
00113 if (att >= matt)
00114 index = -1;
00115 else
00116 dirty_.insert(index);
00117 }
00118 }
00119 if (index < 0)
00120 index = rng_.uniformInt(0, max_index_);
00121
00122 double dist = space_->distance(near, state_storage_->getState(index));
00123
00124 if (dist > distance)
00125 {
00126 double d = pow(rng_.uniform01(), inv_dim_) * distance;
00127 space_->interpolate(near, state_storage_->getState(index), d / dist, state);
00128 }
00129 else
00130 space_->copyState(state, state_storage_->getState(index));
00131 }
00132
00133 virtual void sampleGaussian(ob::State* state, const ob::State* mean, const double stdDev)
00134 {
00135 sampleUniformNear(state, mean, rng_.gaussian(0.0, stdDev));
00136 }
00137
00138 protected:
00140 const ConstraintApproximationStateStorage* state_storage_;
00141 std::set<std::size_t> dirty_;
00142 unsigned int max_index_;
00143 double inv_dim_;
00144 };
00145
00146 bool interpolateUsingStoredStates(const ConstraintApproximationStateStorage* state_storage, const ob::State* from,
00147 const ob::State* to, const double t, ob::State* state)
00148 {
00149 int tag_from = from->as<ModelBasedStateSpace::StateType>()->tag;
00150 int tag_to = to->as<ModelBasedStateSpace::StateType>()->tag;
00151
00152 if (tag_from < 0 || tag_to < 0)
00153 return false;
00154
00155 if (tag_from == tag_to)
00156 state_storage->getStateSpace()->copyState(state, to);
00157 else
00158 {
00159 const ConstrainedStateMetadata& md = state_storage->getMetadata(tag_from);
00160
00161 std::map<std::size_t, std::pair<std::size_t, std::size_t> >::const_iterator it = md.second.find(tag_to);
00162 if (it == md.second.end())
00163 return false;
00164 const std::pair<std::size_t, std::size_t>& istates = it->second;
00165 std::size_t index = (std::size_t)((istates.second - istates.first + 2) * t + 0.5);
00166
00167 if (index == 0)
00168 state_storage->getStateSpace()->copyState(state, from);
00169 else
00170 {
00171 --index;
00172 if (index >= istates.second - istates.first)
00173 state_storage->getStateSpace()->copyState(state, to);
00174 else
00175 state_storage->getStateSpace()->copyState(state, state_storage->getState(istates.first + index));
00176 }
00177 }
00178 return true;
00179 }
00180
00181 ompl_interface::InterpolationFunction ompl_interface::ConstraintApproximation::getInterpolationFunction() const
00182 {
00183 if (explicit_motions_ && milestones_ > 0 && milestones_ < state_storage_->size())
00184 return boost::bind(&interpolateUsingStoredStates, state_storage_, _1, _2, _3, _4);
00185 return InterpolationFunction();
00186 }
00187
00188 ompl::base::StateSamplerPtr allocConstraintApproximationStateSampler(
00189 const ob::StateSpace* space, const std::vector<int>& expected_signature,
00190 const ConstraintApproximationStateStorage* state_storage, std::size_t milestones)
00191 {
00192 std::vector<int> sig;
00193 space->computeSignature(sig);
00194 if (sig != expected_signature)
00195 return ompl::base::StateSamplerPtr();
00196 else
00197 return ompl::base::StateSamplerPtr(new ConstraintApproximationStateSampler(space, state_storage, milestones));
00198 }
00199 }
00200
00201 ompl_interface::ConstraintApproximation::ConstraintApproximation(
00202 const std::string& group, const std::string& state_space_parameterization, bool explicit_motions,
00203 const moveit_msgs::Constraints& msg, const std::string& filename, const ompl::base::StateStoragePtr& storage,
00204 std::size_t milestones)
00205 : group_(group)
00206 , state_space_parameterization_(state_space_parameterization)
00207 , explicit_motions_(explicit_motions)
00208 , constraint_msg_(msg)
00209 , ompldb_filename_(filename)
00210 , state_storage_ptr_(storage)
00211 , milestones_(milestones)
00212 {
00213 state_storage_ = static_cast<ConstraintApproximationStateStorage*>(state_storage_ptr_.get());
00214 state_storage_->getStateSpace()->computeSignature(space_signature_);
00215 if (milestones_ == 0)
00216 milestones_ = state_storage_->size();
00217 }
00218
00219 ompl::base::StateSamplerAllocator
00220 ompl_interface::ConstraintApproximation::getStateSamplerAllocator(const moveit_msgs::Constraints& msg) const
00221 {
00222 if (state_storage_->size() == 0)
00223 return ompl::base::StateSamplerAllocator();
00224 return boost::bind(&allocConstraintApproximationStateSampler, _1, space_signature_, state_storage_, milestones_);
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 void ompl_interface::ConstraintsLibrary::loadConstraintApproximations(const std::string& path)
00268 {
00269 constraint_approximations_.clear();
00270 std::ifstream fin((path + "/manifest").c_str());
00271 if (!fin.good())
00272 {
00273 logWarn("Manifest not found in folder '%s'. Not loading constraint approximations.", path.c_str());
00274 return;
00275 }
00276
00277 logInform("Loading constrained space approximations from '%s'...", path.c_str());
00278
00279 while (fin.good() && !fin.eof())
00280 {
00281 std::string group, state_space_parameterization, serialization, filename;
00282 bool explicit_motions;
00283 unsigned int milestones;
00284 fin >> group;
00285 if (fin.eof())
00286 break;
00287 fin >> state_space_parameterization;
00288 if (fin.eof())
00289 break;
00290 fin >> explicit_motions;
00291 if (fin.eof())
00292 break;
00293 fin >> milestones;
00294 if (fin.eof())
00295 break;
00296 fin >> serialization;
00297 if (fin.eof())
00298 break;
00299 fin >> filename;
00300 logInform("Loading constraint approximation of type '%s' for group '%s' from '%s'...",
00301 state_space_parameterization.c_str(), group.c_str(), filename.c_str());
00302 const ModelBasedPlanningContextPtr& pc = context_manager_.getPlanningContext(group, state_space_parameterization);
00303 if (pc)
00304 {
00305 moveit_msgs::Constraints msg;
00306 hexToMsg(serialization, msg);
00307 ConstraintApproximationStateStorage* cass =
00308 new ConstraintApproximationStateStorage(pc->getOMPLSimpleSetup()->getStateSpace());
00309 cass->load((path + "/" + filename).c_str());
00310 ConstraintApproximationPtr cap(new ConstraintApproximation(group, state_space_parameterization, explicit_motions,
00311 msg, filename, ompl::base::StateStoragePtr(cass),
00312 milestones));
00313 if (constraint_approximations_.find(cap->getName()) != constraint_approximations_.end())
00314 logWarn("Overwriting constraint approximation named '%s'", cap->getName().c_str());
00315 constraint_approximations_[cap->getName()] = cap;
00316 std::size_t sum = 0;
00317 for (std::size_t i = 0; i < cass->size(); ++i)
00318 sum += cass->getMetadata(i).first.size();
00319 logInform("Loaded %lu states (%lu milestones) and %lu connections (%0.1lf per state) for constraint named '%s'%s",
00320 cass->size(), cap->getMilestoneCount(), sum, (double)sum / (double)cap->getMilestoneCount(),
00321 msg.name.c_str(), explicit_motions ? ". Explicit motions included." : "");
00322 }
00323 }
00324 logInform("Done loading constrained space approximations.");
00325 }
00326
00327 void ompl_interface::ConstraintsLibrary::saveConstraintApproximations(const std::string& path)
00328 {
00329 logInform("Saving %u constrained space approximations to '%s'", (unsigned int)constraint_approximations_.size(),
00330 path.c_str());
00331 try
00332 {
00333 boost::filesystem::create_directories(path);
00334 }
00335 catch (...)
00336 {
00337 }
00338
00339 std::ofstream fout((path + "/manifest").c_str());
00340 if (fout.good())
00341 for (std::map<std::string, ConstraintApproximationPtr>::const_iterator it = constraint_approximations_.begin();
00342 it != constraint_approximations_.end(); ++it)
00343 {
00344 fout << it->second->getGroup() << std::endl;
00345 fout << it->second->getStateSpaceParameterization() << std::endl;
00346 fout << it->second->hasExplicitMotions() << std::endl;
00347 fout << it->second->getMilestoneCount() << std::endl;
00348 std::string serialization;
00349 msgToHex(it->second->getConstraintsMsg(), serialization);
00350 fout << serialization << std::endl;
00351 fout << it->second->getFilename() << std::endl;
00352 if (it->second->getStateStorage())
00353 it->second->getStateStorage()->store((path + "/" + it->second->getFilename()).c_str());
00354 }
00355 else
00356 logError("Unable to save constraint approximation to '%s'", path.c_str());
00357 fout.close();
00358 }
00359
00360 void ompl_interface::ConstraintsLibrary::clearConstraintApproximations()
00361 {
00362 constraint_approximations_.clear();
00363 }
00364
00365 void ompl_interface::ConstraintsLibrary::printConstraintApproximations(std::ostream& out) const
00366 {
00367 for (std::map<std::string, ConstraintApproximationPtr>::const_iterator it = constraint_approximations_.begin();
00368 it != constraint_approximations_.end(); ++it)
00369 {
00370 out << it->second->getGroup() << std::endl;
00371 out << it->second->getStateSpaceParameterization() << std::endl;
00372 out << it->second->hasExplicitMotions() << std::endl;
00373 out << it->second->getMilestoneCount() << std::endl;
00374 out << it->second->getFilename() << std::endl;
00375 out << it->second->getConstraintsMsg() << std::endl;
00376 }
00377 }
00378
00379 const ompl_interface::ConstraintApproximationPtr&
00380 ompl_interface::ConstraintsLibrary::getConstraintApproximation(const moveit_msgs::Constraints& msg) const
00381 {
00382 std::map<std::string, ConstraintApproximationPtr>::const_iterator it = constraint_approximations_.find(msg.name);
00383 if (it != constraint_approximations_.end())
00384 return it->second;
00385
00386 static ConstraintApproximationPtr empty;
00387 return empty;
00388 }
00389
00390 ompl_interface::ConstraintApproximationConstructionResults
00391 ompl_interface::ConstraintsLibrary::addConstraintApproximation(
00392 const moveit_msgs::Constraints& constr, const std::string& group,
00393 const planning_scene::PlanningSceneConstPtr& scene, const ConstraintApproximationConstructionOptions& options)
00394 {
00395 return addConstraintApproximation(constr, constr, group, scene, options);
00396 }
00397
00398 ompl_interface::ConstraintApproximationConstructionResults
00399 ompl_interface::ConstraintsLibrary::addConstraintApproximation(
00400 const moveit_msgs::Constraints& constr_sampling, const moveit_msgs::Constraints& constr_hard,
00401 const std::string& group, const planning_scene::PlanningSceneConstPtr& scene,
00402 const ConstraintApproximationConstructionOptions& options)
00403 {
00404 ConstraintApproximationConstructionResults res;
00405 ModelBasedPlanningContextPtr pc = context_manager_.getPlanningContext(group, options.state_space_parameterization);
00406 if (pc)
00407 {
00408 pc->clear();
00409 pc->setPlanningScene(scene);
00410 pc->setCompleteInitialState(scene->getCurrentState());
00411
00412 ros::WallTime start = ros::WallTime::now();
00413 ompl::base::StateStoragePtr ss = constructConstraintApproximation(pc, constr_sampling, constr_hard, options, res);
00414 logInform("Spent %lf seconds constructing the database", (ros::WallTime::now() - start).toSec());
00415 if (ss)
00416 {
00417 ConstraintApproximationPtr ca(new ConstraintApproximation(
00418 group, options.state_space_parameterization, options.explicit_motions, constr_hard,
00419 group + "_" + boost::posix_time::to_iso_extended_string(boost::posix_time::microsec_clock::universal_time()) +
00420 ".ompldb",
00421 ss, res.milestones));
00422 if (constraint_approximations_.find(ca->getName()) != constraint_approximations_.end())
00423 logWarn("Overwriting constraint approximation named '%s'", ca->getName().c_str());
00424 constraint_approximations_[ca->getName()] = ca;
00425 res.approx = ca;
00426 }
00427 else
00428 logError("Unable to construct constraint approximation for group '%s'", group.c_str());
00429 }
00430 return res;
00431 }
00432
00433 ompl::base::StateStoragePtr ompl_interface::ConstraintsLibrary::constructConstraintApproximation(
00434 const ModelBasedPlanningContextPtr& pcontext, const moveit_msgs::Constraints& constr_sampling,
00435 const moveit_msgs::Constraints& constr_hard, const ConstraintApproximationConstructionOptions& options,
00436 ConstraintApproximationConstructionResults& result)
00437 {
00438
00439 ConstraintApproximationStateStorage* cass = new ConstraintApproximationStateStorage(pcontext->getOMPLStateSpace());
00440 ob::StateStoragePtr sstor(cass);
00441
00442
00443 kinematic_constraints::KinematicConstraintSet kset(pcontext->getRobotModel());
00444 robot_state::Transforms no_transforms(pcontext->getRobotModel()->getModelFrame());
00445 kset.add(constr_hard, no_transforms);
00446
00447 const robot_state::RobotState& default_state = pcontext->getCompleteInitialRobotState();
00448
00449 unsigned int attempts = 0;
00450
00451 double bounds_val = std::numeric_limits<double>::max() / 2.0 - 1.0;
00452 pcontext->getOMPLStateSpace()->setPlanningVolume(-bounds_val, bounds_val, -bounds_val, bounds_val, -bounds_val,
00453 bounds_val);
00454 pcontext->getOMPLStateSpace()->setup();
00455
00456
00457
00458 robot_state::RobotState kstate(default_state);
00459 const constraint_samplers::ConstraintSamplerManagerPtr& csmng = pcontext->getConstraintSamplerManager();
00460 ConstrainedSampler* csmp = NULL;
00461 if (csmng)
00462 {
00463 constraint_samplers::ConstraintSamplerPtr cs =
00464 csmng->selectSampler(pcontext->getPlanningScene(), pcontext->getJointModelGroup()->getName(), constr_sampling);
00465 if (cs)
00466 csmp = new ConstrainedSampler(pcontext.get(), cs);
00467 }
00468
00469 ob::StateSamplerPtr ss(csmp ? ob::StateSamplerPtr(csmp) : pcontext->getOMPLStateSpace()->allocDefaultStateSampler());
00470
00471 ompl::base::ScopedState<> temp(pcontext->getOMPLStateSpace());
00472 int done = -1;
00473 bool slow_warn = false;
00474 ompl::time::point start = ompl::time::now();
00475 while (sstor->size() < options.samples)
00476 {
00477 ++attempts;
00478 int done_now = 100 * sstor->size() / options.samples;
00479 if (done != done_now)
00480 {
00481 done = done_now;
00482 logInform("%d%% complete (kept %0.1lf%% sampled states)", done, 100.0 * (double)sstor->size() / (double)attempts);
00483 }
00484
00485 if (!slow_warn && attempts > 10 && attempts > sstor->size() * 100)
00486 {
00487 slow_warn = true;
00488 logWarn("Computation of valid state database is very slow...");
00489 }
00490
00491 if (attempts > options.samples && sstor->size() == 0)
00492 {
00493 logError("Unable to generate any samples");
00494 break;
00495 }
00496
00497 ss->sampleUniform(temp.get());
00498 pcontext->getOMPLStateSpace()->copyToRobotState(kstate, temp.get());
00499 if (kset.decide(kstate).satisfied)
00500 {
00501 if (sstor->size() < options.samples)
00502 {
00503 temp->as<ModelBasedStateSpace::StateType>()->tag = sstor->size();
00504 sstor->addState(temp.get());
00505 }
00506 }
00507 }
00508
00509 result.state_sampling_time = ompl::time::seconds(ompl::time::now() - start);
00510 logInform("Generated %u states in %lf seconds", (unsigned int)sstor->size(), result.state_sampling_time);
00511 if (csmp)
00512 {
00513 result.sampling_success_rate = csmp->getConstrainedSamplingRate();
00514 logInform("Constrained sampling rate: %lf", result.sampling_success_rate);
00515 }
00516
00517 result.milestones = sstor->size();
00518 if (options.edges_per_sample > 0)
00519 {
00520 logInform("Computing graph connections (max %u edges per sample) ...", options.edges_per_sample);
00521
00522
00523 const ob::StateSpacePtr& space = pcontext->getOMPLSimpleSetup()->getStateSpace();
00524 unsigned int milestones = sstor->size();
00525 std::vector<ob::State*> int_states(options.max_explicit_points, NULL);
00526 pcontext->getOMPLSimpleSetup()->getSpaceInformation()->allocStates(int_states);
00527
00528 ompl::time::point start = ompl::time::now();
00529 int good = 0;
00530 int done = -1;
00531
00532 for (std::size_t j = 0; j < milestones; ++j)
00533 {
00534 int done_now = 100 * j / milestones;
00535 if (done != done_now)
00536 {
00537 done = done_now;
00538 logInform("%d%% complete", done);
00539 }
00540 if (cass->getMetadata(j).first.size() >= options.edges_per_sample)
00541 continue;
00542
00543 const ob::State* sj = sstor->getState(j);
00544
00545 for (std::size_t i = j + 1; i < milestones; ++i)
00546 {
00547 if (cass->getMetadata(i).first.size() >= options.edges_per_sample)
00548 continue;
00549 double d = space->distance(sstor->getState(i), sj);
00550 if (d >= options.max_edge_length)
00551 continue;
00552 unsigned int isteps =
00553 std::min<unsigned int>(options.max_explicit_points, d / options.explicit_points_resolution);
00554 double step = 1.0 / (double)isteps;
00555 double remain = 1.0;
00556 bool ok = true;
00557 space->interpolate(sstor->getState(i), sj, step, int_states[0]);
00558 for (unsigned int k = 1; k < isteps; ++k)
00559 {
00560 double this_step = step / (1.0 - (k - 1) * step);
00561 space->interpolate(int_states[k - 1], sj, this_step, int_states[k]);
00562 pcontext->getOMPLStateSpace()->copyToRobotState(kstate, int_states[k]);
00563 if (!kset.decide(kstate).satisfied)
00564 {
00565 ok = false;
00566 break;
00567 }
00568 }
00569
00570 if (ok)
00571 {
00572 cass->getMetadata(i).first.push_back(j);
00573 cass->getMetadata(j).first.push_back(i);
00574
00575 if (options.explicit_motions)
00576 {
00577 cass->getMetadata(i).second[j].first = sstor->size();
00578 for (unsigned int k = 0; k < isteps; ++k)
00579 {
00580 int_states[k]->as<ModelBasedStateSpace::StateType>()->tag = -1;
00581 sstor->addState(int_states[k]);
00582 }
00583 cass->getMetadata(i).second[j].second = sstor->size();
00584 cass->getMetadata(j).second[i] = cass->getMetadata(i).second[j];
00585 }
00586
00587 good++;
00588 if (cass->getMetadata(j).first.size() >= options.edges_per_sample)
00589 break;
00590 }
00591 }
00592 }
00593
00594 result.state_connection_time = ompl::time::seconds(ompl::time::now() - start);
00595 logInform("Computed possible connexions in %lf seconds. Added %d connexions", result.state_connection_time, good);
00596 pcontext->getOMPLSimpleSetup()->getSpaceInformation()->freeStates(int_states);
00597
00598 return sstor;
00599 }
00600 }