-
Steve Tonneau authoredSteve Tonneau authored
rbprmbuilder.impl.cc 27.13 KiB
// Copyright (c) 2012 CNRS
// Author: Florent Lamiraux, Joseph Mirabel
//
// This file is part of hpp-manipulation-corba.
// hpp-manipulation-corba is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-manipulation-corba is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-manipulation-corba. If not, see
// <http://www.gnu.org/licenses/>.
//#include <hpp/fcl/math/transform.h>
#include <hpp/util/debug.hh>
#include "rbprmbuilder.impl.hh"
#include "hpp/rbprm/rbprm-device.hh"
#include "hpp/rbprm/rbprm-validation.hh"
#include "hpp/rbprm/rbprm-path-interpolation.hh"
#include "hpp/rbprm/stability/stability.hh"
#include "hpp/model/urdf/util.hh"
#include <fstream>
namespace hpp {
namespace rbprm {
namespace impl {
RbprmBuilder::RbprmBuilder ()
: POA_hpp::corbaserver::rbprm::RbprmBuilder()
, romLoaded_(false)
, fullBodyLoaded_(false)
, bindShooter_()
{
// NOTHING
}
void RbprmBuilder::loadRobotRomModel(const char* robotName,
const char* rootJointType,
const char* packageName,
const char* modelName,
const char* urdfSuffix,
const char* srdfSuffix) throw (hpp::Error)
{
try
{
hpp::model::DevicePtr_t romDevice = model::Device::create (robotName);
romDevices_.insert(std::make_pair(robotName, romDevice));
hpp::model::urdf::loadRobotModel (romDevice,
std::string (rootJointType),
std::string (packageName),
std::string (modelName),
std::string (urdfSuffix),
std::string (srdfSuffix));
}
catch (const std::exception& exc)
{
hppDout (error, exc.what ());
throw hpp::Error (exc.what ());
}
romLoaded_ = true;
}
void RbprmBuilder::loadRobotCompleteModel(const char* robotName,
const char* rootJointType,
const char* packageName,
const char* modelName,
const char* urdfSuffix,
const char* srdfSuffix) throw (hpp::Error)
{
if(!romLoaded_)
{
std::string err("Rom must be loaded before loading complete model") ;
hppDout (error, err );
throw hpp::Error(err.c_str());
}
try
{
hpp::model::RbPrmDevicePtr_t device = hpp::model::RbPrmDevice::create (robotName, romDevices_);
hpp::model::urdf::loadRobotModel (device,
std::string (rootJointType),
std::string (packageName),
std::string (modelName),
std::string (urdfSuffix),
std::string (srdfSuffix));
// Add device to the planner
problemSolver_->robot (device);
problemSolver_->robot ()->controlComputation
(model::Device::JOINT_POSITION);
}
catch (const std::exception& exc)
{
hppDout (error, exc.what ());
throw hpp::Error (exc.what ());
}
}
void RbprmBuilder::loadFullBodyRobot(const char* robotName,
const char* rootJointType,
const char* packageName,
const char* modelName,
const char* urdfSuffix,
const char* srdfSuffix) throw (hpp::Error)
{
try
{
model::DevicePtr_t device = model::Device::create (robotName);
hpp::model::urdf::loadRobotModel (device,
std::string (rootJointType),
std::string (packageName),
std::string (modelName),
std::string (urdfSuffix),
std::string (srdfSuffix));
fullBody_ = rbprm::RbPrmFullBody::create(device);
problemSolver_->pathValidationType ("Discretized",0.05); // reset to avoid conflict with rbprm path
problemSolver_->robot (fullBody_->device_);
problemSolver_->resetProblem();
problemSolver_->robot ()->controlComputation
(model::Device::JOINT_POSITION);
}
catch (const std::exception& exc)
{
hppDout (error, exc.what ());
throw hpp::Error (exc.what ());
}
fullBodyLoaded_ = true;
}
hpp::floatSeq* RbprmBuilder::getSampleConfig(const char* limb, unsigned short sampleId) throw (hpp::Error)
{
if(!fullBodyLoaded_)
throw Error ("No full body robot was loaded");
const T_Limb& limbs = fullBody_->GetLimbs();
T_Limb::const_iterator lit = limbs.find(std::string(limb));
if(lit == limbs.end())
{
std::string err("No limb " + std::string(limb) + "was defined for robot" + fullBody_->device_->name());
throw Error (err.c_str());
}
const RbPrmLimbPtr_t& limbPtr = lit->second;
hpp::floatSeq *dofArray;
Eigen::VectorXd config = fullBody_->device_->currentConfiguration ();
if(sampleId > limbPtr->sampleContainer_.samples_.size())
{
std::string err("Limb " + std::string(limb) + "does not have samples.");
throw Error (err.c_str());
}
const sampling::Sample& sample = limbPtr->sampleContainer_.samples_[sampleId];
config.segment(sample.startRank_, sample.length_) = sample.configuration_;
dofArray = new hpp::floatSeq();
dofArray->length(_CORBA_ULong(config.rows()));
for(std::size_t i=0; i< _CORBA_ULong(config.rows()); i++)
(*dofArray)[(_CORBA_ULong)i] = config [i];
return dofArray;
}
hpp::floatSeq* RbprmBuilder::getSamplePosition(const char* limb, unsigned short sampleId) throw (hpp::Error)
{
if(!fullBodyLoaded_)
throw Error ("No full body robot was loaded");
const T_Limb& limbs = fullBody_->GetLimbs();
T_Limb::const_iterator lit = limbs.find(std::string(limb));
if(lit == limbs.end())
{
std::string err("No limb " + std::string(limb) + "was defined for robot" + fullBody_->device_->name());
throw Error (err.c_str());
}
const RbPrmLimbPtr_t& limbPtr = lit->second;
hpp::floatSeq *dofArray;
if(sampleId > limbPtr->sampleContainer_.samples_.size())
{
std::string err("Limb " + std::string(limb) + "does not have samples.");
throw Error (err.c_str());
}
const sampling::Sample& sample = limbPtr->sampleContainer_.samples_[sampleId];
const fcl::Vec3f& position = sample.effectorPosition_;
dofArray = new hpp::floatSeq();
dofArray->length(_CORBA_ULong(3));
for(std::size_t i=0; i< 3; i++)
(*dofArray)[(_CORBA_ULong)i] = position [i];
return dofArray;
}
model::Configuration_t dofArrayToConfig (const model::DevicePtr_t& robot,
const hpp::floatSeq& dofArray)
{
std::size_t configDim = (std::size_t)dofArray.length();
// Get robot
if (!robot) {
throw hpp::Error ("No robot in problem solver.");
}
std::size_t deviceDim = robot->configSize ();
// Fill dof vector with dof array.
model::Configuration_t config; config.resize (configDim);
for (std::size_t iDof = 0; iDof < configDim; iDof++) {
config [iDof] = dofArray[iDof];
}
// fill the vector by zero
hppDout (info, "config dimension: " <<configDim
<<", deviceDim "<<deviceDim);
if(configDim != deviceDim){
throw hpp::Error ("dofVector Does not match");
}
return config;
}
std::vector<model::Configuration_t> doubleDofArrayToConfig (const model::DevicePtr_t& robot,
const hpp::floatSeqSeq& doubleDofArray)
{
std::size_t configsDim = (std::size_t)doubleDofArray.length();
std::vector<model::Configuration_t> res;
for (std::size_t iConfig = 0; iConfig < configsDim; iConfig++)
{
res.push_back(dofArrayToConfig(robot, doubleDofArray[iConfig]));
}
return res;
}
std::vector<std::string> stringConversion(const hpp::Names_t& dofArray)
{
std::vector<std::string> res;
std::size_t dim = (std::size_t)dofArray.length();
for (std::size_t iDof = 0; iDof < dim; iDof++)
{
res.push_back(std::string(dofArray[iDof]));
}
return res;
}
std::vector<double> doubleConversion(const hpp::floatSeq& dofArray)
{
std::vector<double> res;
std::size_t dim = (std::size_t)dofArray.length();
for (std::size_t iDof = 0; iDof < dim; iDof++)
{
res.push_back(dofArray[iDof]);
}
return res;
}
void RbprmBuilder::setFilter(const hpp::Names_t& roms) throw (hpp::Error)
{
bindShooter_.romFilter_ = stringConversion(roms);
}
void RbprmBuilder::setNormalFilter(const char* romName, const hpp::floatSeq& normal, double range) throw (hpp::Error)
{
std::string name(romName);
bindShooter_.normalFilter_.erase(name);
fcl::Vec3f dir;
for(std::size_t i =0; i <3; ++i)
{
dir[i] = normal[i];
}
NormalFilter filter(dir,range);
bindShooter_.normalFilter_.insert(std::make_pair(name,filter));
}
void RbprmBuilder::boundSO3(const hpp::floatSeq& limitszyx) throw (hpp::Error)
{
std::vector<double> limits = doubleConversion(limitszyx);
if(limits.size() !=6)
{
throw Error ("Can not bound SO3, array of 6 double required");
}
bindShooter_.so3Bounds_ = limits;
}
hpp::floatSeq* RbprmBuilder::generateContacts(const hpp::floatSeq& configuration, const hpp::floatSeq& direction) throw (hpp::Error)
{
if(!fullBodyLoaded_)
throw Error ("No full body robot was loaded");
try
{
fcl::Vec3f dir;
for(std::size_t i =0; i <3; ++i)
{
dir[i] = direction[i];
}
model::Configuration_t config = dofArrayToConfig (fullBody_->device_, configuration);
rbprm::State state = rbprm::ComputeContacts(fullBody_,config,
problemSolver_->collisionObstacles(), dir);
hpp::floatSeq* dofArray = new hpp::floatSeq();
dofArray->length(_CORBA_ULong(state.configuration_.rows()));
for(std::size_t i=0; i< _CORBA_ULong(config.rows()); i++)
(*dofArray)[(_CORBA_ULong)i] = state.configuration_ [i];
return dofArray;
} catch (const std::exception& exc) {
throw hpp::Error (exc.what ());
}
}
hpp::floatSeq* RbprmBuilder::getContactSamplesIds(const char* limbname,
const hpp::floatSeq& configuration,
const hpp::floatSeq& direction) throw (hpp::Error)
{
if(!fullBodyLoaded_)
throw Error ("No full body robot was loaded");
try
{
fcl::Vec3f dir;
for(std::size_t i =0; i <3; ++i)
{
dir[i] = direction[i];
}
model::Configuration_t config = dofArrayToConfig (fullBody_->device_, configuration);
model::Configuration_t save = fullBody_->device_->currentConfiguration();
fullBody_->device_->currentConfiguration(config);
sampling::T_OctreeReport finalSet;
rbprm::T_Limb::const_iterator lit = fullBody_->GetLimbs().find(std::string(limbname));
if(lit == fullBody_->GetLimbs().end())
{
throw std::runtime_error ("Impossible to find limb for joint "
+ std::string(limbname) + " to robot; limb not defined.");
}
const RbPrmLimbPtr_t& limb = lit->second;
fcl::Transform3f transform = limb->limb_->robot()->rootJoint()->childJoint(0)->currentTransformation (); // get root transform from configuration
std::vector<sampling::T_OctreeReport> reports(problemSolver_->collisionObstacles().size());
std::size_t i (0);
//#pragma omp parallel for
for(model::ObjectVector_t::const_iterator oit = problemSolver_->collisionObstacles().begin();
oit != problemSolver_->collisionObstacles().end(); ++oit, ++i)
{
sampling::GetCandidates(limb->sampleContainer_, transform, transform, *oit, dir, reports[i]);
}
for(std::vector<sampling::T_OctreeReport>::const_iterator cit = reports.begin();
cit != reports.end(); ++cit)
{
finalSet.insert(cit->begin(), cit->end());
}
hpp::floatSeq* dofArray = new hpp::floatSeq();
dofArray->length(finalSet.size());
sampling::T_OctreeReport::const_iterator candCit = finalSet.begin();
for(std::size_t i=0; i< _CORBA_ULong(finalSet.size()); ++i, ++candCit)
{
(*dofArray)[(_CORBA_ULong)i] = candCit->sample_->id_;
}
fullBody_->device_->currentConfiguration(save);
return dofArray;
} catch (const std::exception& exc) {
throw hpp::Error (exc.what ());
}
}
void RbprmBuilder::addLimb(const char* id, const char* limb, const char* effector, const hpp::floatSeq& offset, const hpp::floatSeq& normal, double x, double y,
unsigned short samples, const char* heuristicName, double resolution, const char *contactType) throw (hpp::Error)
{
if(!fullBodyLoaded_)
throw Error ("No full body robot was loaded");
try
{
fcl::Vec3f off, norm;
for(std::size_t i =0; i <3; ++i)
{
off[i] = offset[i];
norm[i] = normal[i];
}
ContactType cType = hpp::rbprm::_6_DOF;
if(std::string(contactType) == "_3_DOF")
{
cType = hpp::rbprm::_3_DOF;
}
fullBody_->AddLimb(std::string(id), std::string(limb), std::string(effector), off, norm, x, y, problemSolver_->collisionObstacles(), samples,heuristicName,resolution,cType);
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
void SetPositionAndNormal(rbprm::State& state, hpp::rbprm::RbPrmFullBodyPtr_t fullBody, const hpp::floatSeq& configuration, const hpp::Names_t& contactLimbs)
{
core::Configuration_t old = fullBody->device_->currentConfiguration();
model::Configuration_t config = dofArrayToConfig (fullBody->device_, configuration);
fullBody->device_->currentConfiguration(config);
fullBody->device_->computeForwardKinematics();
std::vector<std::string> names = stringConversion(contactLimbs);
for(std::vector<std::string>::const_iterator cit = names.begin(); cit != names.end();++cit)
{
rbprm::T_Limb::const_iterator lit = fullBody->GetLimbs().find(*cit);
if(lit == fullBody->GetLimbs().end())
{
throw std::runtime_error ("Impossible to find limb for joint "
+ (*cit) + " to robot; limb not defined");
}
const core::JointPtr_t joint = fullBody->device_->getJointByName(lit->second->effector_->name());
const fcl::Transform3f& transform = joint->currentTransformation ();
const fcl::Matrix3f& rot = transform.getRotation();
state.contactPositions_[*cit] = transform.getTranslation();
state.contactRotation_[*cit] = rot;
state.contactNormals_[*cit] = fcl::Vec3f(rot(0,2),rot(1,2), rot(2,2));
state.contacts_[*cit] = true;
state.contactOrder_.push(*cit);
}
state.nbContacts = state.contactNormals_.size() ;
state.configuration_ = config;
state.robustness = stability::IsStable(fullBody,state);
state.stable = state.robustness >= 0;
fullBody->device_->currentConfiguration(old);
}
void RbprmBuilder::setStartState(const hpp::floatSeq& configuration, const hpp::Names_t& contactLimbs) throw (hpp::Error)
{
try
{
SetPositionAndNormal(startState_,fullBody_, configuration, contactLimbs);
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
void RbprmBuilder::setEndState(const hpp::floatSeq& configuration, const hpp::Names_t& contactLimbs) throw (hpp::Error)
{
try
{
SetPositionAndNormal(endState_,fullBody_, configuration, contactLimbs);
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
floatSeqSeq* RbprmBuilder::interpolateConfigs(const hpp::floatSeqSeq& configs, double robustnessTreshold) throw (hpp::Error)
{
try
{
if(startState_.configuration_.rows() == 0)
{
throw std::runtime_error ("Start state not initialized, can not interpolate ");
}
if(endState_.configuration_.rows() == 0)
{
throw std::runtime_error ("End state not initialized, can not interpolate ");
}
hpp::rbprm::RbPrmInterpolationPtr_t interpolator = rbprm::RbPrmInterpolation::create(fullBody_,startState_,endState_);
std::vector<model::Configuration_t> configurations = doubleDofArrayToConfig(fullBody_->device_, configs);
lastStatesComputed_ = interpolator->Interpolate(problemSolver_->collisionObstacles(),configurations,robustnessTreshold);
hpp::floatSeqSeq *res;
res = new hpp::floatSeqSeq ();
res->length (lastStatesComputed_.size ());
std::size_t i=0;
std::size_t id = 0;
for(std::vector<State>::const_iterator cit = lastStatesComputed_.begin(); cit != lastStatesComputed_.end(); ++cit, ++id)
{
std::cout << "ID " << id;
cit->print();
const core::Configuration_t config = cit->configuration_;
_CORBA_ULong size = (_CORBA_ULong) config.size ();
double* dofArray = hpp::floatSeq::allocbuf(size);
hpp::floatSeq floats (size, size, dofArray, true);
//convert the config in dofseq
for (model::size_type j=0 ; j < config.size() ; ++j) {
dofArray[j] = config [j];
}
(*res) [i] = floats;
++i;
}
return res;
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
floatSeqSeq* RbprmBuilder::interpolate(double timestep, double path, double robustnessTreshold) throw (hpp::Error)
{
try
{
int pathId = int(path);
if(startState_.configuration_.rows() == 0)
{
throw std::runtime_error ("Start state not initialized, can not interpolate ");
}
if(endState_.configuration_.rows() == 0)
{
throw std::runtime_error ("End state not initialized, can not interpolate ");
}
if(problemSolver_->paths().size() <= pathId)
{
throw std::runtime_error ("No path computed, cannot interpolate ");
}
hpp::rbprm::RbPrmInterpolationPtr_t interpolator = rbprm::RbPrmInterpolation::create(fullBody_,startState_,endState_,problemSolver_->paths()[pathId]);
lastStatesComputed_ = interpolator->Interpolate(problemSolver_->collisionObstacles(),timestep,robustnessTreshold);
hpp::floatSeqSeq *res;
res = new hpp::floatSeqSeq ();
res->length (lastStatesComputed_.size ());
std::size_t i=0;
std::size_t id = 0;
for(std::vector<State>::const_iterator cit = lastStatesComputed_.begin(); cit != lastStatesComputed_.end(); ++cit, ++id)
{
std::cout << "ID " << id;
cit->print();
const core::Configuration_t config = cit->configuration_;
_CORBA_ULong size = (_CORBA_ULong) config.size ();
double* dofArray = hpp::floatSeq::allocbuf(size);
hpp::floatSeq floats (size, size, dofArray, true);
//convert the config in dofseq
for (model::size_type j=0 ; j < config.size() ; ++j) {
dofArray[j] = config [j];
}
(*res) [i] = floats;
++i;
}
return res;
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
void RbprmBuilder::saveComputedStates(const char* outfilename) throw (hpp::Error)
{
std::stringstream ss;
ss << lastStatesComputed_.size()-2 << "\n";
std::vector<rbprm::State>::iterator cit = lastStatesComputed_.begin()+1;
int i = 0;
ss << i++ << " ";
cit->print(ss);
for(std::vector<rbprm::State>::iterator cit2 = lastStatesComputed_.begin()+2;
cit2 != lastStatesComputed_.end()-1; ++cit2, ++cit, ++i)
{
cit2->robustness = stability::IsStable(this->fullBody_, *cit2);
ss << i<< " ";
cit2->print(ss,*cit);
}
std::ofstream outfile;
outfile.open(outfilename);
if (outfile.is_open())
{
outfile << ss.rdbuf();
outfile.close();
}
else
{
std::string error("Can not open outfile " + std::string(outfilename));
throw Error(error.c_str());
}
}
hpp::floatSeqSeq* RbprmBuilder::GetOctreeBoxes(const char* limbName, const hpp::floatSeq& configuration) throw (hpp::Error)
{
try
{
model::Configuration_t config = dofArrayToConfig (fullBody_->device_, configuration);
model::Configuration_t save = fullBody_->device_->currentConfiguration();
fullBody_->device_->currentConfiguration(config);
fullBody_->device_->computeForwardKinematics();
const std::map<std::size_t, fcl::CollisionObject*>& boxes =
fullBody_->GetLimbs().at(std::string(limbName))->sampleContainer_.boxes_;
const double resolution = fullBody_->GetLimbs().at(std::string(limbName))->sampleContainer_.resolution_;
std::size_t i =0;
hpp::floatSeqSeq *res;
res = new hpp::floatSeqSeq ();
res->length (boxes.size ());
for(std::map<std::size_t, fcl::CollisionObject*>::const_iterator cit = boxes.begin();
cit != boxes.end();++cit,++i)
{
fcl::Vec3f position = (*cit->second).getTranslation();
_CORBA_ULong size = (_CORBA_ULong) 4;
double* dofArray = hpp::floatSeq::allocbuf(size);
hpp::floatSeq floats (size, size, dofArray, true);
//convert the config in dofseq
for (model::size_type j=0 ; j < 3 ; ++j) {
dofArray[j] = position[j];
}
dofArray[3] = resolution;
(*res) [i] = floats;
}
fullBody_->device_->currentConfiguration(save);
fullBody_->device_->computeForwardKinematics();
return res;
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
hpp::floatSeq* RbprmBuilder::getOctreeTransform(const char* limbName, const hpp::floatSeq& configuration) throw (hpp::Error)
{
try{
model::Configuration_t config = dofArrayToConfig (fullBody_->device_, configuration);
model::Configuration_t save = fullBody_->device_->currentConfiguration();
fullBody_->device_->currentConfiguration(config);
fullBody_->device_->computeForwardKinematics();
const hpp::rbprm::RbPrmLimbPtr_t limb =fullBody_->GetLimbs().at(std::string(limbName));
const fcl::Transform3f transform = limb->octreeRoot();
const fcl::Quaternion3f& quat = transform.getQuatRotation();
const fcl::Vec3f& position = transform.getTranslation();
hpp::floatSeq *dofArray;
dofArray = new hpp::floatSeq();
dofArray->length(_CORBA_ULong(7));
for(std::size_t i=0; i< 3; i++)
(*dofArray)[(_CORBA_ULong)i] = position [i];
for(std::size_t i=0; i< 4; i++)
(*dofArray)[(_CORBA_ULong)i+3] = quat [i];
fullBody_->device_->currentConfiguration(save);
fullBody_->device_->computeForwardKinematics();
return dofArray;
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
CORBA::Short RbprmBuilder::isConfigBalanced(const hpp::floatSeq& configuration, const hpp::Names_t& contactLimbs, double robustnessTreshold) throw (hpp::Error)
{
try{
rbprm::State testedState;
model::Configuration_t config = dofArrayToConfig (fullBody_->device_, configuration);
model::Configuration_t save = fullBody_->device_->currentConfiguration();
std::vector<std::string> names = stringConversion(contactLimbs);
for(std::vector<std::string>::const_iterator cit = names.begin(); cit != names.end();++cit)
{
std::cout << "name " << * cit << std::endl;
const hpp::rbprm::RbPrmLimbPtr_t limb =fullBody_->GetLimbs().at(std::string(*cit));
testedState.contacts_[*cit] = true;
testedState.contactPositions_[*cit] = limb->effector_->currentTransformation().getTranslation();
testedState.contactRotation_[*cit] = limb->effector_->currentTransformation().getRotation();
// normal given by effector normal
const fcl::Vec3f normal = limb->effector_->currentTransformation().getRotation() * limb->normal_;
testedState.contactNormals_[*cit] = normal;
testedState.configuration_ = config;
++testedState.nbContacts;
}
fullBody_->device_->currentConfiguration(save);
fullBody_->device_->computeForwardKinematics();
if (stability::IsStable(fullBody_, testedState) >= robustnessTreshold)
{
return (CORBA::Short)(1);
}
else
{
return (CORBA::Short)(0);
}
}
catch(std::runtime_error& e)
{
throw Error(e.what());
}
}
void RbprmBuilder::SetProblemSolver (hpp::core::ProblemSolverPtr_t problemSolver)
{
problemSolver_ = problemSolver;
bindShooter_.problemSolver_ = problemSolver;
//bind shooter creator to hide problem as a parameter and respect signature
// add rbprmshooter
problemSolver->addConfigurationShooterType("RbprmShooter",
boost::bind(&BindShooter::create, boost::ref(bindShooter_), _1));
problemSolver->addPathValidationType("RbprmPathValidation",
boost::bind(&BindShooter::createPathValidation, boost::ref(bindShooter_), _1, _2));
}
} // namespace impl
} // namespace rbprm
} // namespace hpp