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
33 // Algorithm details and publications: http://www.golems.org/node/1570
34
35 #include "dart/planning/PathFollowingTrajectory.hpp"
36
37 #include <fstream>
38 #include <iostream>
39 #include <limits>
40
41 using namespace Eigen;
42 using namespace std;
43
44 namespace dart {
45 namespace planning {
46
47 const double PathFollowingTrajectory::timeStep = 0.001;
48 const double PathFollowingTrajectory::eps = 0.000001;
49
50 // static double squared(double d) {
51 // return d * d;
52 // }
53
PathFollowingTrajectory(const Path & path,const VectorXd & maxVelocity,const VectorXd & maxAcceleration)54 PathFollowingTrajectory::PathFollowingTrajectory(
55 const Path& path,
56 const VectorXd& maxVelocity,
57 const VectorXd& maxAcceleration)
58 : path(path),
59 maxVelocity(maxVelocity),
60 maxAcceleration(maxAcceleration),
61 n(maxVelocity.size()),
62 valid(true),
63 cachedTime(numeric_limits<double>::max())
64 {
65 // debug
66 //{
67 // ofstream file("maxVelocity.txt");
68 // for(double s = 0.0; s < path.getLength(); s += 0.0001) {
69 // double maxVelocity = getAccelerationMaxPathVelocity(s);
70 // if(maxVelocity == numeric_limits<double>::infinity())
71 // maxVelocity = 10.0;
72 // file << s << " " << maxVelocity << " " << getVelocityMaxPathVelocity(s)
73 //<< endl;
74 //}
75 // file.close();
76 //}
77
78 list<TrajectoryStep> startTrajectory;
79 startTrajectory.push_back(TrajectoryStep(0.0, 0.0));
80 double afterAcceleration = getMinMaxPathAcceleration(0.0, 0.0, true);
81 while (!integrateForward(startTrajectory, afterAcceleration) && valid)
82 {
83 double beforeAcceleration;
84 TrajectoryStep switchingPoint;
85 if (getNextSwitchingPoint(
86 startTrajectory.back().pathPos,
87 switchingPoint,
88 beforeAcceleration,
89 afterAcceleration))
90 {
91 break;
92 }
93 // cout << "set arrow from " << switchingPoint.pathPos << ", " <<
94 // switchingPoint.pathVel - 0.8 << " to " << switchingPoint.pathPos << ", "
95 // << switchingPoint.pathVel - 0.3 << endl;
96 list<TrajectoryStep> trajectory;
97 trajectory.push_back(switchingPoint);
98 integrateBackward(trajectory, startTrajectory, beforeAcceleration);
99 }
100
101 list<TrajectoryStep> endTrajectory;
102 endTrajectory.push_front(TrajectoryStep(path.getLength(), 0.0));
103 double beforeAcceleration
104 = getMinMaxPathAcceleration(path.getLength(), 0.0, false);
105 integrateBackward(endTrajectory, startTrajectory, beforeAcceleration);
106
107 this->trajectory = startTrajectory;
108
109 // calculate timing
110 list<TrajectoryStep>::iterator previous = trajectory.begin();
111 list<TrajectoryStep>::iterator it = previous;
112 it->time = 0.0;
113 ++it;
114 while (it != trajectory.end())
115 {
116 it->time = previous->time
117 + (it->pathPos - previous->pathPos)
118 / ((it->pathVel + previous->pathVel) / 2.0);
119 previous = it;
120 ++it;
121 }
122
123 // debug
124 // ofstream file("trajectory.txt");
125 // for(list<TrajectoryStep>::iterator it = trajectory.begin(); it !=
126 // trajectory.end(); it++) { file << it->pathPos << " " << it->pathVel <<
127 // endl;
128 //}
129 // file.close();
130 }
131
~PathFollowingTrajectory(void)132 PathFollowingTrajectory::~PathFollowingTrajectory(void)
133 {
134 }
135
136 // returns true if end of path is reached.
getNextSwitchingPoint(double pathPos,TrajectoryStep & nextSwitchingPoint,double & beforeAcceleration,double & afterAcceleration)137 bool PathFollowingTrajectory::getNextSwitchingPoint(
138 double pathPos,
139 TrajectoryStep& nextSwitchingPoint,
140 double& beforeAcceleration,
141 double& afterAcceleration)
142 {
143 TrajectoryStep accelerationSwitchingPoint(pathPos, 0.0);
144 double accelerationBeforeAcceleration, accelerationAfterAcceleration;
145 bool accelerationReachedEnd;
146 do
147 {
148 accelerationReachedEnd = getNextAccelerationSwitchingPoint(
149 accelerationSwitchingPoint.pathPos,
150 accelerationSwitchingPoint,
151 accelerationBeforeAcceleration,
152 accelerationAfterAcceleration);
153 // double test =
154 // getVelocityMaxPathVelocity(accelerationSwitchingPoint.pathPos);
155 } while (
156 !accelerationReachedEnd
157 && accelerationSwitchingPoint.pathVel
158 > getVelocityMaxPathVelocity(accelerationSwitchingPoint.pathPos));
159
160 TrajectoryStep velocitySwitchingPoint(pathPos, 0.0);
161 double velocityBeforeAcceleration, velocityAfterAcceleration;
162 bool velocityReachedEnd;
163 do
164 {
165 velocityReachedEnd = getNextVelocitySwitchingPoint(
166 velocitySwitchingPoint.pathPos,
167 velocitySwitchingPoint,
168 velocityBeforeAcceleration,
169 velocityAfterAcceleration);
170 } while (!velocityReachedEnd
171 && velocitySwitchingPoint.pathPos
172 <= accelerationSwitchingPoint.pathPos
173 && (velocitySwitchingPoint.pathVel
174 > getAccelerationMaxPathVelocity(
175 velocitySwitchingPoint.pathPos - eps)
176 || velocitySwitchingPoint.pathVel
177 > getAccelerationMaxPathVelocity(
178 velocitySwitchingPoint.pathPos + eps)));
179
180 if (accelerationReachedEnd && velocityReachedEnd)
181 {
182 return true;
183 }
184 else if (
185 !accelerationReachedEnd
186 && (velocityReachedEnd
187 || accelerationSwitchingPoint.pathPos
188 <= velocitySwitchingPoint.pathPos))
189 {
190 nextSwitchingPoint = accelerationSwitchingPoint;
191 beforeAcceleration = accelerationBeforeAcceleration;
192 afterAcceleration = accelerationAfterAcceleration;
193 return false;
194 }
195 else
196 {
197 nextSwitchingPoint = velocitySwitchingPoint;
198 beforeAcceleration = velocityBeforeAcceleration;
199 afterAcceleration = velocityAfterAcceleration;
200 return false;
201 }
202 }
203
getNextAccelerationSwitchingPoint(double pathPos,TrajectoryStep & nextSwitchingPoint,double & beforeAcceleration,double & afterAcceleration)204 bool PathFollowingTrajectory::getNextAccelerationSwitchingPoint(
205 double pathPos,
206 TrajectoryStep& nextSwitchingPoint,
207 double& beforeAcceleration,
208 double& afterAcceleration)
209 {
210 double switchingPathPos = pathPos;
211 double switchingPathVel;
212 while (true)
213 {
214 bool discontinuity;
215 switchingPathPos
216 = path.getNextSwitchingPoint(switchingPathPos, discontinuity);
217
218 if (switchingPathPos > path.getLength() - eps)
219 {
220 return true;
221 }
222
223 if (discontinuity)
224 {
225 const double beforePathVel
226 = getAccelerationMaxPathVelocity(switchingPathPos - eps);
227 const double afterPathVel
228 = getAccelerationMaxPathVelocity(switchingPathPos + eps);
229 switchingPathVel = min(beforePathVel, afterPathVel);
230 beforeAcceleration = getMinMaxPathAcceleration(
231 switchingPathPos - eps, switchingPathVel, false);
232 afterAcceleration = getMinMaxPathAcceleration(
233 switchingPathPos + eps, switchingPathVel, true);
234
235 if ((beforePathVel > afterPathVel
236 || getMinMaxPhaseSlope(
237 switchingPathPos - eps, switchingPathVel, false)
238 > getAccelerationMaxPathVelocityDeriv(
239 switchingPathPos - 2.0 * eps))
240 && (beforePathVel < afterPathVel
241 || getMinMaxPhaseSlope(
242 switchingPathPos + eps, switchingPathVel, true)
243 < getAccelerationMaxPathVelocityDeriv(
244 switchingPathPos + 2.0 * eps)))
245 {
246 break;
247 }
248 }
249 else
250 {
251 switchingPathVel = getAccelerationMaxPathVelocity(switchingPathPos);
252 beforeAcceleration = 0.0;
253 afterAcceleration = 0.0;
254
255 if (getAccelerationMaxPathVelocityDeriv(switchingPathPos - eps) < 0.0
256 && getAccelerationMaxPathVelocityDeriv(switchingPathPos + eps) > 0.0)
257 {
258 break;
259 }
260 }
261 }
262
263 nextSwitchingPoint = TrajectoryStep(switchingPathPos, switchingPathVel);
264 return false;
265 }
266
getNextVelocitySwitchingPoint(double pathPos,TrajectoryStep & nextSwitchingPoint,double & beforeAcceleration,double & afterAcceleration)267 bool PathFollowingTrajectory::getNextVelocitySwitchingPoint(
268 double pathPos,
269 TrajectoryStep& nextSwitchingPoint,
270 double& beforeAcceleration,
271 double& afterAcceleration)
272 {
273 const double stepSize = 0.001;
274 const double accuracy = 0.000001;
275
276 bool start = false;
277 pathPos -= stepSize;
278 do
279 {
280 pathPos += stepSize;
281
282 if (getMinMaxPhaseSlope(pathPos, getVelocityMaxPathVelocity(pathPos), false)
283 >= getVelocityMaxPathVelocityDeriv(pathPos))
284 {
285 start = true;
286 }
287 } while ((!start
288 || getMinMaxPhaseSlope(
289 pathPos, getVelocityMaxPathVelocity(pathPos), false)
290 > getVelocityMaxPathVelocityDeriv(pathPos))
291 && pathPos < path.getLength());
292
293 if (pathPos >= path.getLength())
294 {
295 return true; // end of trajectory reached
296 }
297
298 double beforePathPos = pathPos - stepSize;
299 double afterPathPos = pathPos;
300 while (afterPathPos - beforePathPos > accuracy)
301 {
302 pathPos = (beforePathPos + afterPathPos) / 2.0;
303 if (getMinMaxPhaseSlope(pathPos, getVelocityMaxPathVelocity(pathPos), false)
304 > getVelocityMaxPathVelocityDeriv(pathPos))
305 {
306 beforePathPos = pathPos;
307 }
308 else
309 {
310 afterPathPos = pathPos;
311 }
312 }
313
314 beforeAcceleration = getMinMaxPathAcceleration(
315 beforePathPos, getVelocityMaxPathVelocity(beforePathPos), false);
316 afterAcceleration = getMinMaxPathAcceleration(
317 afterPathPos, getVelocityMaxPathVelocity(afterPathPos), true);
318 nextSwitchingPoint
319 = TrajectoryStep(afterPathPos, getVelocityMaxPathVelocity(afterPathPos));
320 return false;
321 }
322
integrateForward(list<TrajectoryStep> & trajectory,double acceleration)323 bool PathFollowingTrajectory::integrateForward(
324 list<TrajectoryStep>& trajectory, double acceleration)
325 {
326
327 double pathPos = trajectory.back().pathPos;
328 double pathVel = trajectory.back().pathVel;
329
330 list<pair<double, bool> > switchingPoints = path.getSwitchingPoints();
331 list<pair<double, bool> >::iterator nextDiscontinuity
332 = switchingPoints.begin();
333
334 while (true)
335 {
336 if (pathPos > 1.304)
337 {
338 // int test = 48;
339 }
340
341 while (
342 nextDiscontinuity != switchingPoints.end()
343 && (nextDiscontinuity->first <= pathPos || !nextDiscontinuity->second))
344 {
345 ++nextDiscontinuity;
346 }
347
348 double oldPathPos = pathPos;
349 double oldPathVel = pathVel;
350
351 pathVel += timeStep * acceleration;
352 pathPos += timeStep * 0.5 * (oldPathVel + pathVel);
353
354 if (nextDiscontinuity != switchingPoints.end()
355 && pathPos > nextDiscontinuity->first)
356 {
357 pathVel = oldPathVel
358 + (nextDiscontinuity->first + eps - oldPathPos)
359 * (pathVel - oldPathVel) / (pathPos - oldPathPos);
360 pathPos = nextDiscontinuity->first + eps;
361 }
362
363 // pathVel += timeStep * acceleration;
364 // pathPos += timeStep * 0.5 * (oldPathVel + pathVel);
365
366 if (pathPos > path.getLength())
367 {
368 return true;
369 }
370 else if (pathVel < 0.0)
371 {
372 valid = false;
373 cout << "error" << endl;
374 return true;
375 }
376
377 // double test1 = getMinMaxPhaseSlope(oldPathPos,
378 // getVelocityMaxPathVelocity(oldPathPos), false); double test2 =
379 // getVelocityMaxPathVelocityDeriv(oldPathPos);
380
381 if (pathVel > getVelocityMaxPathVelocity(pathPos)
382 && getMinMaxPhaseSlope(
383 oldPathPos, getVelocityMaxPathVelocity(oldPathPos), false)
384 <= getVelocityMaxPathVelocityDeriv(oldPathPos))
385 {
386 pathVel = getVelocityMaxPathVelocity(pathPos);
387 }
388
389 trajectory.push_back(TrajectoryStep(pathPos, pathVel));
390 acceleration = getMinMaxPathAcceleration(pathPos, pathVel, true);
391
392 if (pathVel > getAccelerationMaxPathVelocity(pathPos)
393 || pathVel > getVelocityMaxPathVelocity(pathPos))
394 {
395 // find more accurate intersection with max-velocity curve using bisection
396 TrajectoryStep overshoot = trajectory.back();
397 trajectory.pop_back();
398 double slope = getSlope(trajectory.back(), overshoot);
399 double before = trajectory.back().pathPos;
400 double after = overshoot.pathPos;
401 while (after - before > 0.00001)
402 {
403 const double midpoint = 0.5 * (before + after);
404 double midpointPathVel
405 = trajectory.back().pathVel
406 + slope * (midpoint - trajectory.back().pathPos);
407
408 if (midpointPathVel > getVelocityMaxPathVelocity(midpoint)
409 && getMinMaxPhaseSlope(
410 before, getVelocityMaxPathVelocity(before), false)
411 <= getVelocityMaxPathVelocityDeriv(before))
412 {
413 midpointPathVel = getVelocityMaxPathVelocity(midpoint);
414 }
415
416 if (midpointPathVel > getAccelerationMaxPathVelocity(midpoint)
417 || midpointPathVel > getVelocityMaxPathVelocity(midpoint))
418 after = midpoint;
419 else
420 before = midpoint;
421 }
422 trajectory.push_back(TrajectoryStep(
423 before,
424 trajectory.back().pathVel
425 + slope * (before - trajectory.back().pathPos)));
426
427 if (getAccelerationMaxPathVelocity(after)
428 < getVelocityMaxPathVelocity(after))
429 {
430 if (after > nextDiscontinuity->first)
431 {
432 return false;
433 }
434 else if (
435 getMinMaxPhaseSlope(
436 trajectory.back().pathPos, trajectory.back().pathVel, true)
437 > getAccelerationMaxPathVelocityDeriv(trajectory.back().pathPos))
438 {
439 return false;
440 }
441 }
442 else
443 {
444 if (getMinMaxPhaseSlope(
445 trajectory.back().pathPos, trajectory.back().pathVel, false)
446 > getVelocityMaxPathVelocityDeriv(trajectory.back().pathPos))
447 {
448 return false;
449 }
450 }
451 }
452 }
453 }
454
integrateBackward(list<TrajectoryStep> & trajectory,list<TrajectoryStep> & startTrajectory,double acceleration)455 void PathFollowingTrajectory::integrateBackward(
456 list<TrajectoryStep>& trajectory,
457 list<TrajectoryStep>& startTrajectory,
458 double acceleration)
459 {
460 list<TrajectoryStep>::reverse_iterator before = startTrajectory.rbegin();
461 double pathPos = trajectory.front().pathPos;
462 double pathVel = trajectory.front().pathVel;
463
464 while (true)
465 {
466 // pathPos -= timeStep * pathVel;
467 // pathVel -= timeStep * acceleration;
468
469 double oldPathVel = pathVel;
470 pathVel -= timeStep * acceleration;
471 pathPos -= timeStep * 0.5 * (oldPathVel + pathVel);
472
473 trajectory.push_front(TrajectoryStep(pathPos, pathVel));
474 acceleration = getMinMaxPathAcceleration(pathPos, pathVel, false);
475
476 if (pathVel < 0.0 || pathPos < 0.0)
477 {
478 valid = false;
479 cout << "error " << pathPos << " " << pathVel << endl;
480 return;
481 }
482
483 while (before != startTrajectory.rend() && before->pathPos > pathPos)
484 {
485 ++before;
486 }
487
488 bool error = false;
489
490 if (before != startTrajectory.rbegin()
491 && pathVel
492 >= before->pathVel
493 + getSlope(before.base()) * (pathPos - before->pathPos))
494 {
495 TrajectoryStep overshoot = trajectory.front();
496 trajectory.pop_front();
497 list<TrajectoryStep>::iterator after = before.base();
498 TrajectoryStep intersection = getIntersection(
499 startTrajectory, after, overshoot, trajectory.front());
500 // cout << "set arrow from " << intersection.pathPos << ", " <<
501 // intersection.pathVel - 0.8 << " to " << intersection.pathPos << ", " <<
502 // intersection.pathVel - 0.3 << endl;
503
504 if (after != startTrajectory.end())
505 {
506 startTrajectory.erase(after, startTrajectory.end());
507 startTrajectory.push_back(intersection);
508 }
509 startTrajectory.splice(startTrajectory.end(), trajectory);
510
511 return;
512 }
513 else if (
514 pathVel > getAccelerationMaxPathVelocity(pathPos) + eps
515 || pathVel > getVelocityMaxPathVelocity(pathPos) + eps)
516 {
517 // find more accurate intersection with max-velocity curve using bisection
518 TrajectoryStep overshoot = trajectory.front();
519 trajectory.pop_front();
520 double slope = getSlope(overshoot, trajectory.front());
521 double before = overshoot.pathPos;
522 double after = trajectory.front().pathPos;
523 while (after - before > 0.00001)
524 {
525 const double midpoint = 0.5 * (before + after);
526 double midpointPathVel
527 = overshoot.pathVel + slope * (midpoint - overshoot.pathPos);
528
529 if (midpointPathVel > getAccelerationMaxPathVelocity(midpoint)
530 || midpointPathVel > getVelocityMaxPathVelocity(midpoint))
531 before = midpoint;
532 else
533 after = midpoint;
534 }
535 trajectory.push_front(TrajectoryStep(
536 after, overshoot.pathVel + slope * (after - overshoot.pathPos)));
537
538 if (getAccelerationMaxPathVelocity(before)
539 < getVelocityMaxPathVelocity(before))
540 {
541 if (trajectory.front().pathVel
542 > getAccelerationMaxPathVelocity(before) + 0.0001)
543 {
544 error = true;
545 }
546 else if (
547 getMinMaxPhaseSlope(
548 trajectory.front().pathPos, trajectory.front().pathVel, false)
549 < getAccelerationMaxPathVelocityDeriv(trajectory.front().pathPos))
550 {
551 error = true;
552 }
553 }
554 else
555 {
556 if (getMinMaxPhaseSlope(
557 trajectory.back().pathPos, trajectory.back().pathVel, false)
558 < getVelocityMaxPathVelocityDeriv(trajectory.back().pathPos))
559 {
560 error = true;
561 }
562 }
563 }
564
565 if (error)
566 {
567 ofstream file("trajectory.txt");
568 for (list<TrajectoryStep>::iterator it = startTrajectory.begin();
569 it != startTrajectory.end();
570 ++it)
571 {
572 file << it->pathPos << " " << it->pathVel << endl;
573 }
574 for (list<TrajectoryStep>::iterator it = trajectory.begin();
575 it != trajectory.end();
576 ++it)
577 {
578 file << it->pathPos << " " << it->pathVel << endl;
579 }
580 file.close();
581 cout << "error" << endl;
582 valid = false;
583 return;
584 }
585 }
586 }
587
getSlope(const TrajectoryStep & point1,const TrajectoryStep & point2)588 inline double PathFollowingTrajectory::getSlope(
589 const TrajectoryStep& point1, const TrajectoryStep& point2)
590 {
591 return (point2.pathVel - point1.pathVel) / (point2.pathPos - point1.pathPos);
592 }
593
getSlope(list<TrajectoryStep>::const_iterator lineEnd)594 inline double PathFollowingTrajectory::getSlope(
595 list<TrajectoryStep>::const_iterator lineEnd)
596 {
597 list<TrajectoryStep>::const_iterator lineStart = lineEnd;
598 --lineStart;
599 return getSlope(*lineStart, *lineEnd);
600 }
601
602 PathFollowingTrajectory::TrajectoryStep
getIntersection(const list<TrajectoryStep> & trajectory,list<TrajectoryStep>::iterator & it,const TrajectoryStep & linePoint1,const TrajectoryStep & linePoint2)603 PathFollowingTrajectory::getIntersection(
604 const list<TrajectoryStep>& trajectory,
605 list<TrajectoryStep>::iterator& it,
606 const TrajectoryStep& linePoint1,
607 const TrajectoryStep& linePoint2)
608 {
609
610 const double lineSlope = getSlope(linePoint1, linePoint2);
611 it--;
612
613 double factor = 1.0;
614 if (it->pathVel
615 > linePoint1.pathVel + lineSlope * (it->pathPos - linePoint1.pathPos))
616 factor = -1.0;
617 it++;
618
619 while (it != trajectory.end()
620 && factor * it->pathVel
621 < factor
622 * (linePoint1.pathVel
623 + lineSlope * (it->pathPos - linePoint1.pathPos)))
624 {
625 it++;
626 }
627
628 if (it == trajectory.end())
629 {
630 return TrajectoryStep(0.0, 0.0);
631 }
632 else
633 {
634 const double trajectorySlope = getSlope(it);
635 const double intersectionPathPos
636 = (it->pathVel - linePoint1.pathVel + lineSlope * linePoint1.pathPos
637 - trajectorySlope * it->pathPos)
638 / (lineSlope - trajectorySlope);
639 const double intersectionPathVel
640 = linePoint1.pathVel
641 + lineSlope * (intersectionPathPos - linePoint1.pathPos);
642 return TrajectoryStep(intersectionPathPos, intersectionPathVel);
643 }
644 }
645
getMinMaxPathAcceleration(double pathPos,double pathVel,bool max)646 double PathFollowingTrajectory::getMinMaxPathAcceleration(
647 double pathPos, double pathVel, bool max)
648 {
649 VectorXd configDeriv = path.getTangent(pathPos);
650 VectorXd configDeriv2 = path.getCurvature(pathPos);
651 double factor = max ? 1.0 : -1.0;
652 double maxPathAcceleration = numeric_limits<double>::max();
653 for (unsigned int i = 0; i < n; i++)
654 {
655 if (configDeriv[i] != 0.0)
656 {
657 maxPathAcceleration = min(
658 maxPathAcceleration,
659 maxAcceleration[i] / std::abs(configDeriv[i])
660 - factor * configDeriv2[i] * pathVel * pathVel / configDeriv[i]);
661 }
662 }
663 return factor * maxPathAcceleration;
664 }
665
getMinMaxPhaseSlope(double pathPos,double pathVel,bool max)666 double PathFollowingTrajectory::getMinMaxPhaseSlope(
667 double pathPos, double pathVel, bool max)
668 {
669 return getMinMaxPathAcceleration(pathPos, pathVel, max) / pathVel;
670 }
671
getAccelerationMaxPathVelocity(double pathPos)672 double PathFollowingTrajectory::getAccelerationMaxPathVelocity(double pathPos)
673 {
674 double maxPathVelocity = numeric_limits<double>::infinity();
675 const VectorXd configDeriv = path.getTangent(pathPos);
676 const VectorXd configDeriv2 = path.getCurvature(pathPos);
677 for (unsigned int i = 0; i < n; i++)
678 {
679 if (configDeriv[i] != 0.0)
680 {
681 for (unsigned int j = i + 1; j < n; j++)
682 {
683 if (configDeriv[j] != 0.0)
684 {
685 double A_ij = configDeriv2[i] / configDeriv[i]
686 - configDeriv2[j] / configDeriv[j];
687 if (A_ij != 0.0)
688 {
689 maxPathVelocity = min(
690 maxPathVelocity,
691 sqrt(
692 (maxAcceleration[i] / std::abs(configDeriv[i])
693 + maxAcceleration[j] / std::abs(configDeriv[j]))
694 / std::abs(A_ij)));
695 }
696 }
697 }
698 }
699 else if (configDeriv2[i] != 0.0)
700 {
701 maxPathVelocity = min(
702 maxPathVelocity,
703 sqrt(maxAcceleration[i] / std::abs(configDeriv2[i])));
704 }
705 }
706 return maxPathVelocity;
707 }
708
getVelocityMaxPathVelocity(double pathPos)709 double PathFollowingTrajectory::getVelocityMaxPathVelocity(double pathPos)
710 {
711 const VectorXd tangent = path.getTangent(pathPos);
712 double maxPathVelocity = numeric_limits<double>::max();
713 for (unsigned int i = 0; i < n; i++)
714 {
715 maxPathVelocity
716 = min(maxPathVelocity, maxVelocity[i] / std::abs(tangent[i]));
717 }
718 return maxPathVelocity;
719 }
720
getAccelerationMaxPathVelocityDeriv(double pathPos)721 double PathFollowingTrajectory::getAccelerationMaxPathVelocityDeriv(
722 double pathPos)
723 {
724 return (getAccelerationMaxPathVelocity(pathPos + eps)
725 - getAccelerationMaxPathVelocity(pathPos - eps))
726 / (2.0 * eps);
727 }
728
getVelocityMaxPathVelocityDeriv(double pathPos)729 double PathFollowingTrajectory::getVelocityMaxPathVelocityDeriv(double pathPos)
730 {
731 const VectorXd tangent = path.getTangent(pathPos);
732 double maxPathVelocity = numeric_limits<double>::max();
733 unsigned int activeConstraint = 0;
734 for (unsigned int i = 0; i < n; i++)
735 {
736 const double thisMaxPathVelocity = maxVelocity[i] / std::abs(tangent[i]);
737 if (thisMaxPathVelocity < maxPathVelocity)
738 {
739 maxPathVelocity = thisMaxPathVelocity;
740 activeConstraint = i;
741 }
742 }
743 return -(maxVelocity[activeConstraint]
744 * path.getCurvature(pathPos)[activeConstraint])
745 / (tangent[activeConstraint] * std::abs(tangent[activeConstraint]));
746 }
747
isValid() const748 bool PathFollowingTrajectory::isValid() const
749 {
750 return valid;
751 }
752
getDuration() const753 double PathFollowingTrajectory::getDuration() const
754 {
755 return trajectory.back().time;
756 }
757
758 list<PathFollowingTrajectory::TrajectoryStep>::const_iterator
getTrajectorySegment(double time) const759 PathFollowingTrajectory::getTrajectorySegment(double time) const
760 {
761 if (time >= trajectory.back().time)
762 {
763 list<TrajectoryStep>::const_iterator last = trajectory.end();
764 --last;
765 return last;
766 }
767 else
768 {
769 if (time < cachedTime)
770 {
771 cachedTrajectorySegment = trajectory.begin();
772 }
773 while (time >= cachedTrajectorySegment->time)
774 {
775 ++cachedTrajectorySegment;
776 }
777 cachedTime = time;
778 return cachedTrajectorySegment;
779 }
780 }
781
getPosition(double time) const782 VectorXd PathFollowingTrajectory::getPosition(double time) const
783 {
784 list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
785 list<TrajectoryStep>::const_iterator previous = it;
786 --previous;
787
788 // const double pathPos = previous->pathPos + (time - previous->time) *
789 // (previous->pathVel + it->pathVel) / 2.0;
790
791 double timeStep = it->time - previous->time;
792 const double acceleration
793 = (it->pathPos - previous->pathPos - timeStep * previous->pathVel)
794 / (timeStep * timeStep);
795
796 timeStep = time - previous->time;
797 const double pathPos = previous->pathPos + timeStep * previous->pathVel
798 + timeStep * timeStep * acceleration;
799
800 return path.getConfig(pathPos);
801 }
802
getVelocity(double time) const803 VectorXd PathFollowingTrajectory::getVelocity(double time) const
804 {
805 list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
806 list<TrajectoryStep>::const_iterator previous = it;
807 --previous;
808
809 // const double pathPos = previous->pathPos + (time - previous->time) *
810 // (previous->pathVel + it->pathVel) / 2.0;
811
812 double timeStep = it->time - previous->time;
813 const double acceleration
814 = (it->pathPos - previous->pathPos - timeStep * previous->pathVel)
815 / (timeStep * timeStep);
816
817 timeStep = time - previous->time;
818 const double pathPos = previous->pathPos + timeStep * previous->pathVel
819 + timeStep * timeStep * acceleration;
820 const double pathVel = previous->pathVel + timeStep * acceleration;
821
822 return path.getTangent(pathPos) * pathVel;
823 }
824
getMaxAccelerationError()825 double PathFollowingTrajectory::getMaxAccelerationError()
826 {
827 double maxAccelerationError = 0.0;
828
829 for (double time = 0.0; time < getDuration(); time += 0.000001)
830 {
831 list<TrajectoryStep>::const_iterator it = getTrajectorySegment(time);
832 list<TrajectoryStep>::const_iterator previous = it;
833 --previous;
834
835 double timeStep = it->time - previous->time;
836 const double pathAcceleration
837 = (it->pathPos - previous->pathPos - timeStep * previous->pathVel)
838 / (timeStep * timeStep);
839
840 timeStep = time - previous->time;
841 const double pathPos = previous->pathPos + timeStep * previous->pathVel
842 + timeStep * timeStep * pathAcceleration;
843
844 const double pathVel = previous->pathVel + timeStep * pathAcceleration;
845
846 VectorXd acceleration = path.getTangent(pathPos) * pathAcceleration
847 + path.getCurvature(pathPos) * pathVel * pathVel;
848
849 for (int i = 0; i < acceleration.size(); i++)
850 {
851 if (std::abs(acceleration[i]) > maxAcceleration[i])
852 {
853 maxAccelerationError = max(
854 maxAccelerationError,
855 std::abs(acceleration[i]) / maxAcceleration[i]);
856 }
857 }
858 }
859
860 return maxAccelerationError;
861 }
862
863 } // namespace planning
864 } // namespace dart
865