]> rtime.felk.cvut.cz Git - hubacji1/rrts.git/blob - src/rrts.cc
Merge branch 'feature/store-node'
[hubacji1/rrts.git] / src / rrts.cc
1 #include <algorithm>
2 #include "rrts.h"
3
4 #include "reeds_shepp.h"
5
6 #define ETA 1.0 // for steer, nv
7 #define GAMMA(cV) ({ \
8         __typeof__ (cV) _cV = (cV); \
9         pow(log(_cV) / _cV, 1.0 / 3.0); \
10 })
11
12 template <typename T> int sgn(T val) {
13         return (T(0) < val) - (val < T(0));
14 }
15
16 RRTNode::RRTNode()
17 {
18 }
19
20 RRTNode::RRTNode(const BicycleCar &bc) : BicycleCar(bc)
21 {
22 }
23
24 Obstacle::Obstacle()
25 {
26 }
27
28 double RRTS::elapsed()
29 {
30         std::chrono::duration<double> dt;
31         dt = std::chrono::duration_cast<std::chrono::duration<double>>(
32                 std::chrono::high_resolution_clock::now()
33                 - this->tstart_
34         );
35         this->scnt_ = dt.count();
36         return this->scnt_;
37 }
38
39 bool RRTS::should_stop()
40 {
41         // the following counters must be updated, do not comment
42         this->icnt_++;
43         this->elapsed();
44         // decide the stop conditions (maybe comment some lines)
45         if (this->icnt_ > 999) return true;
46         if (this->scnt_ > 10) return true;
47         if (this->gf()) return true;
48         // but continue by default
49         return false;
50 }
51
52 void RRTS::store_node(RRTNode n)
53 {
54         this->nodes().push_back(n);
55 }
56
57 // RRT procedures
58 std::tuple<bool, unsigned int, unsigned int>
59 RRTS::collide(std::vector<std::tuple<double, double>> &poly)
60 {
61         for (auto &o: this->obstacles())
62                 if (std::get<0>(::collide(poly, o.poly())))
63                         return ::collide(poly, o.poly());
64         return std::make_tuple(false, 0, 0);
65 }
66
67 std::tuple<bool, unsigned int, unsigned int>
68 RRTS::collide_steered_from(RRTNode &f)
69 {
70         std::vector<std::tuple<double, double>> s;
71         s.push_back(std::make_tuple(f.x(), f.y()));
72         for (auto &n: this->steered()) {
73                 s.push_back(std::make_tuple(n.lfx(), n.lfy()));
74                 s.push_back(std::make_tuple(n.lrx(), n.lry()));
75                 s.push_back(std::make_tuple(n.rrx(), n.rry()));
76                 s.push_back(std::make_tuple(n.rfx(), n.rfy()));
77         }
78         auto col = this->collide(s);
79         auto strip_from = this->steered().size() - std::get<1>(col) / 4;
80         if (std::get<0>(col) && strip_from > 0) {
81                 while (strip_from-- > 0) {
82                         this->steered().pop_back();
83                 }
84                 return this->collide_steered_from(f);
85         }
86         return col;
87 }
88
89 std::tuple<bool, unsigned int, unsigned int>
90 RRTS::collide_two_nodes(RRTNode &f, RRTNode &t)
91 {
92         std::vector<std::tuple<double, double>> p;
93         p.push_back(std::make_tuple(f.lfx(), f.lfy()));
94         p.push_back(std::make_tuple(f.lrx(), f.lry()));
95         p.push_back(std::make_tuple(f.rrx(), f.rry()));
96         p.push_back(std::make_tuple(f.rfx(), f.rfy()));
97         p.push_back(std::make_tuple(t.lfx(), t.lfy()));
98         p.push_back(std::make_tuple(t.lrx(), t.lry()));
99         p.push_back(std::make_tuple(t.rrx(), t.rry()));
100         p.push_back(std::make_tuple(t.rfx(), t.rfy()));
101         return this->collide(p);
102 }
103
104 double RRTS::cost_build(RRTNode &f, RRTNode &t)
105 {
106         double cost = 0;
107         cost = sqrt(pow(t.y() - f.y(), 2) + pow(t.x() - f.x(), 2));
108         return cost;
109 }
110
111 double RRTS::cost_search(RRTNode &f, RRTNode &t)
112 {
113         double cost = 0;
114         cost = sqrt(pow(t.y() - f.y(), 2) + pow(t.x() - f.x(), 2));
115         return cost;
116 }
117
118 void RRTS::sample()
119 {
120         double x = this->ndx_(this->gen_);
121         double y = this->ndy_(this->gen_);
122         double h = this->ndh_(this->gen_);
123         this->samples().push_back(RRTNode());
124         this->samples().back().x(x);
125         this->samples().back().y(y);
126         this->samples().back().h(h);
127 }
128
129 RRTNode *RRTS::nn(RRTNode &t)
130 {
131         RRTNode *nn = &this->nodes().front();
132         double cost = this->cost_search(*nn, t);
133         for (auto &f: this->nodes()) {
134                 if (this->cost_search(f, t) < cost) {
135                         nn = &f;
136                         cost = this->cost_search(f, t);
137                 }
138         }
139         return nn;
140 }
141
142 std::vector<RRTNode *> RRTS::nv(RRTNode &t)
143 {
144         std::vector<RRTNode *> nv;
145         double cost = std::min(GAMMA(this->nodes().size()), ETA);
146         for (auto &f: this->nodes())
147                 if (this->cost_search(f, t) < cost)
148                         nv.push_back(&f);
149         return nv;
150 }
151
152 int cb_rs_steer(double q[4], void *user_data)
153 {
154         std::vector<RRTNode> *nodes = (std::vector<RRTNode> *) user_data;
155         RRTNode *ln = nullptr;
156         if (nodes->size() > 0)
157                 ln = &nodes->back();
158         nodes->push_back(RRTNode());
159         nodes->back().x(q[0]);
160         nodes->back().y(q[1]);
161         nodes->back().h(q[2]);
162         nodes->back().sp(q[3]);
163         if (nodes->back().sp() == 0)
164                 nodes->back().set_t(RRTNodeType::cusp);
165         else if (ln != nullptr && sgn(ln->sp()) != sgn(nodes->back().sp()))
166                 ln->set_t(RRTNodeType::cusp);
167         return 0;
168 }
169
170 void RRTS::steer(RRTNode &f, RRTNode &t)
171 {
172         this->steered().clear();
173         double q0[] = {f.x(), f.y(), f.h()};
174         double q1[] = {t.x(), t.y(), t.h()};
175         ReedsSheppStateSpace rsss(f.mtr());
176         rsss.sample(q0, q1, 0.5, cb_rs_steer, &this->steered());
177 }
178
179 void RRTS::join_steered(RRTNode *f)
180 {
181         while (this->steered().size() > 0) {
182                 this->store_node(this->steered().front());
183                 RRTNode *t = &this->nodes().back();
184                 t->p(f);
185                 t->c(this->cost_build(*f, *t));
186                 this->steered().erase(this->steered().begin());
187                 f = t;
188         }
189 }
190
191 bool RRTS::goal_found(RRTNode &f)
192 {
193         bool found = false;
194         for (auto &g: this->goals()) {
195                 double cost = this->cost_build(f, g);
196                 double edist = sqrt(
197                         pow(f.x() - g.x(), 2)
198                         + pow(f.y() - g.y(), 2)
199                 );
200                 double adist = std::abs(f.h() - g.h());
201                 if (edist < 0.05 && adist < M_PI / 32) {
202                         found = true;
203                         if (g.p() == nullptr || cc(f) + cost < cc(g)) {
204                                 g.p(&f);
205                                 g.c(cost);
206                         }
207                 }
208         }
209         return found;
210 }
211
212 // RRT* procedures
213 bool RRTS::connect()
214 {
215         RRTNode *t = &this->steered().front();
216         RRTNode *f = this->nn(this->samples().back());
217         double cost = this->cost_search(*f, *t);
218         for (auto n: this->nv(*t)) {
219                 if (
220                         !std::get<0>(this->collide_two_nodes(*n, *t))
221                         && this->cost_search(*n, *t) < cost
222                 ) {
223                         f = n;
224                         cost = this->cost_search(*n, *t);
225                 }
226         }
227         this->store_node(this->steered().front());
228         t = &this->nodes().back();
229         t->p(f);
230         t->c(this->cost_build(*f, *t));
231         t->set_t(RRTNodeType::connected);
232         return true;
233 }
234
235 void RRTS::rewire()
236 {
237         RRTNode *f = &this->nodes().back();
238         for (auto n: this->nv(*f)) {
239                 if (
240                         !std::get<0>(this->collide_two_nodes(*f, *n))
241                         && cc(*f) + this->cost_search(*f, *n) < cc(*n)
242                 ) {
243                         n->p(f);
244                         n->c(this->cost_build(*f, *n));
245                 }
246         }
247 }
248
249 // API
250 void RRTS::init()
251 {
252 }
253
254 void RRTS::deinit()
255 {
256 }
257
258 std::vector<RRTNode *> RRTS::path()
259 {
260         std::vector<RRTNode *> path;
261         if (this->goals().size() == 0)
262                 return path;
263         RRTNode *goal = &this->goals().front();
264         for (auto &n: this->goals()) {
265                 if (
266                         n.p() != nullptr
267                         && (n.c() < goal->c() || goal->p() == nullptr)
268                 ) {
269                         goal = &n;
270                 }
271         }
272         if (goal->p() == nullptr)
273                 return path;
274         while (goal != nullptr) {
275                 path.push_back(goal);
276                 goal = goal->p();
277         }
278         std::reverse(path.begin(), path.end());
279         return path;
280 }
281
282 bool RRTS::next()
283 {
284         if (this->icnt_ == 0)
285                 this->tstart_ = std::chrono::high_resolution_clock::now();
286         bool next = true;
287         if (this->should_stop())
288                 return false;
289         this->sample();
290         this->steer(
291                 *this->nn(this->samples().back()),
292                 this->samples().back()
293         );
294         if (std::get<0>(this->collide_steered_from(
295                 *this->nn(this->samples().back())
296         )))
297                 return next;
298         if (!this->connect())
299                 return next;
300         this->rewire();
301         unsigned scnt = this->steered().size();
302         this->steered().erase(this->steered().begin());
303         this->join_steered(&this->nodes().back());
304         RRTNode *just_added = &this->nodes().back();
305         while (scnt > 0) {
306                 scnt--;
307                 for (auto &g: this->goals()) {
308                         this->steer(*just_added, g);
309                         if (std::get<0>(this->collide_steered_from(
310                                 *just_added
311                         )))
312                                 continue;
313                         this->join_steered(just_added);
314                 }
315                 this->gf(this->goal_found(this->nodes().back()));
316                 just_added = just_added->p();
317         }
318         return next;
319 }
320
321 void RRTS::set_sample(
322         double mx, double dx,
323         double my, double dy,
324         double mh, double dh
325 )
326 {
327         this->ndx_ = std::normal_distribution<double>(mx, dx);
328         this->ndy_ = std::normal_distribution<double>(my, dy);
329         this->ndh_ = std::normal_distribution<double>(mh, dh);
330 }
331
332 RRTS::RRTS()
333         : gen_(std::random_device{}())
334 {
335         this->goals().reserve(100);
336         this->nodes().reserve(4000000);
337         this->samples().reserve(1000);
338         this->steered().reserve(20000);
339         this->store_node(RRTNode()); // root
340 }
341
342 double cc(RRTNode &t)
343 {
344         RRTNode *n = &t;
345         double cost = 0;
346         while (n != nullptr) {
347                 cost += n->c();
348                 n = n->p();
349         }
350         return cost;
351 }