DART 6.10.1
Loading...
Searching...
No Matches
PathPlanner.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011-2021, The DART development contributors
3 * All rights reserved.
4 *
5 * The list of contributors can be found at:
6 * https://github.com/dartsim/dart/blob/master/LICENSE
7 *
8 * This file is provided under the following "BSD-style" License:
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
11 * conditions are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
42#ifndef DART_PLANNING_PATHPLANNER_HPP_
43#define DART_PLANNING_PATHPLANNER_HPP_
44
45#include <cstdio>
46#include <iostream>
47#include <limits>
48#include <list>
49#include <vector>
50#include <Eigen/Core>
52#include "dart/planning/RRT.hpp"
54
55namespace dart {
56namespace planning {
57
58/* *********************************************************************************************
59 */
61template <class R = RRT>
63{
64public:
65 bool connect;
68 double
70 double
72 std::size_t
76
77 // NOTE: It is useful to keep the rrts around after planning for reuse,
78 // analysis, and etc.
81
82public:
84 PathPlanner() : world(nullptr)
85 {
86 }
87
91 bool bidirectional_ = true,
92 bool connect_ = true,
93 double stepSize_ = 0.1,
94 std::size_t maxNodes_ = 1e6,
95 double goalBias_ = 0.3)
96 : world(&world),
97 bidirectional(bidirectional_),
98 connect(connect_),
99 stepSize(stepSize_),
100 maxNodes(maxNodes_),
101 goalBias(goalBias_)
102 {
103 }
104
106 virtual ~PathPlanner()
107 {
108 }
109
112 dynamics::Skeleton* robot,
113 const std::vector<int>& dofs,
114 const Eigen::VectorXd& start,
115 const Eigen::VectorXd& goal,
116 std::list<Eigen::VectorXd>& path)
117 {
118 std::vector<Eigen::VectorXd> startVector, goalVector;
119 startVector.push_back(start);
120 goalVector.push_back(goal);
121 return planPath(robot, dofs, startVector, goalVector, path);
122 }
123
125 bool planPath(
126 dynamics::Skeleton* robot,
127 const std::vector<std::size_t>& dofs,
128 const std::vector<Eigen::VectorXd>& start,
129 const std::vector<Eigen::VectorXd>& goal,
130 std::list<Eigen::VectorXd>& path);
131
132private:
135 dynamics::Skeleton* robot,
136 const std::vector<int>& dofs,
137 const std::vector<Eigen::VectorXd>& start,
138 const Eigen::VectorXd& goal,
139 std::list<Eigen::VectorXd>& path);
140
149 dynamics::Skeleton* robot,
150 const std::vector<int>& dofs,
151 const std::vector<Eigen::VectorXd>& start,
152 const std::vector<Eigen::VectorXd>& goal,
153 std::list<Eigen::VectorXd>& path);
154};
155
156/* *********************************************************************************************
157 */
158template <class R>
160 dynamics::Skeleton* robot,
161 const std::vector<std::size_t>& dofs,
162 const std::vector<Eigen::VectorXd>& start,
163 const std::vector<Eigen::VectorXd>& goal,
164 std::list<Eigen::VectorXd>& path)
165{
166
167 Eigen::VectorXd savedConfiguration = robot->getPositions(dofs);
168
169 // ====================================================================
170 // Check for collisions in the start and goal configurations
171
172 // Sift through the possible start configurations and eliminate those that are
173 // in collision
174 std::vector<Eigen::VectorXd> feasibleStart;
175 for (unsigned int i = 0; i < start.size(); i++)
176 {
177 robot->setPositions(dofs, start[i]);
178 if (!world->checkCollision())
179 feasibleStart.push_back(start[i]);
180 }
181
182 // Return false if there are no feasible start configurations
183 if (feasibleStart.empty())
184 {
185 printf("WARNING: PathPlanner: Feasible start points are empty!\n");
186 return false;
187 }
188
189 // Sift through the possible goal configurations and eliminate those that are
190 // in collision
191 std::vector<Eigen::VectorXd> feasibleGoal;
192 for (unsigned int i = 0; i < goal.size(); i++)
193 {
194 robot->setPositions(dofs, goal[i]);
195 if (!world->checkCollision())
196 feasibleGoal.push_back(goal[i]);
197 }
198
199 // Return false if there are no feasible goal configurations
200 if (feasibleGoal.empty())
201 {
202 printf("WARNING: PathPlanner: Feasible goal points are empty!\n");
203 return false;
204 }
205
206 // ====================================================================
207 // Make the correct RRT algorithm for the given method
208
209 // Direct the search towards single or bidirectional
210 bool result = false;
211 if (bidirectional)
212 result
213 = planBidirectionalRrt(robot, dofs, feasibleStart, feasibleGoal, path);
214 else
215 {
216 if (feasibleGoal.size() > 1)
217 fprintf(stderr, "WARNING: planPath is using ONLY the first goal!\n");
218 result = planSingleTreeRrt(
219 robot, dofs, feasibleStart, feasibleGoal.front(), path);
220 }
221
222 // Restore previous robot configuration
223 robot->setPositions(dofs, savedConfiguration);
224
225 return result;
226}
227
228/* *********************************************************************************************
229 */
230template <class R>
232 dynamics::Skeleton* robot,
233 const std::vector<int>& dofs,
234 const std::vector<Eigen::VectorXd>& start,
235 const Eigen::VectorXd& goal,
236 std::list<Eigen::VectorXd>& path)
237{
238
239 const bool debug = false;
240
241 // Initialize the RRT
242 start_rrt = new R(world, robot, dofs, start, stepSize);
243
244 // Expand the tree until the goal is reached or the max # nodes is passed
245 typename R::StepResult result = R::STEP_PROGRESS;
246 double smallestGap = std::numeric_limits<double>::infinity();
247 std::size_t numNodes = start_rrt->getSize();
248 while (numNodes <= maxNodes)
249 {
250
251 // Get the target node based on the bias
252 Eigen::VectorXd target;
253 double randomValue = ((double)rand()) / RAND_MAX;
254 if (randomValue < goalBias)
255 target = goal;
256 else
257 target = start_rrt->getRandomConfig();
258
259 // Based on the method, either attempt to connect to the target directly or
260 // take a small step
261 if (connect)
262 start_rrt->connect(target);
263 else
264 start_rrt->tryStep(target);
265
266 // Check if the goal is reached and create the path, if so
267 double gap = start_rrt->getGap(goal);
268 if (gap < stepSize)
269 {
270 if (debug)
271 std::cout << "Returning true, reached the goal" << std::endl;
272 start_rrt->tracePath(start_rrt->activeNode, path);
273 return true;
274 }
275
276 // Update the number of nodes
277 numNodes = start_rrt->getSize();
278 }
279
280 if (debug)
281 printf("numNodes: %lu\n", numNodes);
282
283 // Maximum # of iterations are reached and path is not found - failed.
284 return false;
285}
286
287/* *********************************************************************************************
288 */
289template <class R>
291 dynamics::Skeleton* robot,
292 const std::vector<int>& dofs,
293 const std::vector<Eigen::VectorXd>& start,
294 const std::vector<Eigen::VectorXd>& goal,
295 std::list<Eigen::VectorXd>& path)
296{
297
298 const bool debug = false;
299
300 // Initialize both the start and goal RRTs.
301 // NOTE: We use the pointers for the RRTs to swap their roles in extending
302 // towards a target (random or goal) node.
303 start_rrt = new R(world, robot, dofs, start, stepSize);
304 goal_rrt = new R(world, robot, dofs, goal, stepSize);
305 R* rrt1 = start_rrt;
306 R* rrt2 = goal_rrt;
307
308 // Expand the tree until the trees meet or the max # nodes is passed
309 double smallestGap = std::numeric_limits<double>::infinity();
310 std::size_t numNodes = rrt1->getSize() + rrt2->getSize();
311 while (numNodes < maxNodes)
312 {
313
314 // Swap the roles of the two RRTs. Remember, the first rrt reaches out to a
315 // target node and creates a new node and the second rrt reaches to _the new
316 // node_.
317 R* temp = rrt1;
318 rrt1 = rrt2;
319 rrt2 = temp;
320
321 // Get the target node based on the bias
322 Eigen::VectorXd target;
323 double randomValue = ((double)rand()) / RAND_MAX;
324 if (randomValue < goalBias)
325 target = goal[0];
326 else
327 target = rrt1->getRandomConfig();
328
329 // Based on the method, rrt1 either attempt to connect to the target
330 // directly or takes a step
331 if (connect)
332 rrt1->connect(target);
333 else
334 rrt1->tryStep(target);
335
336 // rrt2 uses the last added node of rrt1 as a target and reaches out to it
337 // (connect or step) NOTE: If a node was not added, the nearest neighbor to
338 // the random node in rrt1 is used. NOTE: connect(x) and tryStep(x)
339 // functions return true if rrt2 can add the given node in the tree. In this
340 // case, this would imply that the two trees meet.
341 bool treesMet = false;
342 const Eigen::VectorXd& rrt2target = *(rrt1->configVector[rrt1->activeNode]);
343 if (connect)
344 treesMet = rrt2->connect(rrt2target);
345 else
346 treesMet = (rrt2->tryStep(rrt2target) == R::STEP_REACHED);
347
348 // Check if the trees have met and create the path, if so.
349 if (treesMet)
350 {
351 start_rrt->tracePath(start_rrt->activeNode, path);
352 goal_rrt->tracePath(goal_rrt->activeNode, path, true);
353 return true;
354 }
355
356 // Update the number of nodes in the two trees
357 numNodes = rrt1->getSize() + rrt2->getSize();
358
359 // Print the gap between the trees in debug mode
360 if (debug)
361 {
362 double gap = rrt2->getGap(*(rrt1->configVector[rrt1->activeNode]));
363 if (gap < smallestGap)
364 {
365 smallestGap = gap;
366 std::cout << "Gap: " << smallestGap
367 << " Sizes: " << start_rrt->configVector.size() << "/"
368 << goal_rrt->configVector.size() << std::endl;
369 }
370 }
371 }
372
373 // Maximum # of iterations are reached and path is not found - failed.
374 return false;
375}
376
377} // namespace planning
378} // namespace dart
379
380#endif // DART_PLANNING_PATHPLANNER_HPP_
CollisionResult * result
Collision result of DART.
Definition FCLCollisionDetector.cpp:160
void setPositions(const Eigen::VectorXd &_positions)
Set the positions for all generalized coordinates.
Definition MetaSkeleton.cpp:398
Eigen::VectorXd getPositions() const
Get the positions for all generalized coordinates.
Definition MetaSkeleton.cpp:413
class Skeleton
Definition Skeleton.hpp:59
The path planner class - a common interface to motion planners.
Definition PathPlanner.hpp:63
virtual ~PathPlanner()
The destructor.
Definition PathPlanner.hpp:106
PathPlanner(simulation::World &world, bool bidirectional_=true, bool connect_=true, double stepSize_=0.1, std::size_t maxNodes_=1e6, double goalBias_=0.3)
The desired constructor - you should use this one.
Definition PathPlanner.hpp:89
bool planBidirectionalRrt(dynamics::Skeleton *robot, const std::vector< int > &dofs, const std::vector< Eigen::VectorXd > &start, const std::vector< Eigen::VectorXd > &goal, std::list< Eigen::VectorXd > &path)
Performs bidirectional RRT with the given options.
Definition PathPlanner.hpp:290
std::size_t maxNodes
Maximum number of iterations the sampling would continue.
Definition PathPlanner.hpp:73
R * goal_rrt
The second rrt if bidirectional search is executed.
Definition PathPlanner.hpp:80
bool planPath(dynamics::Skeleton *robot, const std::vector< int > &dofs, const Eigen::VectorXd &start, const Eigen::VectorXd &goal, std::list< Eigen::VectorXd > &path)
Plan a path from a single start configuration to a single goal.
Definition PathPlanner.hpp:111
simulation::WorldPtr world
The world that the robot is in (for obstacles and etc.)
Definition PathPlanner.hpp:75
bool bidirectional
Whether two trees try to meet each other or one goes for the goal.
Definition PathPlanner.hpp:66
double goalBias
Choose btw goal and random value (for goal-biased search)
Definition PathPlanner.hpp:71
PathPlanner()
The default constructor.
Definition PathPlanner.hpp:84
double stepSize
Step size from a node in the tree to the random/goal node.
Definition PathPlanner.hpp:69
bool planSingleTreeRrt(dynamics::Skeleton *robot, const std::vector< int > &dofs, const std::vector< Eigen::VectorXd > &start, const Eigen::VectorXd &goal, std::list< Eigen::VectorXd > &path)
Performs a unidirectional RRT with the given options.
Definition PathPlanner.hpp:231
bool connect
Whether we take a small step or shoot for the target node.
Definition PathPlanner.hpp:65
R * start_rrt
The rrt for unidirectional search.
Definition PathPlanner.hpp:79
class World
Definition World.hpp:84
std::shared_ptr< World > WorldPtr
Definition SmartPointer.hpp:41
Definition BulletCollisionDetector.cpp:65
const bool debug
Definition urdf_world_parser.cpp:52