1 // Copyright 2009, 2010 Michal Sojka <sojkam1@fel.cvut.cz>
2 // Copyright 2009 Petr Beneš
4 // This file is part of Trgen library.
6 // Trgen is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // Trgen is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Trgen. If not, see <http://www.gnu.org/licenses/>.
21 * @author Michal Sojka, Petr Beneš
22 * @date Sun Aug 12 09:59:32 2007
24 * @brief Trajectory Generator
38 // #ifdef MATLAB_MEX_FILE
39 // #define S_FUNCTION_LEVEL 2
40 // #define S_FUNCTION_NAME sf_trgen
41 // #include "simstruc.h"
44 using namespace Segment;
47 * Split a sergment and add the newly created segment to the
50 * @param seg Segment to split.
51 * @param time Where to split.
56 Trajectory::splitSegmentByTime(iterator &seg, double time)
58 TrajectorySegment *ns;
60 if (typeid(**seg) != typeid(Turn))
63 ns = (*seg)->splitAtByTime(time, np);
70 wayPoints.push_back(np);
71 seg = insert(++seg, ns);
77 * Split a sergment and add the newly created segment to the
80 * @param seg Segment to split.
81 * @param distance Where to split.
86 Trajectory::splitSegment(iterator &seg, double distance)
88 TrajectorySegment *ns;
90 if (typeid(**seg) != typeid(Turn))
93 ns = (*seg)->splitAt(distance, np);
100 wayPoints.push_back(np);
101 seg = insert(++seg, ns);
105 // iterator insert(reverse_iterator it, const value_type& val) {
106 // return insert((--it).base(), val);
110 * Connects points by line segments.
113 Trajectory::points2segments()
115 TrajectoryPoints::iterator p1, p2, p3;
116 Point ip(initPos.x, initPos.y);
119 if (*wayPoints.front() != ip) {
120 initialPoint = new Point(ip);
121 wayPoints.push_front(initialPoint);
123 initialPoint = wayPoints.front();
126 // Delete old segments
129 if (wayPoints.size() < 2 &&
130 (finalHeading.turn_type == FH_DONT_TURN ||
131 (finalHeading.turn_type == FH_SHORTEST && \
132 fabs(initPos.phi - finalHeading.heading) < 1.0/180*M_PI))) {
136 if (wayPoints.size() >= 3) {
137 // be aware of two identical points, you can not measure any angle, so delete one of them
138 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin(); p2 != wayPoints.end(); p1++, p2++) {
139 if ((*p1)->distanceTo(**p2) < 0.001) {
142 sprintf(ccc, "#One of identical points x %lf y %lf erased\n", (*p2)->x, (*p2)->y);
145 p2 = wayPoints.erase(p2);
149 // For avoiding too sharp turns than a constant we add one point to the right angle, so that
150 // we obtain two bigger angles instead of one very small. This point is so close to the original one
151 // and should not affect the trajectory from the macroscopical point of view.
152 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin(), p3 = ++wayPoints.begin(), ++p3;
153 p3 != wayPoints.end();
155 edge = fabs((*p2)->angleTo(**p1) - (*p2)->angleTo(**p3));
157 edge = (2*M_PI) - edge;
158 if (edge*180/M_PI < 3.0)
160 edge = (*p2)->angleTo(**p1) + M_PI/2.0;
161 Point *pt = new Point ((*p2)->x + cos(edge)*0.025, (*p2)->y + sin(edge)*0.025);
162 wayPoints.insert(p2, pt);
165 sprintf(ccc, "#Sharp edge smoothed %lf %lf, %lf %lf, %lf %lf\n",
166 (**p1).x, (**p1).y, (**p2).x, (**p2).y, (**p3).x, (**p3).y);
175 for (p1 = wayPoints.begin(); p1 != wayPoints.end(); p1++) {
176 sprintf(c, "#wayPoints: x %lf y %lf\n", (*p1)->x, (*p1)->y);
181 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin();
182 p2 != wayPoints.end();
184 push_back(new Line(*p1, *p2));
191 * Converts corners in trajectory to arcs.
195 // \frame{\begin{tikzpicture}
196 // \draw (-5cm,0) coordinate(p1) node[left]{$p_1$} --
197 // node[sloped,above]{$\mathrm seg_1$} (0,0) coordinate(p2)
198 // node[above]{$p_2$} -- node[sloped,above]{$\mathrm seg_2$} +(-30:5cm)
199 // node[right]{$p_3$} coordinate (p3);
200 // \coordinate[shift=(-105:5cm)] (c) at (p2);
201 // \draw (p2) -- (c);
202 // \draw (c) -- (c |- p2);
203 // \draw (c) -- (intersection of c--40:10cm and p2--p3);
204 // \end{tikzpicture}}
209 Trajectory::corners2arcs()
211 iterator seg, segNext, segPrev;
213 if (size() < 2) return;
215 // Find radiuses to meet e <= maxe
216 for (segPrev = begin(), segNext = ++begin();
218 segPrev++, segNext++) {
220 double alpha; // curve angle (-pi <= alpha <= +pi)
221 double r; // radius of proposed arc. (alpha < 0 -> r < 0)
222 double s; // length of the segment replaced by the arc (s > 0)
224 alpha = dynamic_cast<Line*>(*segNext)->getAngle() -
225 dynamic_cast<Line*>(*segPrev)->getAngle();
226 if (alpha > +M_PI) alpha -= 2.0*M_PI;
227 if (alpha < -M_PI) alpha += 2.0*M_PI;
229 if (fabs(alpha) < M_PI/180.0) continue;
231 r = constr.maxe / (1/cos(alpha/2.0) - 1);
232 if (alpha < 0) r = -r;
233 s = r*tan(alpha/2.0);
234 if (s > (*segPrev)->getLength()) {
235 s = (*segPrev)->getLength();
236 r = s/tan(alpha/2.0);
238 if (s > (*segNext)->getLength()) {
239 s = (*segNext)->getLength();
240 r = s/tan(alpha/2.0);
244 (*segPrev)->alphahalf = alpha/2.0;
246 catch (std::exception& e) {} // Skip wrong dynamic_cast
250 // Reduce overlapping arcs by decreasing radiuses
251 double s1, s2, r1, r2, l, alphahalf1, alphahalf2;
253 for (segPrev = begin(), segNext = ++begin();
255 segPrev++, segNext++) {
256 l = (*segNext)->getLength();
261 alphahalf1 = (*segPrev)->alphahalf;
262 alphahalf2 = (*segNext)->alphahalf;
264 if (fabs(r1) > fabs(r2)) {
266 r1 = s1/tan(alphahalf1);
267 wantSameR = (fabs(r1) < fabs(r2));
270 r2 = s2/tan(alphahalf2);
271 wantSameR = (fabs(r1) > fabs(r2));
274 if (alphahalf1 < 0 ^ alphahalf2 < 0)
275 s1 = l*tan(alphahalf1)/(tan(alphahalf1)-tan(alphahalf2));
277 s1 = l*tan(alphahalf1)/(tan(alphahalf1)+tan(alphahalf2));
279 r1 = s1/tan(alphahalf1);
280 r2 = s2/tan(alphahalf2);
290 // replace corners by arcs with previously computed radiuses
291 for (segPrev = begin(), segNext = ++begin();
293 ++segPrev, ++segNext) {
294 if (fabs((*segPrev)->r) > 0) {
295 Point *newEnd1, *newEnd2;
296 double s = (*segPrev)->s;
297 newEnd1 = new Point();
298 newEnd2 = new Point();
299 (*segPrev)->shortenBy(+s, newEnd1);
300 (*segNext)->shortenBy(-s, newEnd2);
301 wayPoints.push_back(newEnd1);
302 wayPoints.push_back(newEnd2);
303 segPrev = insert(segNext, new Arc(newEnd1, newEnd2,
308 //delete zero-length segments
310 while (seg != end()) {
311 if ((*seg)->getLength() <= 1e-9) {
321 * Converts corners in trajectory to splines.
322 * The algorithm finds the smaller of two neighbour lines,
323 * grabs a half of it's length, than approximation constraint shortens this distance.
324 * This distance is replaced by a symetric spline curve.
327 Trajectory::corners2splines()
329 #ifdef MATLAB_MEX_FILE
330 mexEvalString("disp('...preparing spline...')");
333 iterator seg, segNext, segPrev;
334 double origLen = -1.0; // length of segment segPrev before being cut off
336 if (size() < 2) return;
338 for (segPrev = begin(), segNext = ++begin();
340 ++segPrev, ++segNext)
342 Point *newEnd1, *newEnd2, *edge;
344 newEnd1 = new Point();
345 newEnd2 = new Point();
347 double dst; // distance to cut off from both Lines
350 dst = fmin((*segPrev)->getLength(), (*segNext)->getLength()) * 0.5;
352 dst = fmin(origLen, (*segNext)->getLength()) * 0.5;
354 // just to count the angle between lines
355 (*segPrev)->getPointAt((*segPrev)->getLength(), edge);
356 (*segPrev)->getPointAt(-dst, newEnd1);
357 (*segNext)->getPointAt(dst, newEnd2);
359 // shorten dst according to constraint maxe
360 double ang = fabs(edge->angleTo(*newEnd1) - edge->angleTo(*newEnd2));
362 ang = (2.0*M_PI) - ang;
363 double e; // distance from the spline to edge
364 const double C0 = 0.892303;
365 const double C1 = -0.008169;
366 const double C2 = 1.848555E-05;
368 // experimental relation, but good enough
369 // see Matlab m-file 'splines/constr_maxe.m'
370 e = (C2*pow(ang*180.0/M_PI, 2) + C1*(ang*180.0/M_PI) + C0) * dst;
372 if (e > constr.maxe && !(segPrev == begin() && contains_inertial))
373 dst = dst * (constr.maxe/e);
375 origLen = (*segNext)->getLength();
377 (*segPrev)->getPointAt((*segPrev)->getLength(), edge);
378 (*segPrev)->shortenBy(+dst, newEnd1);
379 (*segNext)->shortenBy(-dst, newEnd2);
380 wayPoints.push_back(newEnd1);
381 wayPoints.push_back(newEnd2);
382 segPrev = insert(segNext, new Spline(newEnd1, newEnd2, edge));
385 sprintf(c, "#splineToBeCounted: begin %lf %lf end %lf %lf edge %lf %lf\n",
386 newEnd1->x, newEnd1->y, newEnd2->x, newEnd2->y, edge->x, edge->y);
392 TrajectoryPoints::iterator p1;
394 for (p1 = wayPoints.begin(); p1 != wayPoints.end(); p1++) {
395 sprintf(c, "#wayPointsSplined: x %lf y %lf\n", (*p1)->x, (*p1)->y);
400 //delete zero-length segments
402 while (seg != end()) {
404 if ((*seg)->getLength() <= 1e-9) {
415 * Assigns speeds and accelerations to segments; tries to maximize
416 * speed where possible. If necessary it also splits long segments
417 * to multiple parts with maximum acceleration/deceleration and
418 * maximal speed. The optimization is done in three passes. In the
419 * first pass, maximal speed of segments are set up (see
420 * TrajectoryConstraints::maxv, TrajectoryConstraints::maxomega,
421 * TrajectoryConstraints::maxcenacc). Then follows a forward pass, where
422 * acceleration is added to join segments with increasing maximal
423 * speeds. Finally, backward pass does almost the same by adding
424 * deceleration segments.
426 * Finding the split point of the segment where deceleration
427 * immediately follows acceleration is based on the following
430 * For uniformly accelerated motion, we can calculate time as
431 * function of speed: \f[ t(v)=\frac{v-v_0}{a}\f] Using this, we can
432 * express distance \f$ s \f$ as a function of speed: \f[ s(v) =
433 * \frac{1}{2} at(v)^2 + v_0 t(v) = \frac{v^2 - v_0^2}{2a}\f]
435 * Then, distance traveled during acceleration (\f$ s_1 \f$) and
436 * deceleration (\f$ s_2 \f$) must be equal to the length of the
437 * segment \f$ l = s_1 + s_2 \f$. Considering a segment with initial
438 * speed \f$ v_1 \f$, final speed \f$ v_2 \f$, and maximal speed (in
439 * the split point) \f$ v_{max} \f$, we can derive: \f[ l =
440 * s_1(v_{max}) + s_2(v_{max}) = \frac{2v_{max}^2 - v_1^2 - v_2^2}{2a}
441 * \f] \f[ v_{max}^2 = al + \frac{v_1^2 + v_2^2}{2} \f]
443 * Then, the length of the segment before split is: \f[ s_1 = l - s_2
444 * = l - \frac{v_{max}^2-v_2^2}{2a} = \frac{1}{2}l + \frac{v_2^2 -
447 * --- SPLINE UPDATE: The algorithm works nearly the same as before and is
448 * possible to use with splines. However, spline segments are not being
449 * cut off, but only their acceleration profiles change to ensure speed
450 * connectivity. This is not time optimal, but time loss is small enough,
451 * we avoid a lot of difficulties and keep regressive compatibility (with arcs).
454 Trajectory::calcSpeeds()
456 if (size() == 0) return;
458 // Assign maximum speed
459 for (iterator seg = begin(); seg != end(); seg++) {
460 (*seg)->setMaxV(constr);
461 // (*seg)->v1 = (*seg)->maxv;
462 // (*seg)->v2 = (*seg)->maxv;
464 #ifdef MATLAB_MEX_FILE
469 bool turning = false; // FIXME: turning je integer podle smeru otaceni
471 // Accelerate where possible
473 for (iterator seg = begin(); seg != end(); seg++) {
474 if (turning != (*seg)->isTurn()) {
475 turning = (*seg)->isTurn();
478 double v1 = (*seg)->v1;
479 double v2 = (*seg)->v2;
480 double maxv = (*seg)->maxv;
481 //dbgPrintf("processing: %p v1=%g\n", *seg, v1);
485 if ((*seg)->isSpline() == false) {
486 double l = (*seg)->getUnifiedLength();
487 double a = (*seg)->getMaxAcc(constr);
490 t = (-v1+sqrt(v1*v1 + 2.0*a*l))/a;
493 //dbgPrintf("t=%g v2=%g l=%g\n", t, v2, l);
494 if (v2 > maxv) { // split this segment
498 //dbgPrintf("t=%g v2=%g l=%g\n", t, v2, l);
500 if (splitSegment(ns, l)) {
511 #ifdef MATLAB_MEX_FILE
515 // Deccelerate where needed
517 lastv = 0; // Final speed
518 for (reverse_iterator seg = rbegin(); seg != rend(); seg++) {
519 if (turning != (*seg)->isTurn()) {
520 turning = (*seg)->isTurn();
523 double v1 = (*seg)->v1;
524 double v2 = (*seg)->v2;
525 double maxv = (*seg)->maxv;
526 dbgPrintf("processing: %p v2=%g\n", *seg, v2);
530 if ((*seg)->isSpline() == false) {
531 double l = (*seg)->getUnifiedLength();
532 double a = (*seg)->getMaxAcc(constr);
535 t = (-v2+sqrt(v2*v2 + 2.0*a*l))/a;
538 //dbgPrintf("t=%g v1=%g v2=%g l=%g\n", t, v1, v2, l);
539 if (v1 > maxv && (*seg)->v1 == maxv) {
542 double l2 = v2*t+0.5*a*t*t;
543 //dbgPrintf("t=%g v1=%g v2=%g l=%g l2=%g\n", t, v1, v2, l, l2);
544 iterator ns = --(seg.base());
545 //dbgPrintf("seg=%p ns=%p\n", *seg, *ns);
546 if (splitSegment(ns, l-l2)) {
547 //dbgPrintf("ns=%p\n", *ns);
551 } else if (v1 > (*seg)->v1) {
552 // Acceleration and deacceleration within one segment
553 // Where is the crossing af acceleration and decceleration?
555 double s1 = l/2.0 + (v2*v2 - v1*v1)/4.0*a;
557 if (s1 > l/1000 && s1 < l - l/1000) {
558 //dbgPrintf("t=%g v1=%g v2=%g l=%g s1=%g\n", t, v1, v2, l, s1);
559 iterator ns = --(seg.base());
560 //dbgPrintf("seg=%p ns=%p (before split)\n", *seg, *ns);
561 if (splitSegment(ns, s1)) {
562 ++seg; //move to the earlier subsegment of the splited one
563 //dbgPrintf("seg=%p ns=%p (after split)\n", *seg, *ns);
564 v1 = sqrt(v1*v1 + 2.0*a*s1);
579 #ifdef MATLAB_MEX_FILE
582 for (iterator seg = begin(); seg != end(); ++seg) {
583 dbgPrintf("final: %-16s %p v1=%-8.2g v2=%-8.2g l=%-8.2g\n",
584 typeid(**seg).name(),
585 *seg, (*seg)->v1, (*seg)->v2, (*seg)->getLength());
591 Trajectory::calcLength()
594 for (iterator seg = begin(); seg != end(); ++seg) {
595 totLen += (*seg)->getLength();
600 static double minimizeAngle(double rad)
602 rad = fmod(rad, 2.0*M_PI);
603 if (rad > +M_PI) rad -= 2.0*M_PI;
604 if (rad < -M_PI) rad += 2.0*M_PI;
608 static double calcTurnBy(double initialHeading, struct final_heading finalHeading)
611 if (finalHeading.turn_type == FH_DONT_TURN) turnBy = NAN;
613 turnBy = minimizeAngle(finalHeading.heading - initialHeading);
614 if (turnBy < 0 && finalHeading.turn_type == FH_CCW) turnBy += M_PI*2.0;
615 if (turnBy > 0 && finalHeading.turn_type == FH_CW) turnBy -= M_PI*2.0;
621 * Adds a point to the beginning of trajectory, because moving robot can not change
622 * direction at once. Needed by nonzero initial speed.
624 void Trajectory::addInertialPoint()
627 double braking_distance;
628 braking_distance = (0.5 * initPos.v * initPos.v / constr.maxacc) + 0.02;
629 p.x = initPos.x + braking_distance * cos(initPos.phi);
630 p.y = initPos.y + braking_distance * sin(initPos.phi);
631 initialPoint = new Point(p);
632 wayPoints.push_front(initialPoint);
633 contains_inertial = true;
637 void Trajectory::addTurns()
640 TrajectorySegment *seg;
641 double initialHeading = initPos.phi;
644 initialHeading -= M_PI;
647 // We have to turn only. No movement.
648 dbgPrintf("*** Adding only the turn - start: %5.2f, end %5.2f\n", initialHeading/M_PI*180, finalHeading.heading/M_PI*180);
649 initialTurnBy = calcTurnBy(initialHeading, finalHeading);
650 if (fabs(initialTurnBy) > 1e-3) {
651 push_front(new Turn(initialPoint, initialHeading, initialTurnBy));
654 // Add turn at beginning
656 seg->v1 = 1; // Hack - speeds are not calculated yet
658 seg->startAt(0); // Assign times so we can use
660 seg->getRefPos(0, p);
661 dbgPrintf("*** Adding initial turn - start: %5.2f, end %5.2f\n", initialHeading/M_PI*180, p.phi/M_PI*180);
662 initialTurnBy = minimizeAngle(p.phi - initialHeading);
663 if (fabs(initialTurnBy) > 1e-3 && initPos.v == 0) {
664 push_front(new Turn(initialPoint, initialHeading, initialTurnBy));
667 // Add turn at the end
669 seg->v1 = 1; // Hack - speeds are not calculated yet
671 seg->startAt(0); // Assign times so we can use getRefPos();
672 seg->getRefPos(seg->getT2(), p);
673 finalTurnBy = calcTurnBy(p.phi, finalHeading);
674 if (fabs(finalTurnBy) > 1e-3) { // NaN in finalHeading makes the condition false
675 dbgPrintf("*** Adding final turn - start: %5.2f, end %5.2f\n", p.phi/M_PI*180, finalHeading.heading/M_PI*180);
676 push_back(new Turn(finalPoint, p.phi, finalTurnBy));
682 * Prepares the trajectory. It converts points added by addPoint() to
683 * line segments (::Line). Then it replaces by sharp
684 * corners by arcs (see corners2arcs()), then it adds turns at the
685 * begin and end and finally it calculates speeds in the different
686 * parts of the trajectory by adding acceleration and decceleration
687 * segments (see calcSpeeds()).
689 * @param _initPos The point where the trajectory should
690 * start. Typically the current robot position.
691 * @return True in case of success, false when the trajectory has only
692 * one point and initPos is already equal to that point.
695 Trajectory::prepare(Pos _initPos)
697 if (constr.maxv <= 0 || constr.maxv > 10 ||
698 constr.maxomega <= 0 || constr.maxomega > 10 ||
699 constr.maxangacc <= 0 || constr.maxangacc > 10 ||
700 constr.maxacc <= 0 || constr.maxacc > 10 ||
701 constr.maxcenacc <= 0 || constr.maxcenacc > 10 ||
702 constr.maxe <= 0 || constr.maxe > 10) {
703 dbgPrintf("wrong constraints!!!!\n");
706 if (wayPoints.size() == 0) {
707 dbgPrintf("No point in trajectory!\n");
713 contains_inertial = false;
714 // adds a point in actual (initial) direction
718 // TODO: no support for omega continuity yet
719 if (initPos.v == 0 && initPos.omega != 0)
721 // printf("//// not supported turning\n");
726 if (points2segments() == false) {
727 dbgPrintf("points2segments error!\n");
738 // Assign times to segments
740 for (iterator seg = begin(); seg != end(); ++seg) {
741 t = (*seg)->startAt(t);
743 currentSeg = begin();
750 * Returns reference position of the trajectory at a given time.
752 * @param[in] time Time from the beginning of the trajectory.
753 * @param[out] rp Returned reference position.
754 * @return True if the time is after the trajectory ends or
755 * error. False otherwise.
758 Trajectory::getRefPos(double time, Pos &rp)
762 TrajectorySegment *seg;
768 d=(*currentSeg)->containsTime(time);
770 if (currentSeg == --end() && d > 0) break;
771 if (currentSeg == begin() && d < 0) break;
772 if (d>0) ++currentSeg;
773 else if (d<0) --currentSeg;
779 sprintf(c, "#slength %lf\n", seg->getLength()); // gnuplot middle part
783 getSegRefPos(seg, time, rp);
785 getSegRefPos(seg, seg->getT1(), rp);
787 getSegRefPos(seg, seg->getT2(), rp);
788 ret = true; // We are at the end.
796 * Returns reference position of the given segment in the trajectory
797 * and takes @c backward into the account.
799 * @param[in] seg Segment to get the position from.
800 * @param[in] time Time from the beginning of the trajectory.
801 * @param[out] rp Returned reference position.
804 Trajectory::getSegRefPos(TrajectorySegment *seg, double time, Pos &rp)
806 seg->getRefPos(time, rp);
815 * Connects to the recent trajectory a new one - @c traj.
816 * It must satisfy some demands e.g. being prepared.
817 * @param traj new trajectory
818 * @param time on the recent trajectory to find the point where to join
820 * @return true if the action succeeded
822 bool Trajectory::appendTrajectory(Trajectory &traj, double time)
826 if (backward != traj.backward)
831 // printf("swtime> %lf\n", time);
833 /* Pos h1, h2, h3, h4;
834 for (iterator seg = begin(); seg != end(); ++seg) {
835 (*seg)->getRefPos((*seg)->getT1(), h1);
836 (*seg)->getRefPos((*seg)->getT2(), h2);
837 printf("puvodni %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
838 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
839 printf("details: v1 %lf v2 %lf acc %lf len %lf\n", (*seg)->v1, (*seg)->v2, (*seg)->acc, (*seg)->getLength()); // segment details
842 for (iterator seg = traj.begin(); seg != traj.end(); ++seg) {
843 (*seg)->getRefPos((*seg)->getT1(), h1);
844 (*seg)->getRefPos((*seg)->getT2(), h2);
845 printf("novy %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
846 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
850 for (iterator seg = begin(); seg != end(); ++seg) {
851 if ((*seg)->containsTime(time) == 0) {
853 (*seg)->getRefPos(time, con_pos);
854 Point continuity(con_pos.x, con_pos.y);
855 if (continuity != *(traj.initialPoint)) {
856 return false; // the trajectories don't fit
858 // if (time == (*seg)->getT1()) {
859 // seg = erase(seg, end());
860 // } else if (time == (*seg)->getT2()) {
863 // seg = erase(seg, end());
865 splitSegmentByTime(seg, time);
866 seg = erase(seg, end());
873 // add new segments to the old trajectory
877 // add way points (why?)
879 finalPoint = traj.finalPoint;
882 finalHeading = traj.finalHeading;
886 for (iterator seg = begin(); seg != end(); ++seg) {
887 t = (*seg)->startAt(t);
892 for (iterator seg = begin(); seg != end(); ++seg) {
893 (*seg)->getRefPos((*seg)->getT1(), h1);
894 getRefPos((*seg)->getT1(), h3);
895 (*seg)->getRefPos((*seg)->getT2(), h2);
896 getRefPos((*seg)->getT2(), h4);
897 printf("merged %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
898 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
899 printf("*merged %lf %lf %lf %lf\n", h3.x, h3.y, h4.x, h4.y);
900 printf("details: v1 %lf v2 %lf acc %lf len %lf\n", (*seg)->v1, (*seg)->v2, (*seg)->acc, (*seg)->getLength()); // segment details
903 currentSeg = begin();
907 // getRefPos(0.1, p);
908 // printf("-difference real %lf %lf\n", p.x, p.y);
911 log("#trajectory APPENDED (merged two trajectories togeather)\n");
915 for (iterator seg = begin(); seg != end(); seg++) { // logging segment parameters
916 (*seg)->getRefPos((*seg)->getT1(), p1);
917 (*seg)->getRefPos((*seg)->getT2(), p2);
918 sprintf(c, "#segment: begin %lf %lf, end %lf %lf, angles %lf %lf, v1 %lf, v2 %lf, t1 %lf, t2 %lf, len %lf\n",
919 p1.x, p1.y, p2.x, p2.y, p1.phi, p2.phi,(*seg)->v1, (*seg)->v2, (*seg)->getT1(), (*seg)->getT2(), (*seg)->getLength());
922 iterator end_seg = --end();
923 double max_tm = (*end_seg)->getT2();
925 for(double tm = 0; tm <= max_tm; tm += 0.05) {
927 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", tm, p1.x, p1.y, p1.phi, 2); // gnuplot middle part
936 Trajectory::log(const char* str) {
938 f = fopen("motion.log", "a");
940 printf("logged not - cant open/create motion.log");
947 #ifdef MATLAB_MEX_FILE
949 Trajectory::plot(const char *style)
951 for (iterator seg = begin(); seg != end(); ++seg) {
956 Trajectory::plotSpeed(const char *style)
958 const char *f2 = "figure(2); xlabel('Time [s]'); ylabel('Speed [m/s], dotted [rad/s]');";
959 const char *f1 = "hold on; figure(1)";
961 strcpy(turnstyle, style);
962 if (turnstyle[1] == '-') turnstyle[1] = ':';
965 for (iterator seg = begin(); seg != end(); ++seg) {
966 t = (*seg)->startAt(t);
967 if (!(*seg)->isTurn())
968 (*seg)->plotSpeed(style);
970 (*seg)->plotSpeed(turnstyle);
978 for (iterator seg = begin(); seg != end(); ++seg) {
979 sprintf(debug, "disp('*** seg %d: t1 %lf, t2 %lf, len %lf, v1 %lf, v2 %lf.')",
980 i, t, (*seg)->startAt(t), (*seg)->getUnifiedLength(), (*seg)->v1, (*seg)->v2);
981 t = (*seg)->startAt(t);
983 mexEvalString(debug);
991 Trajectory::logTraj(double start_time)
995 for (iterator seg = begin(); seg != end(); seg++) { // logging segment parameters
996 (*seg)->getRefPos((*seg)->getT1(), p1);
997 (*seg)->getRefPos((*seg)->getT2(), p2);
998 sprintf(c, "#segment: begin %lf %lf, end %lf %lf, angles %lf %lf, v1 %lf, v2 %lf, t1 %lf, t2 %lf, len %lf\n",
999 p1.x, p1.y, p2.x, p2.y, p1.phi, p2.phi,(*seg)->v1, (*seg)->v2, (*seg)->getT1(), (*seg)->getT2(), (*seg)->getLength());
1001 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+(*seg)->getT1(), p1.x, p1.y, p1.phi, 1); //gnuplot start point
1003 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+(*seg)->getT2(), p2.x, p2.y, p2.phi, 3); //gnuplot end point
1006 iterator end_seg = --end();
1007 double max_tm = (*end_seg)->getT2();
1009 for(double tm = 0; tm <= max_tm; tm += 0.05) {
1011 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+tm, p1.x, p1.y, p1.phi, 2); // gnuplot middle part