3 * @author Michal Sojka, Petr Beneš
4 * @date Sun Aug 12 09:59:32 2007
6 * @brief Trajectory Generator
20 // #ifdef MATLAB_MEX_FILE
21 // #define S_FUNCTION_LEVEL 2
22 // #define S_FUNCTION_NAME sf_trgen
23 // #include "simstruc.h"
26 using namespace Segment;
29 * Split a sergment and add the newly created segment to the
32 * @param seg Segment to split.
33 * @param time Where to split.
38 Trajectory::splitSegmentByTime(iterator &seg, double time)
40 TrajectorySegment *ns;
42 if (typeid(**seg) != typeid(Turn))
45 ns = (*seg)->splitAtByTime(time, np);
52 wayPoints.push_back(np);
53 seg = insert(++seg, ns);
59 * Split a sergment and add the newly created segment to the
62 * @param seg Segment to split.
63 * @param distance Where to split.
68 Trajectory::splitSegment(iterator &seg, double distance)
70 TrajectorySegment *ns;
72 if (typeid(**seg) != typeid(Turn))
75 ns = (*seg)->splitAt(distance, np);
82 wayPoints.push_back(np);
83 seg = insert(++seg, ns);
87 // iterator insert(reverse_iterator it, const value_type& val) {
88 // return insert((--it).base(), val);
92 * Connects points by line segments.
95 Trajectory::points2segments()
97 TrajectoryPoints::iterator p1, p2, p3;
98 Point ip(initPos.x, initPos.y);
101 if (*wayPoints.front() != ip) {
102 initialPoint = new Point(ip);
103 wayPoints.push_front(initialPoint);
105 initialPoint = wayPoints.front();
108 // Delete old segments
111 if (wayPoints.size() < 2 &&
112 (finalHeading.turn_type == FH_DONT_TURN ||
113 (finalHeading.turn_type == FH_SHORTEST && \
114 fabs(initPos.phi - finalHeading.heading) < 1.0/180*M_PI))) {
118 if (wayPoints.size() >= 3) {
119 // be aware of two identical points, you can not measure any angle, so delete one of them
120 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin(); p2 != wayPoints.end(); p1++, p2++) {
121 if ((*p1)->distanceTo(**p2) < 0.001) {
124 sprintf(ccc, "One of identical points x %lf y %lf erased\n", (*p2)->x, (*p2)->y);
127 p2 = wayPoints.erase(p2);
131 // For avoiding too sharp turns than a constant we add one point to the right angle, so that
132 // we obtain two bigger angles instead of one very small. This point is so close to the original one
133 // and should not affect the trajectory from the macroscopical point of view.
134 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin(), p3 = ++wayPoints.begin(), ++p3;
135 p3 != wayPoints.end();
137 edge = fabs((*p2)->angleTo(**p1) - (*p2)->angleTo(**p3));
139 edge = (2*M_PI) - edge;
140 if (edge*180/M_PI < 3.0)
142 edge = (*p2)->angleTo(**p1) + M_PI/2.0;
143 Point *pt = new Point ((*p2)->x + cos(edge)*0.025, (*p2)->y + sin(edge)*0.025);
144 wayPoints.insert(p2, pt);
147 sprintf(ccc, "Sharp edge smoothed %lf %lf, %lf %lf, %lf %lf\n",
148 (**p1).x, (**p1).y, (**p2).x, (**p2).y, (**p3).x, (**p3).y);
157 for (p1 = wayPoints.begin(); p1 != wayPoints.end(); p1++) {
158 sprintf(c, "wayPoints: x %lf y %lf\n", (*p1)->x, (*p1)->y);
163 for (p1 = wayPoints.begin(), p2 = ++wayPoints.begin();
164 p2 != wayPoints.end();
166 push_back(new Line(*p1, *p2));
173 * Converts corners in trajectory to arcs.
177 // \frame{\begin{tikzpicture}
178 // \draw (-5cm,0) coordinate(p1) node[left]{$p_1$} --
179 // node[sloped,above]{$\mathrm seg_1$} (0,0) coordinate(p2)
180 // node[above]{$p_2$} -- node[sloped,above]{$\mathrm seg_2$} +(-30:5cm)
181 // node[right]{$p_3$} coordinate (p3);
182 // \coordinate[shift=(-105:5cm)] (c) at (p2);
183 // \draw (p2) -- (c);
184 // \draw (c) -- (c |- p2);
185 // \draw (c) -- (intersection of c--40:10cm and p2--p3);
186 // \end{tikzpicture}}
191 Trajectory::corners2arcs()
193 iterator seg, segNext, segPrev;
195 if (size() < 2) return;
197 // Find radiuses to meet e <= maxe
198 for (segPrev = begin(), segNext = ++begin();
200 segPrev++, segNext++) {
202 double alpha; // curve angle (-pi <= alpha <= +pi)
203 double r; // radius of proposed arc. (alpha < 0 -> r < 0)
204 double s; // length of the segment replaced by the arc (s > 0)
206 alpha = dynamic_cast<Line*>(*segNext)->getAngle() -
207 dynamic_cast<Line*>(*segPrev)->getAngle();
208 if (alpha > +M_PI) alpha -= 2.0*M_PI;
209 if (alpha < -M_PI) alpha += 2.0*M_PI;
211 if (fabs(alpha) < M_PI/180.0) continue;
213 r = constr.maxe / (1/cos(alpha/2.0) - 1);
214 if (alpha < 0) r = -r;
215 s = r*tan(alpha/2.0);
216 if (s > (*segPrev)->getLength()) {
217 s = (*segPrev)->getLength();
218 r = s/tan(alpha/2.0);
220 if (s > (*segNext)->getLength()) {
221 s = (*segNext)->getLength();
222 r = s/tan(alpha/2.0);
226 (*segPrev)->alphahalf = alpha/2.0;
228 catch (std::exception& e) {} // Skip wrong dynamic_cast
232 // Reduce overlapping arcs by decreasing radiuses
233 double s1, s2, r1, r2, l, alphahalf1, alphahalf2;
235 for (segPrev = begin(), segNext = ++begin();
237 segPrev++, segNext++) {
238 l = (*segNext)->getLength();
243 alphahalf1 = (*segPrev)->alphahalf;
244 alphahalf2 = (*segNext)->alphahalf;
246 if (fabs(r1) > fabs(r2)) {
248 r1 = s1/tan(alphahalf1);
249 wantSameR = (fabs(r1) < fabs(r2));
252 r2 = s2/tan(alphahalf2);
253 wantSameR = (fabs(r1) > fabs(r2));
256 if (alphahalf1 < 0 ^ alphahalf2 < 0)
257 s1 = l*tan(alphahalf1)/(tan(alphahalf1)-tan(alphahalf2));
259 s1 = l*tan(alphahalf1)/(tan(alphahalf1)+tan(alphahalf2));
261 r1 = s1/tan(alphahalf1);
262 r2 = s2/tan(alphahalf2);
272 // replace corners by arcs with previously computed radiuses
273 for (segPrev = begin(), segNext = ++begin();
275 ++segPrev, ++segNext) {
276 if (fabs((*segPrev)->r) > 0) {
277 Point *newEnd1, *newEnd2;
278 double s = (*segPrev)->s;
279 newEnd1 = new Point();
280 newEnd2 = new Point();
281 (*segPrev)->shortenBy(+s, newEnd1);
282 (*segNext)->shortenBy(-s, newEnd2);
283 wayPoints.push_back(newEnd1);
284 wayPoints.push_back(newEnd2);
285 segPrev = insert(segNext, new Arc(newEnd1, newEnd2,
290 //delete zero-length segments
292 while (seg != end()) {
293 if ((*seg)->getLength() <= 1e-9) {
303 * Converts corners in trajectory to splines.
304 * The algorithm finds the smaller of two neighbour lines,
305 * grabs a half of it's length, than approximation constraint shortens this distance.
306 * This distance is replaced by a symetric spline curve.
309 Trajectory::corners2splines()
311 #ifdef MATLAB_MEX_FILE
312 mexEvalString("disp('...preparing spline...')");
315 iterator seg, segNext, segPrev;
316 double origLen = -1.0; // length of segment segPrev before being cut off
318 if (size() < 2) return;
320 for (segPrev = begin(), segNext = ++begin();
322 ++segPrev, ++segNext)
324 Point *newEnd1, *newEnd2, *edge;
326 newEnd1 = new Point();
327 newEnd2 = new Point();
329 double dst; // distance to cut off from both Lines
332 dst = fmin((*segPrev)->getLength(), (*segNext)->getLength()) * 0.5;
334 dst = fmin(origLen, (*segNext)->getLength()) * 0.5;
336 // just to count the angle between lines
337 (*segPrev)->getPointAt((*segPrev)->getLength(), edge);
338 (*segPrev)->getPointAt(-dst, newEnd1);
339 (*segNext)->getPointAt(dst, newEnd2);
341 // shorten dst according to constraint maxe
342 double ang = fabs(edge->angleTo(*newEnd1) - edge->angleTo(*newEnd2));
344 ang = (2.0*M_PI) - ang;
345 double e; // distance from the spline to edge
346 const double C0 = 0.892303;
347 const double C1 = -0.008169;
348 const double C2 = 1.848555E-05;
350 // experimental relation, but good enough
351 // see Matlab m-file 'splines/constr_maxe.m'
352 e = (C2*pow(ang*180.0/M_PI, 2) + C1*(ang*180.0/M_PI) + C0) * dst;
354 if (e > constr.maxe && !(segPrev == begin() && contains_inertial))
355 dst = dst * (constr.maxe/e);
357 origLen = (*segNext)->getLength();
359 (*segPrev)->getPointAt((*segPrev)->getLength(), edge);
360 (*segPrev)->shortenBy(+dst, newEnd1);
361 (*segNext)->shortenBy(-dst, newEnd2);
362 wayPoints.push_back(newEnd1);
363 wayPoints.push_back(newEnd2);
364 segPrev = insert(segNext, new Spline(newEnd1, newEnd2, edge));
367 sprintf(c, "splineToBeCounted: begin %lf %lf end %lf %lf edge %lf %lf\n",
368 newEnd1->x, newEnd1->y, newEnd2->x, newEnd2->y, edge->x, edge->y);
374 TrajectoryPoints::iterator p1;
376 for (p1 = wayPoints.begin(); p1 != wayPoints.end(); p1++) {
377 sprintf(c, "wayPointsSplined: x %lf y %lf\n", (*p1)->x, (*p1)->y);
382 //delete zero-length segments
384 while (seg != end()) {
386 if ((*seg)->getLength() <= 1e-9) {
397 * Assigns speeds and accelerations to segments; tries to maximize
398 * speed where possible. If necessary it also splits long segments
399 * to multiple parts with maximum acceleration/deceleration and
400 * maximal speed. The optimization is done in three passes. In the
401 * first pass, maximal speed of segments are set up (see
402 * TrajectoryConstraints::maxv, TrajectoryConstraints::maxomega,
403 * TrajectoryConstraints::maxcenacc). Then follows a forward pass, where
404 * acceleration is added to join segments with increasing maximal
405 * speeds. Finally, backward pass does almost the same by adding
406 * deceleration segments.
408 * Finding the split point of the segment where deceleration
409 * immediately follows acceleration is based on the following
412 * For uniformly accelerated motion, we can calculate time as
413 * function of speed: \f[ t(v)=\frac{v-v_0}{a}\f] Using this, we can
414 * express distance \f$ s \f$ as a function of speed: \f[ s(v) =
415 * \frac{1}{2} at(v)^2 + v_0 t(v) = \frac{v^2 - v_0^2}{2a}\f]
417 * Then, distance traveled during acceleration (\f$ s_1 \f$) and
418 * deceleration (\f$ s_2 \f$) must be equal to the length of the
419 * segment \f$ l = s_1 + s_2 \f$. Considering a segment with initial
420 * speed \f$ v_1 \f$, final speed \f$ v_2 \f$, and maximal speed (in
421 * the split point) \f$ v_{max} \f$, we can derive: \f[ l =
422 * s_1(v_{max}) + s_2(v_{max}) = \frac{2v_{max}^2 - v_1^2 - v_2^2}{2a}
423 * \f] \f[ v_{max}^2 = al + \frac{v_1^2 + v_2^2}{2} \f]
425 * Then, the length of the segment before split is: \f[ s_1 = l - s_2
426 * = l - \frac{v_{max}^2-v_2^2}{2a} = \frac{1}{2}l + \frac{v_2^2 -
429 * --- SPLINE UPDATE: The algorithm works nearly the same as before and is
430 * possible to use with splines. However, spline segments are not being
431 * cut off, but only their acceleration profiles change to ensure speed
432 * connectivity. This is not time optimal, but time loss is small enough,
433 * we avoid a lot of difficulties and keep regressive compatibility (with arcs).
436 Trajectory::calcSpeeds()
438 if (size() == 0) return;
440 // Assign maximum speed
441 for (iterator seg = begin(); seg != end(); seg++) {
442 (*seg)->setMaxV(constr);
443 // (*seg)->v1 = (*seg)->maxv;
444 // (*seg)->v2 = (*seg)->maxv;
446 #ifdef MATLAB_MEX_FILE
451 bool turning = false; // FIXME: turning je integer podle smeru otaceni
453 // Accelerate where possible
455 for (iterator seg = begin(); seg != end(); seg++) {
456 if (turning != (*seg)->isTurn()) {
457 turning = (*seg)->isTurn();
460 double v1 = (*seg)->v1;
461 double v2 = (*seg)->v2;
462 double maxv = (*seg)->maxv;
463 //dbgPrintf("processing: %p v1=%g\n", *seg, v1);
467 if ((*seg)->isSpline() == false) {
468 double l = (*seg)->getUnifiedLength();
469 double a = (*seg)->getMaxAcc(constr);
472 t = (-v1+sqrt(v1*v1 + 2.0*a*l))/a;
475 //dbgPrintf("t=%g v2=%g l=%g\n", t, v2, l);
476 if (v2 > maxv) { // split this segment
480 //dbgPrintf("t=%g v2=%g l=%g\n", t, v2, l);
482 if (splitSegment(ns, l)) {
493 #ifdef MATLAB_MEX_FILE
497 // Deccelerate where needed
499 lastv = 0; // Final speed
500 for (reverse_iterator seg = rbegin(); seg != rend(); seg++) {
501 if (turning != (*seg)->isTurn()) {
502 turning = (*seg)->isTurn();
505 double v1 = (*seg)->v1;
506 double v2 = (*seg)->v2;
507 double maxv = (*seg)->maxv;
508 dbgPrintf("processing: %p v2=%g\n", *seg, v2);
512 if ((*seg)->isSpline() == false) {
513 double l = (*seg)->getUnifiedLength();
514 double a = (*seg)->getMaxAcc(constr);
517 t = (-v2+sqrt(v2*v2 + 2.0*a*l))/a;
520 //dbgPrintf("t=%g v1=%g v2=%g l=%g\n", t, v1, v2, l);
521 if (v1 > maxv && (*seg)->v1 == maxv) {
524 double l2 = v2*t+0.5*a*t*t;
525 //dbgPrintf("t=%g v1=%g v2=%g l=%g l2=%g\n", t, v1, v2, l, l2);
526 iterator ns = --(seg.base());
527 //dbgPrintf("seg=%p ns=%p\n", *seg, *ns);
528 if (splitSegment(ns, l-l2)) {
529 //dbgPrintf("ns=%p\n", *ns);
533 } else if (v1 > (*seg)->v1) {
534 // Acceleration and deacceleration within one segment
535 // Where is the crossing af acceleration and decceleration?
537 double s1 = l/2.0 + (v2*v2 - v1*v1)/4.0*a;
539 if (s1 > l/1000 && s1 < l - l/1000) {
540 //dbgPrintf("t=%g v1=%g v2=%g l=%g s1=%g\n", t, v1, v2, l, s1);
541 iterator ns = --(seg.base());
542 //dbgPrintf("seg=%p ns=%p (before split)\n", *seg, *ns);
543 if (splitSegment(ns, s1)) {
544 ++seg; //move to the earlier subsegment of the splited one
545 //dbgPrintf("seg=%p ns=%p (after split)\n", *seg, *ns);
546 v1 = sqrt(v1*v1 + 2.0*a*s1);
561 #ifdef MATLAB_MEX_FILE
564 for (iterator seg = begin(); seg != end(); ++seg) {
565 dbgPrintf("final: %-16s %p v1=%-8.2g v2=%-8.2g l=%-8.2g\n",
566 typeid(**seg).name(),
567 *seg, (*seg)->v1, (*seg)->v2, (*seg)->getLength());
573 Trajectory::calcLength()
576 for (iterator seg = begin(); seg != end(); ++seg) {
577 totLen += (*seg)->getLength();
582 static double minimizeAngle(double rad)
584 rad = fmod(rad, 2.0*M_PI);
585 if (rad > +M_PI) rad -= 2.0*M_PI;
586 if (rad < -M_PI) rad += 2.0*M_PI;
590 static double calcTurnBy(double initialHeading, struct final_heading finalHeading)
593 if (finalHeading.turn_type == FH_DONT_TURN) turnBy = NAN;
595 turnBy = minimizeAngle(finalHeading.heading - initialHeading);
596 if (turnBy < 0 && finalHeading.turn_type == FH_CCW) turnBy += M_PI*2.0;
597 if (turnBy > 0 && finalHeading.turn_type == FH_CW) turnBy -= M_PI*2.0;
603 * Adds a point to the beginning of trajectory, because moving robot can not change
604 * direction at once. Needed by nonzero initial speed.
606 void Trajectory::addInertialPoint()
609 double braking_distance;
610 braking_distance = (0.5 * initPos.v * initPos.v / constr.maxacc) + 0.02;
611 p.x = initPos.x + braking_distance * cos(initPos.phi);
612 p.y = initPos.y + braking_distance * sin(initPos.phi);
613 initialPoint = new Point(p);
614 wayPoints.push_front(initialPoint);
615 contains_inertial = true;
619 void Trajectory::addTurns()
622 TrajectorySegment *seg;
623 double initialHeading = initPos.phi;
626 initialHeading -= M_PI;
629 // We have to turn only. No movement.
630 dbgPrintf("*** Adding only the turn - start: %5.2f, end %5.2f\n", initialHeading/M_PI*180, finalHeading.heading/M_PI*180);
631 turnBy = calcTurnBy(initialHeading, finalHeading);
632 if (fabs(turnBy) > 1e-3) {
633 push_front(new Turn(initialPoint, initialHeading, turnBy));
636 // Add turn at beginning
638 seg->v1 = 1; // Hack - speeds are not calculated yet
640 seg->startAt(0); // Assign times so we can use
642 seg->getRefPos(0, p);
643 dbgPrintf("*** Adding initial turn - start: %5.2f, end %5.2f\n", initialHeading/M_PI*180, p.phi/M_PI*180);
644 turnBy = minimizeAngle(p.phi - initialHeading);
645 if (fabs(turnBy) > 1e-3 && initPos.v == 0) {
646 push_front(new Turn(initialPoint, initialHeading, turnBy));
649 // Add turn at the end
651 seg->v1 = 1; // Hack - speeds are not calculated yet
653 seg->startAt(0); // Assign times so we can use getRefPos();
654 seg->getRefPos(seg->getT2(), p);
655 turnBy = calcTurnBy(p.phi, finalHeading);
656 if (fabs(turnBy) > 1e-3) { // NaN in finalHeading makes the condition false
657 dbgPrintf("*** Adding final turn - start: %5.2f, end %5.2f\n", p.phi/M_PI*180, finalHeading.heading/M_PI*180);
658 push_back(new Turn(finalPoint, p.phi, turnBy));
664 * Prepares the trajectory. It converts points added by addPoint() to
665 * line segments (::Line). Then it replaces by sharp
666 * corners by arcs (see corners2arcs()), then it adds turns at the
667 * begin and end and finally it calculates speeds in the different
668 * parts of the trajectory by adding acceleration and decceleration
669 * segments (see calcSpeeds()).
671 * @param _initPos The point where the trajectory should
672 * start. Typically the current robot position.
673 * @return True in case of success, false when the trajectory has only
674 * one point and initPos is already equal to that point.
677 Trajectory::prepare(Pos _initPos)
679 if (constr.maxv <= 0 || constr.maxv > 10 ||
680 constr.maxomega <= 0 || constr.maxomega > 10 ||
681 constr.maxangacc <= 0 || constr.maxangacc > 10 ||
682 constr.maxacc <= 0 || constr.maxacc > 10 ||
683 constr.maxcenacc <= 0 || constr.maxcenacc > 10 ||
684 constr.maxe <= 0 || constr.maxe > 10) {
685 dbgPrintf("wrong constraints!!!!\n");
688 if (wayPoints.size() == 0) {
689 dbgPrintf("No point in trajectory!\n");
695 contains_inertial = false;
696 // adds a point in actual (initial) direction
700 // TODO: no support for omega continuity yet
701 if (initPos.v == 0 && initPos.omega != 0)
703 // printf("//// not supported turning\n");
708 if (points2segments() == false) {
709 dbgPrintf("points2segments error!\n");
720 // Assign times to segments
722 for (iterator seg = begin(); seg != end(); ++seg) {
723 t = (*seg)->startAt(t);
725 currentSeg = begin();
732 * Returns reference position of the trajectory at a given time.
734 * @param[in] time Time from the beginning of the trajectory.
735 * @param[out] rp Returned reference position.
736 * @return True if the time is after the trajectory ends or
737 * error. False otherwise.
740 Trajectory::getRefPos(double time, Pos &rp)
744 TrajectorySegment *seg;
750 d=(*currentSeg)->containsTime(time);
752 if (currentSeg == --end() && d > 0) break;
753 if (currentSeg == begin() && d < 0) break;
754 if (d>0) ++currentSeg;
755 else if (d<0) --currentSeg;
761 sprintf(c, "slength %lf\n", seg->getLength()); // gnuplot middle part
765 getSegRefPos(seg, time, rp);
767 getSegRefPos(seg, seg->getT1(), rp);
769 getSegRefPos(seg, seg->getT2(), rp);
770 ret = true; // We are at the end.
778 * Returns reference position of the given segment in the trajectory
779 * and takes @c backward into the account.
781 * @param[in] seg Segment to get the position from.
782 * @param[in] time Time from the beginning of the trajectory.
783 * @param[out] rp Returned reference position.
786 Trajectory::getSegRefPos(TrajectorySegment *seg, double time, Pos &rp)
788 seg->getRefPos(time, rp);
797 * Connects to the recent trajectory a new one - @c traj.
798 * It must satisfy some demands e.g. being prepared.
799 * @param traj new trajectory
800 * @param time on the recent trajectory to find the point where to join
802 * @return true if the action succeeded
804 bool Trajectory::appendTrajectory(Trajectory &traj, double time)
808 if (backward != traj.backward)
813 // printf("swtime> %lf\n", time);
815 /* Pos h1, h2, h3, h4;
816 for (iterator seg = begin(); seg != end(); ++seg) {
817 (*seg)->getRefPos((*seg)->getT1(), h1);
818 (*seg)->getRefPos((*seg)->getT2(), h2);
819 printf("puvodni %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
820 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
821 printf("details: v1 %lf v2 %lf acc %lf len %lf\n", (*seg)->v1, (*seg)->v2, (*seg)->acc, (*seg)->getLength()); // segment details
824 for (iterator seg = traj.begin(); seg != traj.end(); ++seg) {
825 (*seg)->getRefPos((*seg)->getT1(), h1);
826 (*seg)->getRefPos((*seg)->getT2(), h2);
827 printf("novy %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
828 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
832 for (iterator seg = begin(); seg != end(); ++seg) {
833 if ((*seg)->containsTime(time) == 0) {
835 (*seg)->getRefPos(time, con_pos);
836 Point continuity(con_pos.x, con_pos.y);
837 if (continuity != *(traj.initialPoint)) {
838 return false; // the trajectories don't fit
840 // if (time == (*seg)->getT1()) {
841 // seg = erase(seg, end());
842 // } else if (time == (*seg)->getT2()) {
845 // seg = erase(seg, end());
847 splitSegmentByTime(seg, time);
848 seg = erase(seg, end());
855 // add new segments to the old trajectory
859 // add way points (why?)
861 finalPoint = traj.finalPoint;
864 finalHeading = traj.finalHeading;
868 for (iterator seg = begin(); seg != end(); ++seg) {
869 t = (*seg)->startAt(t);
874 for (iterator seg = begin(); seg != end(); ++seg) {
875 (*seg)->getRefPos((*seg)->getT1(), h1);
876 getRefPos((*seg)->getT1(), h3);
877 (*seg)->getRefPos((*seg)->getT2(), h2);
878 getRefPos((*seg)->getT2(), h4);
879 printf("merged %lf %lf %lf %lf", h1.x, h1.y, h2.x, h2.y);
880 printf(" -- times: %lf %lf\n", (*seg)->getT1(), (*seg)->getT2());
881 printf("*merged %lf %lf %lf %lf\n", h3.x, h3.y, h4.x, h4.y);
882 printf("details: v1 %lf v2 %lf acc %lf len %lf\n", (*seg)->v1, (*seg)->v2, (*seg)->acc, (*seg)->getLength()); // segment details
885 currentSeg = begin();
889 // getRefPos(0.1, p);
890 // printf("-difference real %lf %lf\n", p.x, p.y);
893 log("trajectory APPENDED (merged two trajectories togeather)\n");
897 for (iterator seg = begin(); seg != end(); seg++) { // logging segment parameters
898 (*seg)->getRefPos((*seg)->getT1(), p1);
899 (*seg)->getRefPos((*seg)->getT2(), p2);
900 sprintf(c, "segment: begin %lf %lf, end %lf %lf, angles %lf %lf, v1 %lf, v2 %lf, t1 %lf, t2 %lf, len %lf\n",
901 p1.x, p1.y, p2.x, p2.y, p1.phi, p2.phi,(*seg)->v1, (*seg)->v2, (*seg)->getT1(), (*seg)->getT2(), (*seg)->getLength());
904 iterator end_seg = --end();
905 double max_tm = (*end_seg)->getT2();
907 for(double tm = 0; tm <= max_tm; tm += 0.05) {
909 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", tm, p1.x, p1.y, p1.phi, 2); // gnuplot middle part
918 Trajectory::log(const char* str) {
920 f = fopen("motion.log", "a");
922 printf("logged not - cant open/create motion.log");
929 #ifdef MATLAB_MEX_FILE
931 Trajectory::plot(const char *style)
933 for (iterator seg = begin(); seg != end(); ++seg) {
938 Trajectory::plotSpeed(const char *style)
940 const char *f2 = "figure(2); xlabel('Time [s]'); ylabel('Speed [m/s], dotted [rad/s]');";
941 const char *f1 = "hold on; figure(1)";
943 strcpy(turnstyle, style);
944 if (turnstyle[1] == '-') turnstyle[1] = ':';
947 for (iterator seg = begin(); seg != end(); ++seg) {
948 t = (*seg)->startAt(t);
949 if (!(*seg)->isTurn())
950 (*seg)->plotSpeed(style);
952 (*seg)->plotSpeed(turnstyle);
960 for (iterator seg = begin(); seg != end(); ++seg) {
961 sprintf(debug, "disp('*** seg %d: t1 %lf, t2 %lf, len %lf, v1 %lf, v2 %lf.')",
962 i, t, (*seg)->startAt(t), (*seg)->getUnifiedLength(), (*seg)->v1, (*seg)->v2);
963 t = (*seg)->startAt(t);
965 mexEvalString(debug);
973 Trajectory::logTraj(double start_time)
977 for (iterator seg = begin(); seg != end(); seg++) { // logging segment parameters
978 (*seg)->getRefPos((*seg)->getT1(), p1);
979 (*seg)->getRefPos((*seg)->getT2(), p2);
980 sprintf(c, "segment: begin %lf %lf, end %lf %lf, angles %lf %lf, v1 %lf, v2 %lf, t1 %lf, t2 %lf, len %lf\n",
981 p1.x, p1.y, p2.x, p2.y, p1.phi, p2.phi,(*seg)->v1, (*seg)->v2, (*seg)->getT1(), (*seg)->getT2(), (*seg)->getLength());
983 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+(*seg)->getT1(), p1.x, p1.y, p1.phi, 1); //gnuplot start point
985 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+(*seg)->getT2(), p2.x, p2.y, p2.phi, 3); //gnuplot end point
988 iterator end_seg = --end();
989 double max_tm = (*end_seg)->getT2();
991 for(double tm = 0; tm <= max_tm; tm += 0.05) {
993 sprintf(c, "gnuplot: %lf %lf %lf %lf %d\n", start_time+tm, p1.x, p1.y, p1.phi, 2); // gnuplot middle part