]> rtime.felk.cvut.cz Git - hubacji1/iamcar2.git/blobdiff - rrts/src/rrts.cc
Merge branch 'fix-path-opt-ext13'
[hubacji1/iamcar2.git] / rrts / src / rrts.cc
index 7443bff89398e98ec00d5ccc14ba05bc9786023a..5a142174de1babc904991b1b15d0b680cd29e60f 100644 (file)
@@ -55,25 +55,37 @@ RRTNode::p() const
 }
 
 void
-RRTNode::p(RRTNode& p)
+RRTNode::p(RRTNode& p, bool can_be_too_close)
 {
-       if (this != &p) {
-               this->_p = &p;
+       assert(this != &p);
+       if (!can_be_too_close) {
+               assert(!(std::abs(p.x() - this->x()) < 1e-3
+                       && std::abs(p.y() - this->y()) < 1e-3
+                       && std::abs(p.h() - this->h()) < 1e-3));
        }
+       this->_p = &p;
+       this->p_is_cusp(this->would_be_cusp_if_parent(p));
+       this->cusp_cnt(p);
+}
+
+void
+RRTNode::p(RRTNode& p)
+{
+       return this->p(p, false);
 }
 
 unsigned int
-RRTNode::cusp() const
+RRTNode::cusp_cnt() const
 {
-       return this->_cusp;
+       return this->_cusp_cnt;
 }
 
 void
-RRTNode::cusp(RRTNode const& p)
+RRTNode::cusp_cnt(RRTNode const& p)
 {
-       this->_cusp = p.cusp();
-       if (this->sp() != p.sp() || this->sp() == 0.0) {
-               this->_cusp++;
+       this->_cusp_cnt = p.cusp_cnt();
+       if (this->_p_is_cusp) {
+               this->_cusp_cnt++;
        }
 }
 
@@ -89,6 +101,45 @@ RRTNode::st(int st)
        this->_segment_type = st;
 }
 
+bool
+RRTNode::p_is_cusp(void) const
+{
+       return this->_p_is_cusp;
+}
+
+void
+RRTNode::p_is_cusp(bool isit)
+{
+       this->_p_is_cusp = isit;
+}
+
+bool
+RRTNode::would_be_cusp_if_parent(RRTNode const& p) const
+{
+       if (std::abs(p.sp()) < 1e-3) {
+               // It should not be possible to have two zero speed nodes next
+               // to each other. In practice, this sometimes happens.
+               //assert(std::abs(this->sp()) > 1e-3);
+               if (p.p()) {
+                       if (sgn(p.p()->sp()) != sgn(this->sp())) {
+                               return true;
+                       } else {
+                               return false;
+                       }
+               } else {
+                       return true; // only root has no parent and it is cusp
+               }
+       } else {
+               if (std::abs(this->sp()) < 1e-3) {
+                       return false; // this is cusp, not the parent
+               } else if (sgn(p.sp()) != sgn(this->sp())) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+}
+
 bool
 RRTNode::operator==(RRTNode const& n)
 {
@@ -96,32 +147,32 @@ RRTNode::operator==(RRTNode const& n)
 }
 
 void
-RRTS::recompute_cc(RRTNode* g)
+RRTS::recompute_cc_for_predecessors_and(RRTNode* g)
 {
-       this->path_.clear();
+       std::vector<RRTNode*> path;
+       path.reserve(this->_path.size());
        while (g != nullptr) {
-               this->path_.push_back(g);
+               path.push_back(g);
                g = g->p();
        }
-       std::reverse(this->path_.begin(), this->path_.end());
-       for (unsigned int i = 1; i < this->path_.size(); i++) {
-               this->path_[i]->c(this->cost_build(*this->path_[i - 1],
-                       *this->path_[i]));
+       std::reverse(path.begin(), path.end());
+       for (unsigned int i = 1; i < path.size(); i++) {
+               path[i]->c(this->cost_build(*path[i - 1], *path[i]));
        }
 }
 
 void
 RRTS::recompute_path_cc()
 {
-       this->recompute_cc(&this->goal_);
+       this->recompute_cc_for_predecessors_and(&this->_goal);
 }
 
 double
 RRTS::min_gamma_eta() const
 {
-       double ns = this->nodes_.size();
+       double ns = this->_nodes.size();
        double gamma = pow(log(ns) / ns, 1.0 / 3.0);
-       return std::min(gamma, this->eta_);
+       return std::min(gamma, this->eta());
 }
 
 bool
@@ -133,28 +184,30 @@ RRTS::should_continue() const
 void
 RRTS::join_steered(RRTNode* f)
 {
-       while (this->steered_.size() > 0) {
-               this->store(this->steered_.front());
-               RRTNode* t = &this->nodes_.back();
+       while (this->_steered.size() > 0) {
+               this->store(this->_steered.front());
+               RRTNode* t = &this->_nodes.back();
                t->p(*f);
                t->c(this->cost_build(*f, *t));
-               t->cusp(*f);
-               this->steered_.erase(this->steered_.begin());
+               this->_steered.erase(this->_steered.begin());
                f = t;
        }
 }
 
-RRTNode&
-RRTS::nn()
-{
-       return *this->nn_;
-}
-
 bool
 RRTS::connect()
 {
-       RRTNode* f = this->nn_;
-       RRTNode* t = &this->steered_.front();
+       RRTNode* f = this->_nn;
+       RRTNode* t = &this->_steered.front();
+       // Require the steer method to return first node equal to nn:
+       assert(std::abs(t->x() - f->x()) < 1e-3
+               && std::abs(t->y() - f->y()) < 1e-3
+               && std::abs(t->h() - f->h()) < 1e-3);
+       this->_steered.erase(this->_steered.begin());
+       t = &this->_steered.front();
+       assert(!(std::abs(t->x() - f->x()) < 1e-3
+               && std::abs(t->y() - f->y()) < 1e-3
+               && std::abs(t->h() - f->h()) < 1e-3));
 #if USE_RRTS
        double cost = f->cc() + this->cost_build(*f, *t);
        for (auto n: this->nv_) {
@@ -165,30 +218,29 @@ RRTS::connect()
                }
        }
        // Check if it's possible to drive from *f to *t. If not, then fallback
-       // to *f = nn_. This could be also solved by additional steer from *f to
+       // to *f = _nn. This could be also solved by additional steer from *f to
        // *t instead of the following code.
-       this->bc_.set_pose(*f);
-       if (!this->bc_.drivable(*t)) {
-               f = this->nn_;
+       this->set_bc_pose_to(*f);
+       if (!this->_bc.drivable(*t)) {
+               f = this->_nn;
        }
 #endif
-       this->store(this->steered_.front());
-       t = &this->nodes_.back();
+       this->store(this->_steered.front());
+       t = &this->_nodes.back();
        t->p(*f);
        t->c(this->cost_build(*f, *t));
-       t->cusp(*f);
-       this->steered_.erase(this->steered_.begin());
+       this->_steered.erase(this->_steered.begin());
        return true;
 }
 
 void
 RRTS::rewire()
 {
-       RRTNode *f = &this->nodes_.back();
-       for (auto n: this->nv_) {
+       RRTNode *f = &this->_nodes.back();
+       for (auto n: this->_nv) {
                double fc = f->cc() + this->cost_build(*f, *n);
-               this->bc_.set_pose(*f);
-               bool drivable = this->bc_.drivable(*n);
+               this->set_bc_pose_to(*f);
+               bool drivable = this->_bc.drivable(*n);
                if (drivable && fc < n->cc()) {
                        n->p(*f);
                        n->c(this->cost_build(*f, *n));
@@ -199,14 +251,14 @@ RRTS::rewire()
 bool
 RRTS::goal_drivable_from(RRTNode const& f)
 {
-       this->bc_.set_pose(f);
-       return this->bc_.drivable(this->goal_);
+       this->set_bc_pose_to(f);
+       return this->_bc.drivable(this->_goal);
 }
 
 void
 RRTS::store(RRTNode n)
 {
-       this->nodes_.push_back(n);
+       this->_nodes.push_back(n);
 }
 
 double
@@ -224,12 +276,12 @@ RRTS::cost_search(RRTNode const& f, RRTNode const& t) const
 void
 RRTS::find_nn(RRTNode const& t)
 {
-       this->nn_ = &this->nodes_.front();
-       this->cost_ = this->cost_search(*this->nn_, t);
-       for (auto& f: this->nodes_) {
-               if (this->cost_search(f, t) < this->cost_) {
-                       this->nn_ = &f;
-                       this->cost_ = this->cost_search(f, t);
+       this->_nn = &this->_nodes.front();
+       this->_cost = this->cost_search(*this->_nn, t);
+       for (auto& f: this->_nodes) {
+               if (this->cost_search(f, t) < this->_cost) {
+                       this->_nn = &f;
+                       this->_cost = this->cost_search(f, t);
                }
        }
 }
@@ -237,11 +289,11 @@ RRTS::find_nn(RRTNode const& t)
 void
 RRTS::find_nv(RRTNode const& t)
 {
-       this->nv_.clear();
-       this->cost_ = this->min_gamma_eta();
-       for (auto& f: this->nodes_) {
-               if (this->cost_search(f, t) < this->cost_) {
-                       this->nv_.push_back(&f);
+       this->_nv.clear();
+       this->_cost = this->min_gamma_eta();
+       for (auto& f: this->_nodes) {
+               if (this->cost_search(f, t) < this->_cost) {
+                       this->_nv.push_back(&f);
                }
        }
 }
@@ -250,16 +302,16 @@ void
 RRTS::compute_path()
 {
        this->_path.clear();
-       RRTNode *g = &this->goal();
+       RRTNode *g = &this->_goal;
        if (g->p() == nullptr) {
                return;
        }
        while (g != nullptr && this->_path.size() < 10000) {
                /* FIXME in ext13
                 *
-                * There shouldn't be this->path_.size() < 10000 condition.
+                * There shouldn't be this->_path.size() < 10000 condition.
                 * However, the RRTS::compute_path() called from
-                * RRTExt13::compute_path tends to re-allocate this->path_
+                * RRTExt13::compute_path tends to re-allocate this->_path
                 * infinitely. There's probably node->p() = &node somewhere...
                 */
                this->_path.push_back(g);
@@ -268,7 +320,7 @@ RRTS::compute_path()
        std::reverse(this->_path.begin(), this->_path.end());
 }
 
-RRTS::RRTS() : goal_(0.0, 0.0, 0.0, 0.0), gen_(std::random_device{}())
+RRTS::RRTS() : _goal(0.0, 0.0, 0.0, 0.0), _gen(std::random_device{}())
 {
        this->_nodes.reserve(4000000);
        this->_steered.reserve(1000);
@@ -277,13 +329,19 @@ RRTS::RRTS() : goal_(0.0, 0.0, 0.0, 0.0), gen_(std::random_device{}())
        this->store(RRTNode()); // root
 }
 
-BicycleCar&
-RRTS::bc(void) const
+void
+RRTS::set_bc_pose_to(Pose const& p)
+{
+       this->_bc.set_pose_to(p);
+}
+
+void
+RRTS::set_bc_to_become(std::string what)
 {
-       return this->_bc;
+       this->_bc.become(what);
 }
 
-RRTGoal&
+RRTGoal const&
 RRTS::goal(void) const
 {
        return this->_goal;
@@ -319,6 +377,12 @@ RRTS::icnt_max(unsigned int i)
        this->_icnt_max = i;
 }
 
+void
+RRTS::tstart(void)
+{
+       this->_ter.start();
+}
+
 double
 RRTS::scnt() const
 {
@@ -326,11 +390,11 @@ RRTS::scnt() const
 }
 
 void
-RRTS::start(double x, double y, double h)
+RRTS::set_init_pose_to(Pose const& p)
 {
-       this->_nodes.front().x(x);
-       this->_nodes.front().y(y);
-       this->_nodes.front().h(h);
+       this->_nodes.front().x(p.x());
+       this->_nodes.front().y(p.y());
+       this->_nodes.front().h(p.h());
 }
 
 std::vector<Pose>
@@ -346,19 +410,17 @@ RRTS::path() const
 double
 RRTS::path_cost() const
 {
-       return this->goal().cc();
+       return this->_goal.cc();
 }
 
 double
 RRTS::last_path_cost(void) const
 {
-       return this->_last_path_cost;
-}
-
-void
-RRTS::last_path_cost(double c)
-{
-       this->_last_path_cost = c;
+       if (this->_logged_paths.size() == 0) {
+               return 0.0;
+       }
+       assert(this->_logged_paths.back().size() > 0);
+       return this->_logged_paths.back().back().cc();
 }
 
 double
@@ -374,19 +436,65 @@ RRTS::eta(double e)
 }
 
 Json::Value
-RRTS::json() const
+RRTS::json(void) const
 {
        Json::Value jvo;
-       unsigned int i = 0;
-       for (auto n: this->_path) { // TODO because path() has just x, y, h
+       unsigned int i = 0, j = 0;
+       for (auto path: this->_logged_paths) {
+               i = 0;
+               for (auto n: path) {
+                       jvo["paths"][j][i][0] = n.x();
+                       jvo["paths"][j][i][1] = n.y();
+                       jvo["paths"][j][i][2] = n.h();
+                       jvo["paths"][j][i][3] = n.sp();
+                       jvo["paths"][j][i][4] = n.st();
+                       jvo["paths"][j][i][5] = false;
+                       if (n.p_is_cusp()) {
+                               assert(i > 0);
+                               jvo["paths"][j][i - 1][5] = true;
+                       }
+                       i++;
+               }
+               // Initial point is part of the first segment.
+               jvo["paths"][j][0][3] = jvo["paths"][j][1][3];
+               jvo["paths"][j][0][4] = jvo["paths"][j][1][4];
+               // Goal point is part of the last segment.
+               jvo["paths"][j][i - 1][3] = jvo["paths"][j][i - 2][3];
+               jvo["paths"][j][i - 1][4] = jvo["paths"][j][i - 2][4];
+               // --
+               jvo["costs"][j] = path.back().cc();
+               j++;
+       }
+       i = 0;
+       for (auto n: this->_path) {
+               jvo["paths"][j][i][0] = n->x();
+               jvo["paths"][j][i][1] = n->y();
+               jvo["paths"][j][i][2] = n->h();
+               jvo["paths"][j][i][3] = n->sp();
+               jvo["paths"][j][i][4] = n->st();
+               jvo["paths"][j][i][5] = n->p_is_cusp();
                jvo["path"][i][0] = n->x();
                jvo["path"][i][1] = n->y();
                jvo["path"][i][2] = n->h();
                jvo["path"][i][3] = n->sp();
                jvo["path"][i][4] = n->st();
+               jvo["path"][i][5] = false;
+               if (n->p_is_cusp()) {
+                       assert(i > 0);
+                       jvo["path"][i - 1][5] = true;
+               }
                i++;
        }
-       jvo["goal_cc"] = this->goal().cc();
+       // Initial point is part of the first segment.
+       jvo["path"][0][3] = jvo["path"][1][3];
+       jvo["path"][0][4] = jvo["path"][1][4];
+       // Goal point is part of the last segment.
+       jvo["path"][i - 1][3] = jvo["path"][i - 2][3];
+       jvo["path"][i - 1][4] = jvo["path"][i - 2][4];
+       // --
+       jvo["costs"][j] = this->_path.back()->cc();
+       jvo["goal_cc"] = this->_goal.cc(); // TODO remove, use the following
+       jvo["cost"] = this->path_cost();
        jvo["time"] = this->scnt();
        return jvo;
 }
@@ -396,10 +504,10 @@ RRTS::json(Json::Value jvi)
 {
        assert(jvi["init"] != Json::nullValue);
        assert(jvi["goal"] != Json::nullValue);
-       this->start(
+       this->set_init_pose_to(Pose(
                jvi["init"][0].asDouble(),
                jvi["init"][1].asDouble(),
-               jvi["init"][2].asDouble());
+               jvi["init"][2].asDouble()));
        if (jvi["goal"].size() == 4) {
                this->goal(
                        jvi["goal"][0].asDouble(),
@@ -418,27 +526,27 @@ RRTS::json(Json::Value jvi)
 bool
 RRTS::next()
 {
-       if (this->icnt_ == 0) {
-               this->ter_.start();
+       if (this->icnt() == 0) {
+               this->tstart();
        }
-       this->icnt_ += 1;
        auto rs = this->sample();
 #if 1 // anytime RRTs
 {
-       double d1 = this->cost_search(this->nodes_.front(), rs);
-       double d2 = this->cost_search(rs, this->goal_);
-       if (this->last_goal_cc_ != 0.0 && d1 + d2 > this->last_goal_cc_) {
-               rs = this->last_path_[rand() % this->last_path_.size()];
+       double d1 = this->cost_search(this->_nodes.front(), rs);
+       double d2 = this->cost_search(rs, this->_goal);
+       if (this->last_path_cost() != 0.0 && d1 + d2 > this->last_path_cost()) {
+               auto& last_path = this->_logged_paths.back();
+               rs = last_path[rand() % last_path.size()];
        }
 }
 #endif
        this->find_nn(rs);
-       this->steer(this->nn(), rs);
+       this->steer(*this->_nn, rs);
        if (this->collide_steered()) {
                return this->should_continue();
        }
 #if USE_RRTS
-       this->find_nv(this->steered_.front());
+       this->find_nv(this->_steered.front());
 #endif
        if (!this->connect()) {
                return this->should_continue();
@@ -446,28 +554,31 @@ RRTS::next()
 #if USE_RRTS
        this->rewire();
 #endif
-       unsigned int ss = this->steered_.size();
-       this->join_steered(&this->nodes_.back());
-       RRTNode* just_added = &this->nodes_.back();
+       unsigned int ss = this->_steered.size();
+       this->join_steered(&this->_nodes.back());
+       RRTNode* just_added = &this->_nodes.back();
        bool gf = false;
-       while (ss > 0 && just_added->p() != nullptr) {
-               this->steer(*just_added, this->goal_);
+       while (ss > 0 && just_added != nullptr) {
+               this->steer(*just_added, this->_goal);
                if (this->collide_steered()) {
                        ss--;
                        just_added = just_added->p();
                        continue;
                }
+               // The first of steered is the same as just_added.
+               this->_steered.erase(this->_steered.begin());
                this->join_steered(just_added);
-               bool gn = this->goal_.edist(this->nodes_.back()) < this->eta_;
-               bool gd = this->goal_drivable_from(this->nodes_.back());
+               bool gn = this->_goal.edist(this->_nodes.back()) < this->eta();
+               bool gd = this->goal_drivable_from(this->_nodes.back());
                if (gn && gd) {
-                       double nc = this->cost_build(this->nodes_.back(),
-                               this->goal_);
-                       double ncc = this->nodes_.back().cc() + nc;
-                       if (this->goal_.p() == nullptr
-                                       || ncc < this->goal_.cc()) {
-                               this->goal_.p(this->nodes_.back());
-                               this->goal_.c(nc);
+                       double nc = this->cost_build(
+                               this->_nodes.back(),
+                               this->_goal);
+                       double ncc = this->_nodes.back().cc() + nc;
+                       if (this->_goal.p() == nullptr
+                                       || ncc < this->_goal.cc()) {
+                               this->_goal.p(this->_nodes.back(), true);
+                               this->_goal.c(nc);
                                gf = true;
                        }
                }
@@ -477,7 +588,8 @@ RRTS::next()
        if (gf) {
                this->compute_path();
        }
-       this->time_ = this->ter_.scnt();
+       this->_time = this->scnt();
+       this->icnt(this->icnt() + 1);
        return this->should_continue();
 }
 
@@ -486,17 +598,31 @@ RRTS::reset()
 {
        if (this->path_cost() != 0.0
                        && this->path_cost() < this->last_path_cost()) {
-               this->last_path_cost(this->path_cost);
-               this->_last_path.clear();
+               this->_logged_paths.push_back(std::vector<RRTNode>());
+               auto& last_path = this->_logged_paths.back();
+               last_path.reserve(this->_path.size());
+               RRTNode* p = nullptr;
                for (auto n: this->_path) {
-                       this->_last_path.push_back(*n);
+                       last_path.push_back(*n);
+                       if (p != nullptr) {
+                               last_path.back().p(*p);
+                       }
+                       p = &last_path.back();
+               }
+               // Test that last path cost matches.
+               auto last_path_cost = last_path.back().cc();
+               for (unsigned int i = 1; i < last_path.size(); i++) {
+                       last_path[i].c(this->cost_build(
+                               last_path[i - 1],
+                               last_path[i]));
                }
+               assert(last_path_cost == last_path.back().cc());
        }
-       this->goal(
-               this->goal().x(),
-               this->goal().y(),
-               this->goal().b(),
-               this->goal().e());
+       this->_goal = RRTGoal(
+               this->_goal.x(),
+               this->_goal.y(),
+               this->_goal.b(),
+               this->_goal.e());
        this->_path.clear();
        this->_steered.clear();
        this->_nodes.erase(this->_nodes.begin() + 1, this->_nodes.end());