2 * SPDX-FileCopyrightText: 2021 Jiri Vlasak <jiri.vlasak.2@cvut.cz>
4 * SPDX-License-Identifier: GPL-3.0-only
12 #define USE_RRTS 0 // TODO improve, this solution isn't clear.
20 this->tstart_ = std::chrono::high_resolution_clock::now();
26 using namespace std::chrono;
27 auto t = high_resolution_clock::now() - this->tstart_;
28 auto d = duration_cast<duration<double>>(t);
41 assert(this->p_ != nullptr);
43 this->cc_ = this->p_->cc() + c;
59 RRTNode::p(RRTNode& p)
73 RRTNode::cusp(RRTNode const& p)
75 this->cusp_ = p.cusp();
76 if (this->sp() != p.sp() || this->sp() == 0.0) {
82 RRTNode::operator==(RRTNode const& n)
88 RRTS::recompute_cc(RRTNode* g)
91 while (g != nullptr) {
92 this->path_.push_back(g);
95 std::reverse(this->path_.begin(), this->path_.end());
96 for (unsigned int i = 1; i < this->path_.size(); i++) {
97 this->path_[i]->c(this->cost_build(*this->path_[i - 1],
103 RRTS::recompute_path_cc()
105 this->recompute_cc(&this->goal_);
109 RRTS::min_gamma_eta() const
111 double ns = this->nodes_.size();
112 double gamma = pow(log(ns) / ns, 1.0 / 3.0);
113 return std::min(gamma, this->eta_);
117 RRTS::should_continue() const
119 return !this->should_finish();
123 RRTS::join_steered(RRTNode* f)
125 while (this->steered_.size() > 0) {
126 this->store(this->steered_.front());
127 RRTNode* t = &this->nodes_.back();
129 t->c(this->cost_build(*f, *t));
131 this->steered_.erase(this->steered_.begin());
145 RRTNode* f = this->nn_;
146 RRTNode* t = &this->steered_.front();
148 double cost = f->cc() + this->cost_build(*f, *t);
149 for (auto n: this->nv_) {
150 double nc = n->cc() + this->cost_build(*n, *t);
156 // Check if it's possible to drive from *f to *t. If not, then fallback
157 // to *f = nn_. This could be also solved by additional steer from *f to
158 // *t instead of the following code.
159 this->bc_.set_pose(*f);
160 if (!this->bc_.drivable(*t)) {
164 this->store(this->steered_.front());
165 t = &this->nodes_.back();
167 t->c(this->cost_build(*f, *t));
169 this->steered_.erase(this->steered_.begin());
176 RRTNode *f = &this->nodes_.back();
177 for (auto n: this->nv_) {
178 double fc = f->cc() + this->cost_build(*f, *n);
179 this->bc_.set_pose(*f);
180 bool drivable = this->bc_.drivable(*n);
181 if (drivable && fc < n->cc()) {
183 n->c(this->cost_build(*f, *n));
189 RRTS::goal_drivable_from(RRTNode const& f)
191 this->bc_.set_pose(f);
192 return this->bc_.drivable(this->goal_);
196 RRTS::store(RRTNode n)
198 this->nodes_.push_back(n);
202 RRTS::cost_build(RRTNode const& f, RRTNode const& t) const
208 RRTS::cost_search(RRTNode const& f, RRTNode const& t) const
210 return this->cost_build(f, t);
214 RRTS::find_nn(RRTNode const& t)
216 this->nn_ = &this->nodes_.front();
217 this->cost_ = this->cost_search(*this->nn_, t);
218 for (auto& f: this->nodes_) {
219 if (this->cost_search(f, t) < this->cost_) {
221 this->cost_ = this->cost_search(f, t);
227 RRTS::find_nv(RRTNode const& t)
230 this->cost_ = this->min_gamma_eta();
231 for (auto& f: this->nodes_) {
232 if (this->cost_search(f, t) < this->cost_) {
233 this->nv_.push_back(&f);
242 RRTNode *g = &this->goal_;
243 if (g->p() == nullptr) {
246 while (g != nullptr && this->path_.size() < 10000) {
249 * There shouldn't be this->path_.size() < 10000 condition.
250 * However, the RRTS::compute_path() called from
251 * RRTExt13::compute_path tends to re-allocate this->path_
252 * infinitely. There's probably node->p() = &node somewhere...
254 this->path_.push_back(g);
257 std::reverse(this->path_.begin(), this->path_.end());
260 RRTS::RRTS() : goal_(0.0, 0.0, 0.0, 0.0), gen_(std::random_device{}())
262 this->nodes_.reserve(4000000);
263 this->steered_.reserve(1000);
264 this->path_.reserve(10000);
265 this->nv_.reserve(1000);
266 this->store(RRTNode()); // root
276 RRTS::set_imax_reset(unsigned int i)
282 RRTS::set_goal(double x, double y, double b, double e)
284 this->goal_ = RRTGoal(x, y, b, e);
288 RRTS::set_start(double x, double y, double h)
290 this->nodes_.front().x(x);
291 this->nodes_.front().y(y);
292 this->nodes_.front().h(h);
296 RRTS::get_path() const
298 std::vector<Pose> path;
299 for (auto n: this->path_) {
300 path.push_back(Pose(n->x(), n->y(), n->h()));
306 RRTS::get_path_cost() const
308 return this->goal_.cc();
318 RRTS::icnt(unsigned int i)
326 return this->ter_.scnt();
334 for (auto n: this->path_) {
335 jvo["path"][i][0] = n->x();
336 jvo["path"][i][1] = n->y();
337 jvo["path"][i][2] = n->h();
340 jvo["goal_cc"] = this->goal_.cc();
341 jvo["time"] = this->time_;
346 RRTS::json(Json::Value jvi)
348 assert(jvi["init"] != Json::nullValue);
349 assert(jvi["goal"] != Json::nullValue);
350 this->nodes_.front().x(jvi["init"][0].asDouble());
351 this->nodes_.front().y(jvi["init"][1].asDouble());
352 this->nodes_.front().h(jvi["init"][2].asDouble());
353 if (jvi["goal"].size() == 4) {
354 this->goal_ = RRTGoal(jvi["goal"][0].asDouble(),
355 jvi["goal"][1].asDouble(),
356 jvi["goal"][2].asDouble(),
357 jvi["goal"][3].asDouble());
359 this->goal_ = RRTGoal(jvi["goal"][0].asDouble(),
360 jvi["goal"][1].asDouble(),
361 jvi["goal"][2].asDouble(),
362 jvi["goal"][2].asDouble());
369 if (this->icnt_ == 0) {
373 auto rs = this->sample();
374 #if 1 // anytime RRTs
376 double d1 = this->cost_search(this->nodes_.front(), rs);
377 double d2 = this->cost_search(rs, this->goal_);
378 if (this->last_goal_cc_ != 0.0 && d1 + d2 > this->last_goal_cc_) {
379 rs = this->last_path_[rand() % this->last_path_.size()];
384 this->steer(this->nn(), rs);
385 if (this->collide_steered()) {
386 return this->should_continue();
389 this->find_nv(this->steered_.front());
391 if (!this->connect()) {
392 return this->should_continue();
397 unsigned int ss = this->steered_.size();
398 this->join_steered(&this->nodes_.back());
399 RRTNode* just_added = &this->nodes_.back();
401 while (ss > 0 && just_added->p() != nullptr) {
402 this->steer(*just_added, this->goal_);
403 if (this->collide_steered()) {
405 just_added = just_added->p();
408 this->join_steered(just_added);
409 bool gn = this->goal_.edist(this->nodes_.back()) < this->eta_;
410 bool gd = this->goal_drivable_from(this->nodes_.back());
412 double nc = this->cost_build(this->nodes_.back(),
414 double ncc = this->nodes_.back().cc() + nc;
415 if (this->goal_.p() == nullptr
416 || ncc < this->goal_.cc()) {
417 this->goal_.p(this->nodes_.back());
423 just_added = just_added->p();
426 this->compute_path();
428 this->time_ = this->ter_.scnt();
429 return this->should_continue();
435 if (this->goal_.cc() != 0.0 && this->goal_.cc() < this->last_goal_cc_) {
436 this->last_goal_cc_ = this->goal_.cc();
437 this->last_path_.clear();
438 for (auto n: this->path_) {
439 this->last_path_.push_back(*n);
442 this->goal_ = RRTGoal(this->goal_.x(), this->goal_.y(), this->goal_.b(),
445 this->steered_.clear();
446 this->nodes_.erase(this->nodes_.begin() + 1, this->nodes_.end());