]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blob - decision_control/slotplanner.cc
Add middle node getter
[hubacji1/iamcar.git] / decision_control / slotplanner.cc
1 /*
2 This file is part of I am car.
3
4 I am car is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 I am car is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with I am car. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <algorithm>
19 #include <cmath>
20 #include <list>
21 #include <queue>
22 #include "slotplanner.h"
23
24 ParallelSlot::ParallelSlot()
25 {}
26
27 // getter
28 RRTNode *ParallelSlot::getMidd()
29 {
30         if (this->cusp().size() > 0)
31                 return this->cusp().front().front();
32         else
33                 return nullptr;
34 }
35
36 std::vector<std::vector<RRTNode *>> &ParallelSlot::cusp()
37 {
38         return this->cusp_;
39 }
40
41 float ParallelSlot::DH() const
42 {
43         return this->DH_;
44 }
45
46 PolygonObstacle &ParallelSlot::slot()
47 {
48         return this->slot_;
49 }
50
51 float ParallelSlot::slotHeading()
52 {
53         return this->slotHeading_;
54 }
55
56 SlotSide ParallelSlot::slotSide()
57 {
58         return this->slotSide_;
59 }
60
61 SlotType ParallelSlot::slotType()
62 {
63         return this->slotType_;
64 }
65
66 // setter
67 void ParallelSlot::DH(float dh)
68 {
69         this->DH_ = dh;
70 }
71
72 void ParallelSlot::setAll()
73 {
74         // slot heading
75         float y0 = this->slot().bnodes()[0]->y();
76         float x0 = this->slot().bnodes()[0]->x();
77         float y3 = this->slot().bnodes()[3]->y();
78         float x3 = this->slot().bnodes()[3]->x();
79         float dy = y0 - y3;
80         float dx = x0 - x3;
81         this->slotHeading_ = atan2(dy, dx);
82         // slot side
83         float y1 = this->slot().bnodes()[1]->y();
84         float x1 = this->slot().bnodes()[1]->x();
85         if (sgn((x1 - x3) * (y0 - y3) - (y1 - y3) * (x0 - x3)) < 0)
86                 this->slotSide_ = LEFT;
87         else
88                 this->slotSide_ = RIGHT;
89         // slot type
90         float d1 = EDIST(
91                 this->slot().bnodes()[0],
92                 this->slot().bnodes()[1]
93         );
94         float d2 = EDIST(
95                 this->slot().bnodes()[1],
96                 this->slot().bnodes()[2]
97         );
98         if (d1 > d2)
99                 this->slotType_ = PERPENDICULAR;
100         else
101                 this->slotType_ = PARALLEL;
102 }
103
104 // other
105 void ParallelSlot::fip(
106         std::vector<CircleObstacle>& co,
107         std::vector<SegmentObstacle>& so
108 )
109 {
110         if (this->slotType() == PERPENDICULAR) {
111                 // TODO different slot headings
112                 // this is jus for slot heading = pi / 2
113                 this->DH(0.01 / BCAR_TURNING_RADIUS);
114                 BicycleCar *perc = nullptr;
115                 RRTNode *cc = nullptr;
116                 BicycleCar *p = nullptr;
117                 int i = 0;
118                 float x;
119                 float h;
120                 float y;
121                 // parking backward
122                 x = this->slot().bnodes()[3]->x();
123                 y = this->slot().bnodes()[3]->y();
124                 h = 0;
125                 // -> top
126                 x -= BCAR_DIST_FRONT;
127                 y = this->slot().bnodes()[3]->y();
128                 y += BCAR_OUT_RRADI - BCAR_TURNING_RADIUS;
129                 if (perc)
130                         delete perc;
131                 perc = new BicycleCar(x, y, h);
132                 if (cc)
133                         delete cc;
134                 cc = perc->ccl();
135                 if (p)
136                         delete p;
137                 p = perc->move(cc, i * this->DH());
138                 while (p->x() < 0) {
139                         delete p;
140                         p = perc->move(cc, i * this->DH());
141                         i++;
142                 }
143                 // -> bottom
144                 // (reset for parking backward)
145                 x = this->slot().bnodes()[0]->x();
146                 y = this->slot().bnodes()[0]->y();
147                 h = 0;
148                 // -> bottom
149                 x -= BCAR_DIST_FRONT;
150                 // get y from quadratic equation
151                 float tmpD = pow(-2 * this->slot().bnodes()[0]->y(), 2);
152                 tmpD -= 4 * (
153                         pow(x - this->slot().bnodes()[0]->x(), 2) +
154                         pow(this->slot().bnodes()[0]->y(), 2) -
155                         pow(BCAR_IN_RADI, 2)
156                 );
157                 y = 2 * this->slot().bnodes()[0]->y();
158                 y += sqrt(tmpD);
159                 y /= 2;
160                 y -= BCAR_TURNING_RADIUS;
161                 // -- end of quadratic equation
162                 if (perc)
163                         delete perc;
164                 perc = new BicycleCar(x, y, h);
165                 if (cc)
166                         delete cc;
167                 cc = perc->ccl();
168                 if (p)
169                         delete p;
170                 p = perc->move(cc, i * this->DH());
171                 while (p->x() < 0) {
172                         delete p;
173                         p = perc->move(cc, i * this->DH());
174                         i++;
175                 }
176                 // store nodes
177                 std::vector<RRTNode *> cusp;
178                 cusp.push_back(new RRTNode(p->x(), p->y(), p->h()));
179                 cusp.push_back(new RRTNode(x, y, h));
180                 this->cusp().push_back(cusp);
181                 return;
182         }
183         // see https://courses.cs.washington.edu/courses/cse326/03su/homework/hw3/bfs.html
184         // RRTNode.s() works as iteration level
185         std::queue<BicycleCar *, std::list<BicycleCar *>> q;
186         std::queue<BicycleCar *, std::list<BicycleCar *>> empty;
187         int di = -1;
188         if (this->slotSide() == LEFT)
189                 di = 1;
190         BicycleCar *CC = this->getEPC();
191         BicycleCar *B = this->getEP();
192         this->DH(di * 0.01 / CC->out_radi());
193         BicycleCar *c;
194         int i = 0;
195         c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
196         while (!this->slot().collide(c->frame())) {
197                 bool end = false;
198                 std::vector<RRTEdge *> eds = c->frame();
199                 for (auto o: co)
200                         if (o.collide(eds))
201                                 end = true;
202                 for (auto o: so)
203                         if (o.collide(eds))
204                                 end = true;
205                 for (auto e: eds)
206                         delete e;
207                 if (!end)
208                         q.push(c);
209                 c = B->move(CC, -i * di * 0.01 / CC->diag_radi());
210                 i += 1;
211         }
212         delete c; // not in q and collide
213         while (!q.empty()) {
214                 c = q.front();
215                 q.pop();
216                 if (this->isInside(c)) {
217                         goto createcuspandfinish;
218                 } else if (c->s() < 9) {
219                         BicycleCar *cc = this->flnc(c, co, so);
220                         cc->s(c->s() + 1);
221                         cc->bcparent(c);
222                         q.push(cc);
223                 } else {
224                         delete c; // not in q and collide
225                 }
226         }
227         std::swap(q, empty);
228         return;
229 createcuspandfinish:
230         std::vector<RRTNode *> cusp;
231         while (c) {
232                 cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
233                 c = c->bcparent();
234         }
235         std::reverse(cusp.begin(), cusp.end());
236         this->cusp().push_back(cusp);
237         std::swap(q, empty);
238 }
239
240 BicycleCar *ParallelSlot::flnc(
241         BicycleCar *B,
242         std::vector<CircleObstacle>& co,
243         std::vector<SegmentObstacle>& so
244 )
245 {
246         RRTNode *cc;
247         if (this->slotSide() == LEFT) {
248                 if (int(B->s()) % 2 == 0)
249                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
250                 else
251                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
252         } else {
253                 if (int(B->s()) % 2 == 0)
254                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
255                 else
256                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
257         }
258         BicycleCar *p;
259         int i = 1;
260         p = B->move(cc, i * this->DH());
261         while (
262                 !this->slot().collide(p->frame())
263                 && std::abs(this->slotHeading() - p->h()) < M_PI / 2
264         ) {
265                 delete p;
266                 i += 10;
267                 p = B->move(cc, i * this->DH());
268                 bool end = false;
269                 std::vector<RRTEdge *> eds = p->frame();
270                 for (auto o: co)
271                         if (o.collide(eds))
272                                 end = true;
273                 for (auto o: so)
274                         if (o.collide(eds))
275                                 end = true;
276                 for (auto e: eds)
277                         delete e;
278                 if (end)
279                         break;
280         }
281         i -= 10;
282         p = B->move(cc, i * this->DH());
283         while (
284                 !this->slot().collide(p->frame())
285                 && std::abs(this->slotHeading() - p->h()) < M_PI / 2
286         ) {
287                 if (this->isInside(p)) {
288                         i += 1;
289                         break;
290                 }
291                 delete p;
292                 i += 1;
293                 p = B->move(cc, i * this->DH());
294                 bool end = false;
295                 std::vector<RRTEdge *> eds = p->frame();
296                 for (auto o: co)
297                         if (o.collide(eds))
298                                 end = true;
299                 for (auto o: so)
300                         if (o.collide(eds))
301                                 end = true;
302                 for (auto e: eds)
303                         delete e;
304                 if (end)
305                         break;
306         }
307         delete p;
308         return B->move(cc, (i - 1) * this->DH());
309 }
310
311 void ParallelSlot::fipr(RRTNode *n)
312 {
313         return this->fipr(new BicycleCar(n->x(), n->y(), n->h()));
314 }
315
316 void ParallelSlot::fipr(BicycleCar *B)
317 {
318         std::vector<RRTNode *> cusp;
319         cusp.push_back(new RRTNode(B->x(), B->y(), B->h()));
320         int di = 1;
321         if (this->slotSide() == LEFT)
322                 di = -1;
323         if (this->slotType() == PERPENDICULAR) {
324                 this->DH(di * 0.01 / B->out_radi()); // TODO car in slot h()
325                 RRTNode *cc;
326                 if (this->slotSide() == LEFT)
327                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
328                 else
329                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
330                 BicycleCar *p;
331                 int i = 1;
332                 p = B->move(cc, i * this->DH());
333                 while (
334                         !this->slot().collide(p->frame())
335                         && this->slot().collide(p)
336                 ) {
337                         delete p;
338                         i += 10;
339                         p = B->move(cc, i * this->DH());
340                 }
341                 i -= 10;
342                 p = B->move(cc, i * this->DH());
343                 while (
344                         !this->slot().collide(p->frame())
345                         && this->slot().collide(p)
346                 ) {
347                         delete p;
348                         i += 1;
349                         p = B->move(cc, i * this->DH());
350                 }
351                 i -= 1;
352                 p = B->move(cc, i * this->DH());
353                 cusp.push_back(new RRTNode(p->x(), p->y(), p->h()));
354                 std::reverse(cusp.begin(), cusp.end());
355                 this->cusp().push_back(cusp);
356                 return;
357         }
358         this->DH(di * 0.01 / B->out_radi());
359         BicycleCar *c;
360         c = this->flncr(B);
361         c->s(B->s() + 1);
362         while ((
363                 this->slotSide() == LEFT
364                 && this->slot().collide(new RRTNode(c->lfx(), c->lfy(), 0))
365         ) || (
366                 this->slotSide() == RIGHT
367                 && this->slot().collide(new RRTNode(c->rfx(), c->rfy(), 0))
368         )) {
369                 cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
370                 BicycleCar *cc = this->flncr(c);
371                 cc->s(c->s() + 1);
372                 delete c;
373                 c = cc;
374         }
375         cusp.push_back(new RRTNode(c->x(), c->y(), c->h()));
376         std::reverse(cusp.begin(), cusp.end());
377         this->cusp().push_back(cusp);
378 }
379
380 BicycleCar *ParallelSlot::flncr(BicycleCar *B)
381 {
382         RRTNode *cc;
383         if (this->slotSide() == LEFT) {
384                 if (int(B->s()) % 2 == 0)
385                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
386                 else
387                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
388         } else {
389                 if (int(B->s()) % 2 == 0)
390                         cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
391                 else
392                         cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
393         }
394         BicycleCar *p;
395         int i = 1;
396         p = B->move(cc, i * this->DH());
397         while (
398                 !this->slot().collide(p->frame())
399                 && ((
400                         this->slotSide() == LEFT
401                         && this->slot().collide(new RRTNode(
402                                 p->lfx(),
403                                 p->lfy(),
404                                 0
405                         ))
406                 ) || (
407                         this->slotSide() == RIGHT
408                         && this->slot().collide(new RRTNode(
409                                 p->rfx(),
410                                 p->rfy(),
411                                 0
412                         ))
413                 ))
414         ) {
415                 delete p;
416                 i += 10;
417                 p = B->move(cc, i * this->DH());
418         }
419         i -= 10;
420         p = B->move(cc, i * this->DH());
421         while (!this->slot().collide(p->frame())) {
422                 if(
423                         this->slotSide() == LEFT
424                         && !this->slot().collide(new RRTNode(
425                                 p->lfx(),
426                                 p->lfy(),
427                                 0
428                         ))
429                 ) {
430                         i += 1;
431                         break;
432                 }
433                 if(
434                         this->slotSide() == RIGHT
435                         && !this->slot().collide(new RRTNode(
436                                 p->rfx(),
437                                 p->rfy(),
438                                 0
439                         ))
440                 ) {
441                         i += 1;
442                         break;
443                 }
444                 i += 1;
445                 p = B->move(cc, i * this->DH());
446         }
447         delete p;
448         return B->move(cc, (i - 1) * this->DH());
449 }
450
451 RRTNode *ParallelSlot::fposecenter()
452 {
453         return this->slot().bnodes().front();
454 }
455
456 bool ParallelSlot::flast(
457         RRTNode *P,
458         bool right,
459         int il,
460         std::vector<RRTNode *> &cusp
461 )
462 {
463         BicycleCar *B = new BicycleCar(P->x(), P->y(), P->h());
464         RRTNode *cc;
465         if (right)
466                 cc = BicycleCar(B->x(), B->y(), B->h()).ccr();
467         else
468                 cc = BicycleCar(B->x(), B->y(), B->h()).ccl();
469         BicycleCar *p;
470         int i = 1;
471         p = B->move(cc, i * this->DH());
472         while (!this->slot().collide(p->frame())
473                         && (
474                                 (this->DH() > 0 && p->x() <= 0)
475                                 || (this->DH() < 0 && p->x() >= 0)
476                         )) {
477                 delete p;
478                 i += 10;
479                 p = B->move(cc, i * this->DH());
480         }
481         i -= 10;
482         p = B->move(cc, i * this->DH());
483         while (!this->slot().collide(p->frame())
484                         && (
485                                 (this->DH() > 0 && p->x() <= 0)
486                                 || (this->DH() < 0 && p->x() >= 0)
487                         )) {
488                 if (this->DH() > 0 && p->rfx() <= 0 && p->rrx() <= 0) {
489                         i += 1;
490                         break;
491                 }
492                 if (this->DH() < 0 && p->lfx() >= 0 && p->lrx() >= 0) {
493                         i += 1;
494                         break;
495                 }
496                 delete p;
497                 i += 1;
498                 p = B->move(cc, i * this->DH());
499         }
500         delete p;
501         p = B->move(cc, (i - 1) * this->DH());
502         if (this->DH() > 0 && p->rfx() <= 0 && p->rrx() <= 0) {
503                 cusp.push_back(p);
504                 return true;
505         } else if (this->DH() < 0 && p->lfx() >= 0 && p->lrx() >= 0) {
506                 cusp.push_back(p);
507                 return true;
508         } else if (il < 8) {
509                 cusp.push_back(p);
510                 return this->flast(p, !right, il + 1, cusp);
511         }
512         return false;
513 }
514
515 void ParallelSlot::fpose()
516 {
517         bool left = false; // right parking slot
518         float di = -1;
519         BicycleCar *CC = new BicycleCar(
520                 this->fposecenter()->x(),
521                 this->fposecenter()->y() - 0.01,
522                 this->slotHeading()
523         );
524         BicycleCar *B = new BicycleCar(
525                 CC->x() - CC->width() / 2,
526                 CC->y() - (CC->length() + CC->wheelbase()) / 2,
527                 this->slotHeading()
528         );
529         if (this->slot().bnodes()[0]->x() > this->slot().bnodes()[1]->x()) {
530                 left = true;
531                 di = 1;
532                 delete B;
533                 B = new BicycleCar(
534                         CC->x() + CC->width() / 2,
535                         CC->y() - (CC->length() + CC->wheelbase()) / 2,
536                         this->slotHeading()
537                 );
538         }
539         this->DH(di * 0.01 / CC->out_radi());
540         BicycleCar *p;
541         int i = 0;
542         p = B->move(CC, -i * di * 0.01 / CC->diag_radi());
543         while (!this->slot().collide(p->frame())) {
544                 std::vector<RRTNode *> tmpcusp;
545                 tmpcusp.push_back(new BicycleCar(p->x(), p->y(), p->h()));
546                 if (this->flast(p, left, 0, tmpcusp)) {
547                         this->cusp().push_back(tmpcusp);
548                         return;
549                 }
550                 i += 1;
551                 delete p;
552                 p = B->move(CC, -i * di * 0.01 / CC->diag_radi());
553         }
554 }
555
556 BicycleCar *ParallelSlot::getEP()
557 {
558         // new pose for parallel parking to right slot
559         float tnx;
560         float tny;
561         float nx;
562         float ny;
563         BicycleCar *CC = this->getEPC();
564         // move left by car width / 2
565         tnx = CC->x() + CC->width() / 2 * cos(CC->h() + M_PI / 2);
566         tny = CC->y() + CC->width() / 2 * sin(CC->h() + M_PI / 2);
567         if (this->slotSide() == LEFT) {
568                 // move right by car width / 2
569                 tnx = CC->x() + CC->width() / 2 * cos(CC->h() - M_PI / 2);
570                 tny = CC->y() + CC->width() / 2 * sin(CC->h() - M_PI / 2);
571         }
572         if (this->slotType() == PARALLEL) {
573                 // move down
574                 nx = tnx - (CC->length() + CC->wheelbase()) / 2 * cos(CC->h());
575                 ny = tny - (CC->length() + CC->wheelbase()) / 2 * sin(CC->h());
576         } else {
577                 // move down
578                 nx = tnx + (CC->length() - CC->wheelbase()) / 2 * cos(CC->h());
579                 ny = tny + (CC->length() - CC->wheelbase()) / 2 * sin(CC->h());
580         }
581         return new BicycleCar(nx, ny, CC->h());
582 }
583
584 BicycleCar *ParallelSlot::getEPC()
585 {
586         // new pose for parallel parking to right slot
587         float ta;
588         float nx;
589         float ny;
590         ta = this->slotHeading() + M_PI;
591         if (this->slotSide() == RIGHT)
592                 ta -= M_PI / 4;
593         else
594                 ta += M_PI / 4;
595         nx = this->fposecenter()->x() + 0.01 * cos(ta);
596         ny = this->fposecenter()->y() + 0.01 * sin(ta);
597         return new BicycleCar(nx, ny, this->slotHeading());
598 }
599
600 BicycleCar *ParallelSlot::getFP()
601 {
602         float x = this->slot().bnodes()[3]->x();
603         float y = this->slot().bnodes()[3]->y();
604         float h = this->slotHeading();
605         float nx;
606         float ny;
607         if (this->slotType() == PARALLEL) {
608                 if (this->slotSide() == LEFT) {
609                         nx = x + BCAR_WIDTH / 2 * cos(h + M_PI / 2);
610                         ny = y + BCAR_WIDTH / 2 * sin(h + M_PI / 2);
611                 } else {
612                         nx = x + BCAR_WIDTH / 2 * cos(h - M_PI / 2);
613                         ny = y + BCAR_WIDTH / 2 * sin(h - M_PI / 2);
614                 }
615                 x = nx + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * cos(h);
616                 y = ny + ((BCAR_LENGTH - BCAR_WHEEL_BASE) / 2 + 0.01) * sin(h);
617         } else {
618                 if (this->slotSide() == LEFT) {
619                         h -= M_PI / 2;
620                         nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
621                                 * cos(h + M_PI);
622                         ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
623                                 * sin(h + M_PI);
624                         x = nx + (BCAR_DIAG_RRADI) * cos(h + M_PI / 2);
625                         y = ny + (BCAR_DIAG_RRADI) * sin(h + M_PI / 2);
626                 } else {
627                         h += M_PI / 2;
628                         nx = x + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
629                                 * cos(h - M_PI);
630                         ny = y + (BCAR_LENGTH + BCAR_WHEEL_BASE) / 2
631                                 * sin(h - M_PI);
632                         x = nx + (BCAR_DIAG_RRADI) * cos(h - M_PI / 2);
633                         y = ny + (BCAR_DIAG_RRADI) * sin(h - M_PI / 2);
634                 }
635         }
636         return new BicycleCar(x, y, h);
637 }
638
639 bool ParallelSlot::isInside(BicycleCar *c)
640 {
641         bool inside = true;
642         RRTNode *tmpn;
643         tmpn = new RRTNode(c->lfx(), c->lfy(), 0);
644         if (!this->slot().collide(tmpn))
645                 inside = false;
646         delete tmpn;
647         tmpn = new RRTNode(c->lrx(), c->lry(), 0);
648         if (!this->slot().collide(tmpn))
649                 inside = false;
650         delete tmpn;
651         tmpn = new RRTNode(c->rrx(), c->rry(), 0);
652         if (!this->slot().collide(tmpn))
653                 inside = false;
654         delete tmpn;
655         tmpn = new RRTNode(c->rfx(), c->rfy(), 0);
656         if (!this->slot().collide(tmpn))
657                 inside = false;
658         delete tmpn;
659         return inside;
660 }
661
662 struct SamplingInfo ParallelSlot::getSamplingInfo()
663 {
664         struct SamplingInfo si;
665         if (this->slotType() == PARALLEL) {
666                 si.x = this->slot().bnodes().front()->x();
667                 si.y = this->slot().bnodes().front()->y();
668                 si.mr = BCAR_WIDTH / 2;
669                 si.mmh = 0;
670         } else {
671                 si.x = this->slot().bnodes().back()->x();
672                 si.x -= this->slot().bnodes().front()->x();
673                 si.x /= 2;
674                 si.x += this->slot().bnodes().front()->x();
675                 si.y = this->slot().bnodes().back()->y();
676                 si.y -= this->slot().bnodes().front()->y();
677                 si.y /= 2;
678                 si.y += this->slot().bnodes().front()->y();
679                 si.mr = 0;
680                 si.mmh = (M_PI - M_PI / 6) / 2;
681         }
682         si.r = BCAR_LENGTH;
683         si.h = M_PI;
684         si.mh = M_PI / 2;
685         si.sh = this->slotHeading();
686         if (this->slotSide() == RIGHT)
687                 si.dh = 1;
688         else
689                 si.dh = -1;
690         return si;
691 }