]> rtime.felk.cvut.cz Git - hubacji1/iamcar.git/blob - base/main.cc
61fd55f30bdad9446dfb407a75f2bdfa68b5beb8
[hubacji1/iamcar.git] / base / main.cc
1 /*
2 This file is part of I am car.
3
4 I am car is nree 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 <chrono>
20 #include <cmath>
21 #include <cstdlib>
22 #include <iostream>
23 #include <jsoncpp/json/json.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <unistd.h>
27 #include "compile.h"
28 #include "obstacle.h"
29 #include "rrtplanner.h"
30 #include "slotplanner.h"
31
32 #if USE_GL > 0
33 // OpenGL
34 #include <GL/gl.h>
35 #include <GL/glu.h>
36 #include <SDL2/SDL.h>
37 #endif
38
39 // debug
40 //#define JSONLOGEDGES
41 //#define JSONLOGSAMPLES
42
43 #if USE_GL > 0
44         #define USE_INTERRUPT
45 #else
46         // choose
47         //#define USE_INTERRUPT
48         // or
49         #define USE_TMAX
50         // or
51         //#define USE_LOADF
52         // or
53         //#define USE_PTHREAD
54 #endif
55
56 // OpenGL window size
57 #define SCREEN_WIDTH 1000
58 #define SCREEN_HEIGHT 1000
59
60 std::chrono::high_resolution_clock::time_point TSTART_;
61 std::chrono::high_resolution_clock::time_point TEND_;
62 float TELAPSED = 0;
63 float ELAPSED = 0;
64 void TSTART() {TSTART_ = std::chrono::high_resolution_clock::now();}
65 void TEND() {
66         std::chrono::duration<float> DT_;
67         TEND_ = std::chrono::high_resolution_clock::now();
68         DT_ = std::chrono::duration_cast<std::chrono::duration<float>>(
69                 TEND_ - TSTART_
70         );
71         TELAPSED += DT_.count();
72         ELAPSED = DT_.count();
73 }
74 void TPRINT(const char *what) {
75         std::chrono::duration<float> DT_;
76         DT_ = std::chrono::duration_cast<std::chrono::duration<float>>(
77                 TEND_ - TSTART_
78         );
79         std::cerr << what << ": " << DT_.count() << std::endl;
80 }
81
82 bool run_planner = true;
83
84 #if USE_GL > 0
85 SDL_Window* gw = NULL;
86 SDL_GLContext gc;
87
88 bool init();
89 bool initGL();
90 #endif
91
92 void hint(int)
93 {
94         run_planner = false;
95 }
96
97 #ifdef USE_PTHREAD
98 struct next_arg {
99         bool *gf;
100         T2 *p;
101 };
102
103 void *next_run(void *arg)
104 {
105         struct next_arg *na = (struct next_arg *) arg;
106         T2 *lp = (T2 *) na->p;
107         bool *gf = na->gf;
108         while (!*gf && lp->elapsed() < TMAX) {
109                 if (lp->next())
110                         *gf = true;
111                 lp->tend();
112         }
113         pthread_exit(NULL);
114         return NULL;
115 }
116 #endif
117
118 RRTNode *sa_tmp()
119 {
120         float new_x = 1 + static_cast<float>(rand()) /
121                 static_cast<float>(RAND_MAX / (6.6 - 1 - 1));
122         float new_y = 1;
123         float new_h = M_PI / 2;
124         return new RRTNode(new_x, new_y, new_h);
125 }
126
127 int main()
128 {
129         srand(static_cast<unsigned>(time(0)));
130 #if USE_GL > 0
131         init();
132 #endif
133
134         Json::Value jvi; // JSON input
135         Json::Value jvo; // JSON output
136         unsigned int i = 0;
137         unsigned int j = 0;
138         std::cin >> jvi;
139         std::string encoding = jvi.get("encoding", "UTF-8" ).asString();
140
141         if (jvi["init"] == Json::nullValue) {
142                 std::cerr << "I need `init` in JSON input scenario";
143                 std::cerr << std::endl;
144                 return 1;
145         }
146
147         if (jvi["goal"] == Json::nullValue) {
148                 std::cerr << "I need `goal` in JSON input scenario";
149                 std::cerr << std::endl;
150                 return 1;
151         }
152
153         PLANNER p(
154                 new RRTNode(
155                         jvi["init"][0].asFloat(),
156                         jvi["init"][1].asFloat(),
157                         jvi["init"][2].asFloat()
158                 ),
159                 new RRTNode(
160                         jvi["goal"][0].asFloat(),
161                         jvi["goal"][1].asFloat(),
162                         jvi["goal"][2].asFloat()
163                 )
164         );
165         jvo["init"][0] = p.root()->x();
166         jvo["init"][1] = p.root()->y();
167         jvo["init"][2] = p.root()->h();
168         std::vector<CircleObstacle> co;
169         std::vector<SegmentObstacle> so;
170         p.HMIN = p.root()->x();
171         p.HMAX = p.root()->x();
172         p.VMIN = p.root()->y();
173         p.VMAX = p.root()->y();
174         j = 0;
175         for (auto o: jvi["obst"]) {
176                 float tmpx;
177                 float tmpy;
178                 float tmpr;
179                 float tmps;
180                 for (i = 0; i < o.size() - 1; i++) {
181                         tmpx = o[i][0].asFloat();
182                         tmpy = o[i][1].asFloat();
183                         tmpr = o[i + 1][0].asFloat();
184                         tmps = o[i + 1][1].asFloat();
185                         so.push_back(SegmentObstacle(
186                                 new RRTNode(tmpx, tmpy, 0),
187                                 new RRTNode(tmpr, tmps, 0)
188                         ));
189                         p.frame().add_bnode(so.back().init());
190                         if (tmpx < p.HMIN) p.HMIN = tmpx;
191                         if (tmpx > p.HMAX) p.HMAX = tmpx;
192                         if (tmpy < p.VMIN) p.VMIN = tmpy;
193                         if (tmpy > p.VMAX) p.VMAX = tmpy;
194                         if (tmpr < p.HMIN) p.HMIN = tmpr;
195                         if (tmpr > p.HMAX) p.HMAX = tmpr;
196                         if (tmps < p.VMIN) p.VMIN = tmps;
197                         if (tmps > p.VMAX) p.VMAX = tmps;
198
199                         // output
200                         jvo["obst"][j][i][0] = tmpx;
201                         jvo["obst"][j][i][1] = tmpy;
202                 }
203                 jvo["obst"][j][i][0] = tmpr;
204                 jvo["obst"][j][i][1] = tmps;
205                 j++;
206         }
207         p.defaultSamplingInfo();
208         p.link_obstacles(&co, &so);
209         p.ocost(p.root());
210         p.ocost(p.goal());
211
212         ParallelSlot ps = ParallelSlot();
213         if (
214                 jvi["slot"] != Json::nullValue &&
215                 jvi["slot"]["polygon"] != Json::nullValue
216         ) {
217                 for (auto xy: jvi["slot"]["polygon"]) {
218                         ps.slot().add_bnode(new RRTNode(
219                                 xy[0].asFloat(),
220                                 xy[1].asFloat()
221                         ));
222                 }
223                 for (auto e: ps.slot().frame())
224                         so.push_back(SegmentObstacle(e->init(), e->goal()));
225         }
226 #ifdef USE_SLOTPLANNER
227         TSTART();
228         if (ps.slot().bnodes().size() > 0)
229                 ps.fip(co, so);
230         TEND();
231         jvo["ppse"] = ELAPSED;
232         TPRINT("ParallelSlot");
233 #endif
234         if (ps.slot().bnodes().size() > 0) {
235                 ps.setAll();
236                 //if (ps.getMidd() != nullptr)
237                 //        p.setSamplingInfo(ps.getSamplingInfo());
238         }
239         if (ps.cusp().size() > 0) {
240                 p.goal(ps.getMidd());
241                 p.slot_cusp(ps.cusp().front()); // use first found solution
242                 p.goals(ps.goals());
243                 jvo["midd"][0] = p.goal()->x();
244                 jvo["midd"][1] = p.goal()->y();
245                 jvo["midd"][2] = p.goal()->h();
246                 jvo["goal"][0] = p.slot_cusp().back()->x();
247                 jvo["goal"][1] = p.slot_cusp().back()->y();
248                 jvo["goal"][2] = p.slot_cusp().back()->h();
249         } else {
250                 jvo["goal"][0] = p.goal()->x();
251                 jvo["goal"][1] = p.goal()->y();
252                 jvo["goal"][2] = p.goal()->h();
253         }
254         TSTART();
255         std::cerr << "Slot Info:" << std::endl;
256         if (ps.slotSide() == LEFT)
257                 std::cerr << "- LEFT" << std::endl;
258         else
259                 std::cerr << "- RIGHT" << std::endl;
260         if (ps.slotType() == PARALLEL)
261                 std::cerr << "- PARALLEL" << std::endl;
262         else
263                 std::cerr << "- PERPENDICULAR" << std::endl;
264 #ifdef USE_LOADF
265         std::vector<RRTNode *> steered;
266         for (auto jn: jvi["traj"][0]) {
267                 steered.push_back(new RRTNode(
268                                         jn[0].asFloat(),
269                                         jn[1].asFloat(),
270                                         jn[2].asFloat(),
271                                         jn[3].asFloat(),
272                                         jn[4].asFloat()));
273         }
274         std::reverse(steered.begin(), steered.end());
275         RRTNode *pn = p.root();
276         for (auto n: steered) {
277                 if (IS_NEAR(pn, n))
278                         continue;
279                 pn->add_child(n, p.cost(pn, n));
280                 pn = n;
281                 p.glplot();
282         }
283         pn->add_child(p.goal(), p.cost(pn, p.goal()));
284         p.goal_found(true);
285         p.tlog(p.findt());
286         if (p.opt_path()) {
287                 p.tlog(p.findt());
288                 p.glplot();
289         }
290         p.glplot();
291         sleep(2);
292 #elif defined USE_INTERRUPT
293         signal(SIGINT, hint);
294         signal(SIGTERM, hint);
295         p.tstart();
296         while (run_planner) {
297                 p.next();
298                 p.tend();
299                 if (p.opt_path())
300                         p.tlog(p.findt());
301                 p.glplot();
302         }
303 #elif defined USE_TMAX
304         p.tstart();
305         p.tend();
306         while (!p.goal_found() && p.elapsed() < TMAX) {
307                 p.next();
308                 p.tend();
309                 if (p.opt_path()) {
310                         p.tlog(p.findt());
311                 }
312         }
313         if (p.goal_found() && ps.slotType() == PARALLEL)
314                 p.tlog(p.findt(p.slot_cusp().back()));
315 #elif defined USE_PTHREAD
316         bool gf = false;
317         RRTNode *ron = nullptr;
318         RRTNode *gon = nullptr;
319         float mc = 9999;
320         pthread_t rt; // root thread
321         pthread_t gt; // goal thread
322         pthread_t ct; // connect thread
323
324         struct next_arg ra;
325         ra.gf = &gf;
326         ra.p = &p.p_root_;
327
328         struct next_arg ga;
329         ga.gf = &gf;
330         ga.p = &p.p_goal_;
331
332         p.tstart();
333         p.p_root_.tstart();
334         p.p_goal_.tstart();
335         pthread_create(&rt, NULL, &next_run, (void *) &ra);
336         pthread_create(&gt, NULL, &next_run, (void *) &ga);
337         int tol = 0;
338         int ndl = 0;
339         bool ndone = true;
340         while (!gf && p.elapsed() < TMAX &&
341                         p.p_root_.nodes().size() < NOFNODES &&
342                         p.p_goal_.nodes().size() < NOFNODES) {
343                 // overlap trees
344                 ndone = true;
345                 for (int i = 0; i < IXSIZE; i++) {
346                 for (int j = 0; j < IYSIZE; j++) {
347                         if (p.p_root_.ixy_[i][j].changed() &&
348                                         p.p_goal_.ixy_[i][j].changed()) {
349 ndone = false;
350 for (auto rn: p.p_root_.ixy_[i][j].nodes()) {
351 for (auto gn: p.p_goal_.ixy_[i][j].nodes()) {
352         if (rn->ccost() + gn->ccost() < mc &&
353                         IS_NEAR(rn, gn)) {
354                 gf = true;
355                 p.goal_found(true);
356                 ron = rn;
357                 gon = gn;
358                 mc = rn->ccost() + gn->ccost();
359         }
360 }}
361                         }
362                         tol++;
363                         if (ndone)
364                                 ndl++;
365                         p.tend();
366                         if (p.elapsed() >= TMAX)
367                                 goto escapeloop;
368                 }}
369                 // end of overlap trees
370                 p.tend();
371         }
372 escapeloop:
373         pthread_join(rt, NULL);
374         pthread_join(gt, NULL);
375         float nodo = ((float) ndl / (float) tol);
376         std::cerr << "nothing done is " << 100.0 * nodo;
377         std::cerr << "%" << std::endl;
378         //std::cerr << "rgf is " << p.p_root_.goal_found() << std::endl;
379         //std::cerr << "ggf is " << p.p_goal_.goal_found() << std::endl;
380         //std::cerr << "cgf is " << p.goal_found() << std::endl;
381         if (p.p_root_.goal_found() && p.p_root_.goal()->ccost() < mc) {
382                 ron = p.p_root_.goal()->parent();
383                 gon = p.p_root_.goal();
384                 mc = p.p_root_.goal()->ccost();
385         }
386         if (p.p_goal_.goal_found() && p.p_goal_.goal()->ccost() < mc) {
387                 ron = p.p_goal_.goal();
388                 gon = p.p_goal_.goal()->parent();
389                 mc = p.p_goal_.goal()->ccost();
390         }
391         p.root()->remove_parent();  // needed if p.p_goal_.goal_found()
392         p.root()->ccost(0);
393         p.goal()->children().clear();
394         // connect trees
395         if (gf) {
396         while (gon != p.goal()) {
397                 p.p_root_.nodes().push_back(new RRTNode(
398                                 gon->x(),
399                                 gon->y(),
400                                 gon->h()));
401                 ron->add_child(
402                                 p.p_root_.nodes().back(),
403                                 p.p_root_.cost(
404                                                 ron,
405                                                 p.p_root_.nodes().back()));
406                 ron = p.p_root_.nodes().back();
407                 gon = gon->parent();
408         }
409         ron->add_child(p.goal(), p.p_root_.cost(ron, p.goal()));
410         }
411         // end of connect trees
412         if (gf)
413                 p.tlog(p.findt());
414         if (p.opt_path())
415                 p.tlog(p.findt());
416 #endif
417         TEND();
418         TPRINT("RRT");
419         jvo["rrte"] = ELAPSED;
420 #ifdef JSONLOGEDGES
421         p.logr(p.root());
422 #endif
423
424         // statistics to error output
425         std::cerr << "TELAPSED is " << TELAPSED << std::endl;
426         std::cerr << "Elapsed is " << p.elapsed() << std::endl;
427         std::cerr << "Goal found is " << p.goal_found() << std::endl;
428         std::cerr << "#nodes is " << p.nodes().size() << std::endl;
429         std::cerr << "#samples is " << p.samples().size() << std::endl;
430         std::cerr << "`tlog` size is " << p.tlog().size() << std::endl;
431         std::cerr << "trajectories costs:" << std::endl;
432         for (j = 0; j < p.clog().size(); j++)
433                 std::cerr << "- " << p.clog()[j] << std::endl;
434         std::cerr << "RRT #nodes:" << std::endl;
435         for (j = 0; j < p.nlog().size(); j++)
436                 std::cerr << "- " << p.nlog()[j] << std::endl;
437         std::cerr << "trajectories seconds:" << std::endl;
438         for (j = 0; j < p.slog().size(); j++)
439                 std::cerr << "- " << p.slog()[j] << std::endl;
440         std::cerr << "RRT edges (from root) log size: " << p.rlog().size();
441         std::cerr << std::endl;
442         for (auto edges: p.rlog())
443                 std::cerr << "- " << edges.size() << std::endl;
444
445         // JSON output
446         jvo["elap"] = TELAPSED;
447 #ifdef USE_PTHREAD
448         jvo["nodo"][0] = nodo;
449 #endif
450         // log cost
451         for (j = 0; j < p.clog().size(); j++)
452                 jvo["cost"][j] = p.clog()[j];
453         // log #nodes
454         for (j = 0; j < p.nlog().size(); j++)
455                 jvo["node"][j] = p.nlog()[j];
456         // log seconds
457         for (j = 0; j < p.slog().size(); j++)
458                 jvo["secs"][j] = p.slog()[j];
459         // log traj
460         i = 0;
461         j = 0;
462         for (auto traj: p.tlog()) {
463                 i = 0;
464                 for (auto n: traj) {
465                         jvo["traj"][j][i][0] = n->x();
466                         jvo["traj"][j][i][1] = n->y();
467                         jvo["traj"][j][i][2] = n->h();
468                         jvo["traj"][j][i][3] = n->t();
469                         jvo["traj"][j][i][4] = n->s();
470                         i++;
471                 }
472                 j++;
473         }
474 #ifdef JSONLOGEDGES
475         i = 0;
476         j = 0;
477         for (auto edges: p.rlog()) {
478                 j = 0;
479                 for (auto e: edges) {
480                         jvo["edge"][i][j][0][0] = e->init()->x();
481                         jvo["edge"][i][j][0][1] = e->init()->y();
482                         jvo["edge"][i][j][0][2] = e->init()->h();
483                         jvo["edge"][i][j][1][0] = e->goal()->x();
484                         jvo["edge"][i][j][1][1] = e->goal()->y();
485                         jvo["edge"][i][j][1][2] = e->goal()->h();
486                         j++;
487                 }
488                 i++;
489         }
490 #endif
491 #ifdef JSONLOGSAMPLES
492         i = 0;
493         j = 0;
494         for (auto s: p.samples()) {
495                 jvo["samp"][j][0] = s->x();
496                 jvo["samp"][j][1] = s->y();
497                 jvo["samp"][j][2] = s->h();
498                 j++;
499         }
500 #endif
501         // print output
502         std::cout << jvo << std::endl;
503
504 #if USE_GL > 0
505         SDL_DestroyWindow(gw);
506         SDL_Quit();
507 #endif
508
509         // free mem
510         for (auto o: so) {
511                 delete o.init();
512                 delete o.goal();
513         }
514         return 0;
515 }
516
517 #if USE_GL > 0
518 bool init()
519 {
520         if (SDL_Init(SDL_INIT_VIDEO) < 0) {
521                 std::cerr << "SDL could not initialize! SDL_Error: ";
522                 std::cerr << SDL_GetError();
523                 std::cerr << std::endl;
524                 return false;
525         }
526         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
527         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
528         gw = SDL_CreateWindow(
529                         "I am car",
530                         SDL_WINDOWPOS_UNDEFINED,
531                         SDL_WINDOWPOS_UNDEFINED,
532                         SCREEN_WIDTH,
533                         SCREEN_HEIGHT,
534                         SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
535         if (gw == NULL) {
536                 std::cerr << "Window could not be created! SDL_Error: ";
537                 std::cerr << SDL_GetError();
538                 std::cerr << std::endl;
539                 return false;
540         }
541         gc = SDL_GL_CreateContext(gw);
542         if (gc == NULL) {
543                 std::cerr << "OpenGL context couldn't be created! SDL Error: ";
544                 std::cerr << SDL_GetError();
545                 std::cerr << std::endl;
546                 return false;
547         }
548         if (SDL_GL_SetSwapInterval(1) < 0) {
549                 std::cerr << "Warning: Unable to set VSync! SDL Error: ";
550                 std::cerr << SDL_GetError();
551                 std::cerr << std::endl;
552                 return false;
553         }
554         if (!initGL()) {
555                 std::cerr << "Unable to initialize OpenGL!";
556                 std::cerr << std::endl;
557                 return false;
558         }
559         return true;
560 }
561
562 bool initGL()
563 {
564         GLenum error = GL_NO_ERROR;
565         glMatrixMode(GL_PROJECTION);
566         glLoadIdentity();
567         error = glGetError();
568         if (error != GL_NO_ERROR) {
569                 std::cerr << "Error initializing OpenGL! ";
570                 std::cerr << gluErrorString(error);
571                 std::cerr << std::endl;
572                 return false;
573         }
574         glMatrixMode(GL_MODELVIEW);
575         glLoadIdentity();
576         error = glGetError();
577         if (error != GL_NO_ERROR) {
578                 std::cerr << "Error initializing OpenGL! ";
579                 std::cerr << gluErrorString(error);
580                 std::cerr << std::endl;
581                 return false;
582         }
583         glClearColor(1, 1, 1, 1);
584         error = glGetError();
585         if (error != GL_NO_ERROR) {
586                 std::cerr << "Error initializing OpenGL! ";
587                 std::cerr << gluErrorString(error);
588                 std::cerr << std::endl;
589                 return false;
590         }
591         return true;
592 }
593 #endif