diff --git a/include/hpp/manipulation/path-planner/end-effector-trajectory.hh b/include/hpp/manipulation/path-planner/end-effector-trajectory.hh index 098de5447ceb5fef03ecc157b2321b74d013f519..783ad7fe5b89633dc0c8a93481783edb79dc2500 100644 --- a/include/hpp/manipulation/path-planner/end-effector-trajectory.hh +++ b/include/hpp/manipulation/path-planner/end-effector-trajectory.hh @@ -52,6 +52,46 @@ typedef shared_ptr<IkSolverInitialization> IkSolverInitializationPtr_t; HPP_PREDEF_CLASS(EndEffectorTrajectory); typedef shared_ptr<EndEffectorTrajectory> EndEffectorTrajectoryPtr_t; +/// \addtogroup path_planning +/// \{ + +/// Plan a path for a robot with constrained trajectory of an end effector +/// +/// This path planner only works with a steering method of type +/// steeringMethod::EndEffectorTrajectory. The steering +/// method defines the desired end-effector trajectory using a time-varying +/// constraint. +/// +/// To plan a path between two configurations \c q_init and \c q_goal, the +/// configurations must satisfy the constraint at the beginning and at the +/// end of the definition interval respectively. +/// +/// The interval of definition \f$[0,T]\f$ of the output path is defined by the +/// time-varying constraint of the steering method. This interval is uniformly +/// discretized in a number of samples that can be accessed using method \link +/// EndEffectorTrajectory::nDiscreteSteps nDiscreteSteps \endlink. +/// +/// The path is planned by successively calling method \link +/// EndEffectorTrajectory::oneStep oneStep \endlink that performs the following +/// actions. +/// - A vector of configurations is produced by appending random +/// configurations to \c q_init. The number of random configurations can +/// be accessed by methods \link EndEffectorTrajectory::nRandomConfig +/// nRandomConfig \endlink. +/// - for each configuration in the vector, +/// - the initial configuration of the path is computed by projecting the +/// configuration on the constraint, +/// - the configuration at following samples is computed by projecting the +/// configuration at the previous sample using the time-varying +/// constraint. +/// - In case of failure +/// - in projecting a configuration or +/// - in validating the path for collision, +/// the loop restart with the next random configuration. +/// +/// Note that continuity is not tested but enforced by projecting the +/// configuration of the previous sample to compute the configuration at +/// a given sample. class HPP_MANIPULATION_DLLAPI EndEffectorTrajectory : public core::PathPlanner { public: /// Return shared pointer to new instance @@ -129,6 +169,7 @@ class HPP_MANIPULATION_DLLAPI EndEffectorTrajectory : public core::PathPlanner { /// Feasibility bool feasibilityOnly_; }; // class EndEffectorTrajectory +// \} } // namespace pathPlanner } // namespace manipulation } // namespace hpp diff --git a/include/hpp/manipulation/steering-method/end-effector-trajectory.hh b/include/hpp/manipulation/steering-method/end-effector-trajectory.hh index 5117641a261fb9bb4106c2155c891c14f75228db..623cb92b1f442230951580015727c9f8d4d15aa4 100644 --- a/include/hpp/manipulation/steering-method/end-effector-trajectory.hh +++ b/include/hpp/manipulation/steering-method/end-effector-trajectory.hh @@ -35,15 +35,40 @@ namespace hpp { namespace manipulation { -/// \addtogroup steering_method -/// \{ namespace steeringMethod { HPP_PREDEF_CLASS(EndEffectorTrajectory); typedef shared_ptr<EndEffectorTrajectory> EndEffectorTrajectoryPtr_t; using core::PathPtr_t; -/// Build StraightPath constrained by a varying right hand side constraint. +/// \addtogroup steering_method +/// \{ + +/// Build piecewise straight paths for a robot end-effector +/// +/// To use this steering method, the user needs to provide +/// \li a constraint with value in \f$SE(3)\f$. An easy way to create such a +/// constraint is to use method hpp::manipulation::Handle::createGrasp. The +/// constraint is passed to the steering method using method \link +/// EndEffectorTrajectory::trajectoryConstraint trajectoryConstraint \endlink. +/// \li the time-varying right hand side of this constraint along the path +/// the user wants to create in the form of a hpp::core::Path instance +/// with values in \f$SE(3)\f$. For that, \link +/// EndEffectorTrajectory::makePiecewiseLinearTrajectory +/// makePiecewiseLinearTrajectory \endlink method may be useful. +/// +/// \warning the constraint should also be inserted in the \link +/// hpp::core::SteeringMethod::constraints set of constraints \endlink +/// of the steering method. +/// +/// Once the steering method has been initialized, it can be called between +/// two configurations \c q1 and \c q2. The interval of definition \f$[0,T]\f$ +/// of the output path is the same as the one of the path provided as the right +/// hand side of the constraint. +/// Note that \c q1 and \c q2 should satisfy the constraint at times 0 and +/// \f$T\f$ respectively. The output path is a \link hpp::core::StraightPath +/// linear interpolation \endlink between \c q1 and \c q2 projected on the +/// steering method constraints. class HPP_MANIPULATION_DLLAPI EndEffectorTrajectory : public core::SteeringMethod { public: @@ -141,8 +166,8 @@ class HPP_MANIPULATION_DLLAPI EndEffectorTrajectory interval_t timeRange_; constraints::ImplicitPtr_t constraint_; }; -} // namespace steeringMethod /// \} +} // namespace steeringMethod } // namespace manipulation } // namespace hpp diff --git a/src/path-planner/end-effector-trajectory.cc b/src/path-planner/end-effector-trajectory.cc index 1a874c7c0350a5cf34a5729625f66bc2bfda8075..4a708bb2b930c394be6c2f38e7c4b54b3491dc3b 100644 --- a/src/path-planner/end-effector-trajectory.cc +++ b/src/path-planner/end-effector-trajectory.cc @@ -151,6 +151,8 @@ void EndEffectorTrajectory::oneStep() { core::interval_t timeRange(sm->timeRange()); + // Generate a vector if configuration where the first one is the initial + // configuration and the following ones are random configurations std::vector<core::Configuration_t> qs( configurations(*problem()->initConfig())); if (qs.empty()) { @@ -166,12 +168,23 @@ void EndEffectorTrajectory::oneStep() { vector_t times(nDiscreteSteps_ + 1); matrix_t steps(problem()->robot()->configSize(), nDiscreteSteps_ + 1); + // Discretize definition interval of the steering method into times times[0] = timeRange.first; for (int j = 1; j < nDiscreteSteps_; ++j) times[j] = timeRange.first + j * (timeRange.second - timeRange.first) / nDiscreteSteps_; times[nDiscreteSteps_] = timeRange.second; + // For each random configuration, + // - compute initial configuration of path by projecting the random + // configuration (initial configuration for the first time), + // - compute following samples by projecting current sample after + // updating right hand side. + // If failure, try next random configuration. + // Failure can be due to + // - projection, + // - collision of final configuration, + // - validation of path (for collision mainly). for (i = 0; i < qs.size(); ++i) { if (resetRightHandSide) { constraints->rightHandSideAt(times[0]); @@ -200,6 +213,7 @@ void EndEffectorTrajectory::oneStep() { if (!success) continue; success = false; + // Test collision of final configuration. if (!cfgValidation->validate(steps.col(nDiscreteSteps_), cfgReport)) { hppDout(info, "Destination config is in collision."); continue; @@ -220,6 +234,10 @@ void EndEffectorTrajectory::oneStep() { continue; } + // In case of success, + // - insert q_init as initial configuration of the roadmap, + // - insert final configuration as goal node in the roadmap, + // - add a roadmap edge between them and stop. roadmap()->initNode(make_shared<Configuration_t>(steps.col(0))); core::NodePtr_t init = roadmap()->initNode(); core::NodePtr_t goal = roadmap()->addGoalNode(