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