| Line | Branch | Exec | Source | 
    
      | 1 |  |  | // Copyright (c) 2017, Joseph Mirabel | 
    
      | 2 |  |  | // Authors: Joseph Mirabel (joseph.mirabel@laas.fr), | 
    
      | 3 |  |  | //          Florent Lamiraux (florent.lamiraux@laas.fr) | 
    
      | 4 |  |  | //          Alexandre Thiault (athiault@laas.fr) | 
    
      | 5 |  |  | //          Le Quang Anh (quang-anh.le@laas.fr) | 
    
      | 6 |  |  | // | 
    
      | 7 |  |  | // This file is part of hpp-manipulation. | 
    
      | 8 |  |  | // hpp-manipulation is free software: you can redistribute it | 
    
      | 9 |  |  | // and/or modify it under the terms of the GNU Lesser General Public | 
    
      | 10 |  |  | // License as published by the Free Software Foundation, either version | 
    
      | 11 |  |  | // 3 of the License, or (at your option) any later version. | 
    
      | 12 |  |  | // | 
    
      | 13 |  |  | // hpp-manipulation is distributed in the hope that it will be | 
    
      | 14 |  |  | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty | 
    
      | 15 |  |  | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
    
      | 16 |  |  | // General Lesser Public License for more details.  You should have | 
    
      | 17 |  |  | // received a copy of the GNU Lesser General Public License along with | 
    
      | 18 |  |  | // hpp-manipulation. If not, see <http://www.gnu.org/licenses/>. | 
    
      | 19 |  |  |  | 
    
      | 20 |  |  | #ifndef HPP_MANIPULATION_PATH_PLANNER_STATES_PATH_FINDER_HH | 
    
      | 21 |  |  | #define HPP_MANIPULATION_PATH_PLANNER_STATES_PATH_FINDER_HH | 
    
      | 22 |  |  |  | 
    
      | 23 |  |  | #include <hpp/core/config-projector.hh> | 
    
      | 24 |  |  | #include <hpp/core/config-validations.hh> | 
    
      | 25 |  |  | #include <hpp/core/fwd.hh> | 
    
      | 26 |  |  | #include <hpp/core/path-planner.hh> | 
    
      | 27 |  |  | #include <hpp/core/path.hh> | 
    
      | 28 |  |  | #include <hpp/core/projection-error.hh> | 
    
      | 29 |  |  | #include <hpp/core/validation-report.hh> | 
    
      | 30 |  |  | #include <hpp/manipulation/config.hh> | 
    
      | 31 |  |  | #include <hpp/manipulation/fwd.hh> | 
    
      | 32 |  |  | #include <hpp/manipulation/problem.hh> | 
    
      | 33 |  |  | #include <unordered_map> | 
    
      | 34 |  |  |  | 
    
      | 35 |  |  | namespace hpp { | 
    
      | 36 |  |  | namespace manipulation { | 
    
      | 37 |  |  | namespace pathPlanner { | 
    
      | 38 |  |  |  | 
    
      | 39 |  |  | /// \addtogroup path_planner | 
    
      | 40 |  |  | /// \{ | 
    
      | 41 |  |  |  | 
    
      | 42 |  |  | /// Optimization-based path planning method. | 
    
      | 43 |  |  | /// | 
    
      | 44 |  |  | /// #### Sketch of the method | 
    
      | 45 |  |  | /// | 
    
      | 46 |  |  | /// Given two configurations \f$ (q_1,q_2) \f$, this class formulates and | 
    
      | 47 |  |  | /// solves the problem as follows. | 
    
      | 48 |  |  | /// - Compute the corresponding states \f$ (s_1, s_2) \f$. | 
    
      | 49 |  |  | /// - For each path \f$ (e_0, ... e_n) \f$ of length not more than | 
    
      | 50 |  |  | ///   parameter "StatesPathFinder/maxDepth" between | 
    
      | 51 |  |  | ///   \f$ (s_1, s_2)\f$ in the constraint graph, do: | 
    
      | 52 |  |  | ///   - define \f$ n-1 \f$ intermediate configuration \f$ p_i \f$, | 
    
      | 53 |  |  | ///   - initialize the optimization problem, as explained below, | 
    
      | 54 |  |  | ///   - solve the optimization problem, which gives \f$ p^*_i \f$, | 
    
      | 55 |  |  | ///   - in case of failure, continue the loop. | 
    
      | 56 |  |  | /// | 
    
      | 57 |  |  | /// #### Problem formulation | 
    
      | 58 |  |  | /// Find \f$ (p_i) \f$ such that: | 
    
      | 59 |  |  | /// - \f$ p_0 = q_1 \f$, | 
    
      | 60 |  |  | /// - \f$ p_{n+1} = q_2 \f$, | 
    
      | 61 |  |  | /// - \f$ p_i \f$ is in state between \f$ (e_{i-1}, e_i) \f$, (\ref | 
    
      | 62 |  |  | /// StateFunction) | 
    
      | 63 |  |  | /// - \f$ (p_i, p_{i+1}) \f$ are reachable with transition \f$ e_i \f$ (\ref | 
    
      | 64 |  |  | /// EdgeFunction). | 
    
      | 65 |  |  | /// | 
    
      | 66 |  |  | /// #### Problem resolution | 
    
      | 67 |  |  | /// | 
    
      | 68 |  |  | /// One solver (hpp::constraints::solver::BySubstitution) is created | 
    
      | 69 |  |  | /// for each waypoint \f$p_i\f$. | 
    
      | 70 |  |  | /// - method buildOptimizationProblem builds a matrix the rows of which | 
    
      | 71 |  |  | ///   are the parameterizable numerical constraints present in the | 
    
      | 72 |  |  | ///   graph, and the columns of which are the waypoints. Each value in the | 
    
      | 73 |  |  | ///   matrix defines the status of each constraint right hand side for | 
    
      | 74 |  |  | ///   this waypoint, among {absent from the solver, | 
    
      | 75 |  |  | ///                         equal to value for previous waypoint, | 
    
      | 76 |  |  | ///                         equal to value for start configuration, | 
    
      | 77 |  |  | ///                         equal to value for end configuration}. | 
    
      | 78 |  |  | /// - method analyseOptimizationProblem loops over the waypoint solvers, | 
    
      | 79 |  |  | ///   tests what happens when solving each waypoint after initializing | 
    
      | 80 |  |  | ///   only the right hand sides that are equal to the initial or goal | 
    
      | 81 |  |  | ///   configuration, and detects if a collision is certain to block any attempts | 
    
      | 82 |  |  | ///   to solve the problem in the solveOptimizationProblem step. | 
    
      | 83 |  |  | /// - method solveOptimizationProblem tries to solve for each waypoint after | 
    
      | 84 |  |  | ///   initializing the right hand sides with the proper values, backtracking | 
    
      | 85 |  |  | ///   to the previous waypoint if the solving failed or a collision is | 
    
      | 86 |  |  | ///   detected a number of times set from the parameter | 
    
      | 87 |  |  | ///   "StatesPathFinder/nTriesUntilBacktrack". If too much backtracking | 
    
      | 88 |  |  | ///   occurs, the method can eventually return false. | 
    
      | 89 |  |  | /// - eventually method buildPath build paths between waypoints with | 
    
      | 90 |  |  | ///   the constraints of the transition in which the path lies. | 
    
      | 91 |  |  | /// | 
    
      | 92 |  |  | /// #### Current status | 
    
      | 93 |  |  | /// | 
    
      | 94 |  |  | /// The method has been successfully tested with romeo holding a placard | 
    
      | 95 |  |  | /// and the construction set benchmarks. The result is satisfactory | 
    
      | 96 |  |  | /// except between pregrasp and grasp waypoints that may be far | 
    
      | 97 |  |  | /// away from each other if the transition between those state does | 
    
      | 98 |  |  | /// not contain the grasp complement constraint. The same holds | 
    
      | 99 |  |  | /// between placement and pre-placement. | 
    
      | 100 |  |  | class HPP_MANIPULATION_DLLAPI StatesPathFinder : public core::PathPlanner { | 
    
      | 101 |  |  | public: | 
    
      | 102 |  |  | struct OptimizationData; | 
    
      | 103 |  |  |  | 
    
      | 104 |  | ✗ | virtual ~StatesPathFinder() {}; | 
    
      | 105 |  |  |  | 
    
      | 106 |  |  | static StatesPathFinderPtr_t create(const core::ProblemConstPtr_t& problem); | 
    
      | 107 |  |  |  | 
    
      | 108 |  |  | static StatesPathFinderPtr_t createWithRoadmap( | 
    
      | 109 |  |  | const core::ProblemConstPtr_t& problem, | 
    
      | 110 |  |  | const core::RoadmapPtr_t& roadmap); | 
    
      | 111 |  |  |  | 
    
      | 112 |  |  | StatesPathFinderPtr_t copy() const; | 
    
      | 113 |  |  |  | 
    
      | 114 |  |  | /// create a vector of configurations between two configurations | 
    
      | 115 |  |  | /// \param q1 initial configuration | 
    
      | 116 |  |  | /// \param q2 pointer to final configuration, NULL if goal is | 
    
      | 117 |  |  | /// defined as a set of constraints | 
    
      | 118 |  |  | /// \return a Configurations_t from q1 to q2 if found. An empty | 
    
      | 119 |  |  | /// vector if a path could not be built. | 
    
      | 120 |  |  | core::Configurations_t computeConfigList(ConfigurationIn_t q1, | 
    
      | 121 |  |  | ConfigurationIn_t q2); | 
    
      | 122 |  |  |  | 
    
      | 123 |  |  | // access functions for Python interface | 
    
      | 124 |  |  | std::vector<std::string> constraintNamesFromSolverAtWaypoint(std::size_t wp); | 
    
      | 125 |  |  | std::vector<std::string> lastBuiltTransitions() const; | 
    
      | 126 |  |  | std::string displayConfigsSolved() const; | 
    
      | 127 |  |  | bool buildOptimizationProblemFromNames(std::vector<std::string> names); | 
    
      | 128 |  |  |  | 
    
      | 129 |  |  | // Substeps of method solveOptimizationProblem | 
    
      | 130 |  |  | void initWPRandom(std::size_t wp); | 
    
      | 131 |  |  | void initWPNear(std::size_t wp); | 
    
      | 132 |  |  | void initWP(std::size_t wp, ConfigurationIn_t q); | 
    
      | 133 |  |  | /// Status of the step to solve for a particular waypoint | 
    
      | 134 |  |  | enum SolveStepStatus { | 
    
      | 135 |  |  | /// Valid solution (no collision) | 
    
      | 136 |  |  | VALID_SOLUTION, | 
    
      | 137 |  |  | /// Bad solve status, no solution from the solver | 
    
      | 138 |  |  | NO_SOLUTION, | 
    
      | 139 |  |  | /// Solution has collision in edge leading to the waypoint | 
    
      | 140 |  |  | COLLISION_BEFORE, | 
    
      | 141 |  |  | /// Solution has collision in edge going from the waypoint | 
    
      | 142 |  |  | COLLISION_AFTER, | 
    
      | 143 |  |  | }; | 
    
      | 144 |  |  |  | 
    
      | 145 |  |  | SolveStepStatus solveStep(std::size_t wp); | 
    
      | 146 |  |  |  | 
    
      | 147 |  |  | /// deletes from memory the latest working states list, which is used to | 
    
      | 148 |  |  | /// resume finding solutions from that list in case of failure at a | 
    
      | 149 |  |  | /// later step. | 
    
      | 150 |  |  | void reset(); | 
    
      | 151 |  |  |  | 
    
      | 152 |  |  | virtual void startSolve(); | 
    
      | 153 |  |  | virtual void oneStep(); | 
    
      | 154 |  |  | /// when both initial state is one of potential goal states, | 
    
      | 155 |  |  | /// try connecting them directly | 
    
      | 156 |  |  | virtual void tryConnectInitAndGoals(); | 
    
      | 157 |  |  |  | 
    
      | 158 |  |  | protected: | 
    
      | 159 |  |  | StatesPathFinder(const core::ProblemConstPtr_t& problem, | 
    
      | 160 |  |  | const core::RoadmapPtr_t&); | 
    
      | 161 |  |  | StatesPathFinder(const StatesPathFinder& other); | 
    
      | 162 |  |  |  | 
    
      | 163 |  | ✗ | void init(StatesPathFinderWkPtr_t weak) { weak_ = weak; } | 
    
      | 164 |  |  |  | 
    
      | 165 |  |  | private: | 
    
      | 166 |  |  | typedef constraints::solver::BySubstitution Solver_t; | 
    
      | 167 |  |  | struct GraphSearchData; | 
    
      | 168 |  |  |  | 
    
      | 169 |  |  | /// Gather constraints of all edges | 
    
      | 170 |  |  | void gatherGraphConstraints(); | 
    
      | 171 |  |  |  | 
    
      | 172 |  |  | /// Step 1 of the algorithm | 
    
      | 173 |  |  | /// \return whether the max depth was reached. | 
    
      | 174 |  |  | bool findTransitions(GraphSearchData& data) const; | 
    
      | 175 |  |  |  | 
    
      | 176 |  |  | /// Step 2 of the algorithm | 
    
      | 177 |  |  | graph::Edges_t getTransitionList(const GraphSearchData& data, | 
    
      | 178 |  |  | const std::size_t& i) const; | 
    
      | 179 |  |  |  | 
    
      | 180 |  |  | /// Step 3 of the algorithm | 
    
      | 181 |  |  |  | 
    
      | 182 |  |  | // check that the solver either contains exactly same constraint | 
    
      | 183 |  |  | // or a constraint with similar parametrizable form | 
    
      | 184 |  |  | // constraint/both and constraint/complement | 
    
      | 185 |  |  | bool contains(const Solver_t& solver, const ImplicitPtr_t& c) const; | 
    
      | 186 |  |  |  | 
    
      | 187 |  |  | // check that the solver either contains exactly same constraint | 
    
      | 188 |  |  | // or a stricter version of the constraint | 
    
      | 189 |  |  | // constraint/both stricter than constraint and stricter than | 
    
      | 190 |  |  | // constraint/complement | 
    
      | 191 |  |  | bool containsStricter(const Solver_t& solver, const ImplicitPtr_t& c) const; | 
    
      | 192 |  |  | bool checkConstantRightHandSide(size_type index); | 
    
      | 193 |  |  | bool buildOptimizationProblem(const graph::Edges_t& transitions); | 
    
      | 194 |  |  |  | 
    
      | 195 |  |  | /// Step 4 of the algorithm | 
    
      | 196 |  |  | void preInitializeRHS(std::size_t j, Configuration_t& q); | 
    
      | 197 |  |  | bool analyseOptimizationProblem(const graph::Edges_t& transitions, | 
    
      | 198 |  |  | core::ProblemConstPtr_t _problem); | 
    
      | 199 |  |  |  | 
    
      | 200 |  |  | /// Step 5 of the algorithm | 
    
      | 201 |  |  | void initializeRHS(std::size_t j); | 
    
      | 202 |  |  | bool solveOptimizationProblem(); | 
    
      | 203 |  |  |  | 
    
      | 204 |  |  | // Data structure used to store a constraint right hand side as value and its | 
    
      | 205 |  |  | // name as key, both in form of hash numbers (so that names and rhs of two | 
    
      | 206 |  |  | // constraints can be easily merge). Exemple : ConstraintMap_t map = | 
    
      | 207 |  |  | // {{nameStringHash, rhsVectorHash}}; With rhsVectorHash the hash of a | 
    
      | 208 |  |  | // vector_t of rights hand side constraints with hashRHS, and nameStringHash | 
    
      | 209 |  |  | // the hash of a std::string - obtained for instance with std::hash. | 
    
      | 210 |  |  | typedef std::unordered_map<size_t, size_t> ConstraintMap_t;  // map (name, | 
    
      | 211 |  |  | // rhs) | 
    
      | 212 |  |  |  | 
    
      | 213 |  |  | /// @brief Get a configuration in accordance with the statuts matrix at a step | 
    
      | 214 |  |  | /// j for the constraint i | 
    
      | 215 |  |  | /// @param i number of the constraint in the status matrix | 
    
      | 216 |  |  | /// @param j step of the potential solution (index of a waypoint) | 
    
      | 217 |  |  | /// @return a configuration Configuration_t which follows the status matrix | 
    
      | 218 |  |  | /// indication at the given indices | 
    
      | 219 |  |  | Configuration_t getConfigStatus(size_type i, size_type j) const; | 
    
      | 220 |  |  |  | 
    
      | 221 |  |  | /// @brief Get the right hand side of a constraint w.r.t a set configuration | 
    
      | 222 |  |  | /// for this constraint | 
    
      | 223 |  |  | /// @param constraint the constraint to compute the right hand side of | 
    
      | 224 |  |  | /// @param q the configuration in which the constraint is set | 
    
      | 225 |  |  | /// @return a right hand side vector_t | 
    
      | 226 |  |  | vector_t getConstraintRHS(ImplicitPtr_t constraint, Configuration_t q) const; | 
    
      | 227 |  |  |  | 
    
      | 228 |  |  | /// @brief Hash a vector of right hand side into a long unsigned integer | 
    
      | 229 |  |  | /// @param rhs the right hand side vector vector_t | 
    
      | 230 |  |  | /// @return a size_t integer hash | 
    
      | 231 |  |  | size_t hashRHS(vector_t rhs) const; | 
    
      | 232 |  |  |  | 
    
      | 233 |  |  | /// @brief Check if a solution (a list of transition) contains impossible to | 
    
      | 234 |  |  | /// solve steps due to inevitable collisions | 
    
      | 235 |  |  | /// @param pairMap The ConstraintMap_tf table of pairs of incompatibles | 
    
      | 236 |  |  | /// constraints | 
    
      | 237 |  |  | /// @param constraintMap The hasmap table of constraints which are in pairMap | 
    
      | 238 |  |  | /// @return a bool which is true is there is no impossible to solve steps, | 
    
      | 239 |  |  | /// true otherwise | 
    
      | 240 |  |  | bool checkSolvers(ConstraintMap_t const& pairMap, | 
    
      | 241 |  |  | ConstraintMap_t const& constraintMap) const; | 
    
      | 242 |  |  |  | 
    
      | 243 |  |  | /// @brief For a certain step wp during solving check for collision impossible | 
    
      | 244 |  |  | /// to solve. | 
    
      | 245 |  |  | /// @param pairMap The ConstraintMap_t table of pairs of incompatibles | 
    
      | 246 |  |  | /// constraints | 
    
      | 247 |  |  | /// @param constraintMap The hasmap table of constraints which are in pairMap | 
    
      | 248 |  |  | /// @param wp The index of the current step | 
    
      | 249 |  |  | /// @return a bool which is true if there is no collision or impossible to | 
    
      | 250 |  |  | /// solve ones, false otherwise. | 
    
      | 251 |  |  | bool saveIncompatibleRHS(ConstraintMap_t& pairMap, | 
    
      | 252 |  |  | ConstraintMap_t& constraintMap, size_type const wp); | 
    
      | 253 |  |  |  | 
    
      | 254 |  |  | // For a joint get his most, constrained with it, far parent | 
    
      | 255 |  |  | core::JointConstPtr_t maximalJoint(size_t const wp, core::JointConstPtr_t a); | 
    
      | 256 |  |  |  | 
    
      | 257 |  |  | /// Step 6 of the algorithm | 
    
      | 258 |  |  | core::Configurations_t getConfigList() const; | 
    
      | 259 |  |  |  | 
    
      | 260 |  |  | /// Functions used in assert statements | 
    
      | 261 |  |  | bool checkWaypointRightHandSide(std::size_t ictr, std::size_t jslv) const; | 
    
      | 262 |  |  | bool checkSolverRightHandSide(std::size_t ictr, std::size_t jslv) const; | 
    
      | 263 |  |  | bool checkWaypointRightHandSide(std::size_t jslv) const; | 
    
      | 264 |  |  | bool checkSolverRightHandSide(std::size_t jslv) const; | 
    
      | 265 |  |  |  | 
    
      | 266 |  |  | void displayRhsMatrix(); | 
    
      | 267 |  |  | void displayStatusMatrix(const graph::Edges_t& transitions); | 
    
      | 268 |  |  |  | 
    
      | 269 |  |  | /// A pointer to the manipulation problem | 
    
      | 270 |  |  | ProblemConstPtr_t problem_; | 
    
      | 271 |  |  | /// Path planning problem in each leaf. | 
    
      | 272 |  |  | core::ProblemPtr_t inStateProblem_; | 
    
      | 273 |  |  |  | 
    
      | 274 |  |  | /// Vector of parameterizable edge numerical constraints | 
    
      | 275 |  |  | NumericalConstraints_t constraints_; | 
    
      | 276 |  |  | /// Map of indices in constraints_ | 
    
      | 277 |  |  | std::map<std::string, std::size_t> index_; | 
    
      | 278 |  |  |  | 
    
      | 279 |  |  | /// associative map that stores pairs of constraints of the form | 
    
      | 280 |  |  | /// (constraint/complement, constraint/hold) | 
    
      | 281 |  |  | std::map<ImplicitPtr_t, ImplicitPtr_t> sameRightHandSide_; | 
    
      | 282 |  |  |  | 
    
      | 283 |  |  | /// associative map that stores pairs of constraints of either form | 
    
      | 284 |  |  | /// (constraint, constraint/hold) | 
    
      | 285 |  |  | /// or (constraint/complement, constraint/hold) | 
    
      | 286 |  |  | std::map<ImplicitPtr_t, ImplicitPtr_t> stricterConstraints_; | 
    
      | 287 |  |  |  | 
    
      | 288 |  |  | mutable OptimizationData* optData_; | 
    
      | 289 |  |  | mutable std::shared_ptr<GraphSearchData> graphData_; | 
    
      | 290 |  |  | graph::Edges_t lastBuiltTransitions_; | 
    
      | 291 |  |  |  | 
    
      | 292 |  |  | /// Constraints defining the goal | 
    
      | 293 |  |  | /// For now: | 
    
      | 294 |  |  | /// - comparison type Equality is initialized to zero | 
    
      | 295 |  |  | /// - if goal constraint is not already present in any graph state, | 
    
      | 296 |  |  | ///   it should not require propagating a complement. | 
    
      | 297 |  |  | ///   invalid eg: specify the full pose of an object placement or | 
    
      | 298 |  |  | ///   object grasp | 
    
      | 299 |  |  | NumericalConstraints_t goalConstraints_; | 
    
      | 300 |  |  | bool goalDefinedByConstraints_; | 
    
      | 301 |  |  | // Variables used across several calls to oneStep | 
    
      | 302 |  |  | Configuration_t q1_, q2_; | 
    
      | 303 |  |  | core::Configurations_t configList_; | 
    
      | 304 |  |  | std::size_t idxConfigList_; | 
    
      | 305 |  |  | size_type nTryConfigList_; | 
    
      | 306 |  |  | bool solved_, interrupt_; | 
    
      | 307 |  |  |  | 
    
      | 308 |  |  | /// Weak pointer to itself | 
    
      | 309 |  |  | StatesPathFinderWkPtr_t weak_; | 
    
      | 310 |  |  |  | 
    
      | 311 |  |  | };  // class StatesPathFinder | 
    
      | 312 |  |  | /// \} | 
    
      | 313 |  |  |  | 
    
      | 314 |  |  | }  // namespace pathPlanner | 
    
      | 315 |  |  | }  // namespace manipulation | 
    
      | 316 |  |  | }  // namespace hpp | 
    
      | 317 |  |  |  | 
    
      | 318 |  |  | #endif  // HPP_MANIPULATION_PATH_PLANNER_STATES_PATH_FINDER_HH | 
    
      | 319 |  |  |  |