Program Listing for File d_star_lite.cpp¶
↰ Return to documentation for file (src/d_star_lite.cpp
)
#include "path_planning/d_star_lite.hpp"
#include <algorithm>
#include <chrono>
#include <cmath>
#include <thread>
#ifdef BUILD_INDIVIDUAL
#include <random>
#endif // BUILD_INDIVIDUAL
constexpr int pause_time = 500; // milliseconds
bool DStarLite::IsObstacle(const Node& n) const {
return grid_[n.x_][n.y_] == 1;
}
double DStarLite::H(const Node& n1, const Node& n2) {
return std::sqrt(std::pow(n1.x_ - n2.x_, 2) + std::pow(n1.y_ - n2.y_, 2));
}
std::vector<Node> DStarLite::GetNeighbours(const Node& u) const {
std::vector<Node> neighbours;
for (const auto& m : motions_) {
if (const auto neighbour = u + m;
!checkOutsideBoundary(neighbour, grid_.size())) {
neighbours.push_back(neighbour);
}
}
return neighbours;
}
std::vector<Node> DStarLite::GetPred(const Node& u) const {
return GetNeighbours(u);
}
std::vector<Node> DStarLite::GetSucc(const Node& u) const {
return GetNeighbours(u);
}
double DStarLite::C(const Node& s1, const Node& s2) const {
if (IsObstacle(s1) || IsObstacle(s2)) {
return std::numeric_limits<double>::max();
}
const Node delta{s2.x_ - s1.x_, s2.y_ - s1.y_};
return std::find_if(std::begin(motions_), std::end(motions_),
[&delta](const Node& motion) {
return CompareCoordinates(motion, delta);
})
->cost_;
}
Key DStarLite::CalculateKey(const Node& s) const {
return Key{std::min(g_[s.x_][s.y_], rhs_[s.x_][s.y_]) + H(start_, s) + k_m_,
std::min(g_[s.x_][s.y_], rhs_[s.x_][s.y_])};
}
std::vector<std::vector<double>> DStarLite::CreateGrid() {
return std::vector<std::vector<double>>(
n_, std::vector<double>(n_, std::numeric_limits<double>::max()));
}
void DStarLite::Initialize() {
motions_ = GetMotion();
time_step_ = 0;
U_.clear();
k_m_ = 0;
rhs_ = CreateGrid();
g_ = CreateGrid();
rhs_[goal_.x_][goal_.y_] = 0;
U_.insert(NodeKeyPair{goal_, CalculateKey(goal_)});
}
void DStarLite::UpdateVertex(const Node& u) {
if (grid_[u.x_][u.y_] == 0) {
grid_[u.x_][u.y_] = 2;
}
if (!CompareCoordinates(u, goal_)) {
rhs_[u.x_][u.y_] = std::numeric_limits<double>::max();
const auto successors = GetSucc(u);
for (const auto& sprime : successors) {
rhs_[u.x_][u.y_] =
std::min(rhs_[u.x_][u.y_], C(u, sprime) + g_[sprime.x_][sprime.y_]);
}
}
if (U_.isElementInStruct({u, {}})) {
U_.remove(NodeKeyPair{u, Key()});
}
if (rhs_[u.x_][u.y_] != g_[u.x_][u.y_]) {
U_.insert(NodeKeyPair{u, CalculateKey(u)});
}
}
void DStarLite::ComputeShortestPath() {
while ((!U_.empty() && U_.top().key < CalculateKey(start_)) ||
(rhs_[start_.x_][start_.y_] != g_[start_.x_][start_.y_])) {
k_old_ = U_.top().key;
const Node u = U_.top().node;
U_.pop();
if (const Key u_key = CalculateKey(u); k_old_ < u_key) {
U_.insert(NodeKeyPair{u, u_key});
} else if (g_[u.x_][u.y_] > rhs_[u.x_][u.y_]) {
g_[u.x_][u.y_] = rhs_[u.x_][u.y_];
for (const auto& s : GetPred(u)) {
UpdateVertex(s);
}
} else {
g_[u.x_][u.y_] = std::numeric_limits<double>::max();
for (const auto& s : GetPred(u)) {
UpdateVertex(s);
}
UpdateVertex(u);
}
}
}
std::vector<Node> DStarLite::DetectChanges() {
std::vector<Node> obstacles;
if (time_discovered_obstacles_.find(time_step_) !=
time_discovered_obstacles_.end()) {
const auto discovered_obstacles_at_time =
time_discovered_obstacles_[time_step_];
for (const auto& discovered_obstacle_at_time :
discovered_obstacles_at_time) {
if (!((start_.x_ == discovered_obstacle_at_time.x_ &&
start_.y_ == discovered_obstacle_at_time.y_) ||
(goal_.x_ == discovered_obstacle_at_time.x_ &&
goal_.y_ == discovered_obstacle_at_time.y_))) {
grid_[discovered_obstacle_at_time.x_][discovered_obstacle_at_time.y_] =
1;
obstacles.push_back(discovered_obstacle_at_time);
}
}
}
if (create_random_obstacles_ && rand() > 1.0 / static_cast<double>(n_)) {
const int x = rand() % n_;
const int y = rand() % n_;
if (!((start_.x_ == x && start_.y_ == y) ||
(goal_.x_ == x && goal_.y_ == y))) {
grid_[x][y] = 1;
obstacles.emplace_back(Node(x, y));
}
}
return obstacles;
}
void DStarLite::SetDynamicObstacles(
const bool create_random_obstacles,
const std::unordered_map<int, std::vector<Node>>&
time_discovered_obstacles) {
create_random_obstacles_ = create_random_obstacles;
time_discovered_obstacles_ = time_discovered_obstacles;
}
std::tuple<bool, std::vector<Node>> DStarLite::Plan(const Node& start,
const Node& goal) {
grid_ = original_grid_;
start_ = start;
goal_ = goal;
std::vector<Node> path;
path.push_back(start_);
grid_[start_.x_][start_.y_] = 4;
PrintGrid(grid_);
auto last = start_;
Initialize();
ComputeShortestPath();
while (!CompareCoordinates(start_, goal_)) {
time_step_++;
if (g_[start_.x_][start_.y_] == std::numeric_limits<double>::max()) {
path.clear();
path.push_back(start);
path.back().cost_ = -1;
std::cout << "The path has been blocked" << '\n';
return {false, path};
}
const auto successors = GetSucc(start_);
// double calculation, to optimize
grid_[start_.x_][start_.y_] = 3;
start_ = *std::min_element(std::begin(successors), std::end(successors),
[this](const auto& n1, const auto& n2) {
return C(start_, n1) + g_[n1.x_][n1.y_] <
C(start_, n2) + g_[n2.x_][n2.y_];
});
path.push_back(start_);
grid_[start_.x_][start_.y_] = 4;
#ifndef RUN_TESTS
std::this_thread::sleep_for(std::chrono::milliseconds(pause_time));
#endif // RUN_TESTS
if (const auto changed_nodes = DetectChanges(); !changed_nodes.empty()) {
k_m_ += H(last, start_);
last = start;
for (const auto node : changed_nodes) {
UpdateVertex(node);
}
ComputeShortestPath();
}
start_.PrintStatus();
PrintGrid(grid_);
}
path[0].id_ = path[0].x_ * n_ + path[0].y_;
path[0].pid_ = path[0].id_;
path[0].cost_ = 0;
for (int i = 1; i < path.size(); i++) {
path[i].id_ = path[i].x_ * n_ + path[i].y_;
const auto delta =
Node(path[i].x_ - path[i - 1].x_, path[i].y_ - path[i - 1].y_);
path[i].cost_ = path[i - 1].cost_ +
std::find_if(std::begin(motions_), std::end(motions_),
[&delta](const Node& motion) {
return CompareCoordinates(motion, delta);
})
->cost_;
path[i].pid_ = path[i - 1].id_;
}
return {true, path};
}
#ifdef BUILD_INDIVIDUAL
int main() {
constexpr int n = 11;
std::vector<std::vector<int>> grid(n, std::vector<int>(n, 0));
MakeGrid(grid);
std::random_device rd; // obtain a random number from hardware
std::mt19937 eng(rd()); // seed the generator
std::uniform_int_distribution<int> distr(0, n - 1); // define the range
Node start(distr(eng), distr(eng), 0, 0, 0, 0);
Node goal(distr(eng), distr(eng), 0, 0, 0, 0);
start.id_ = start.x_ * n + start.y_;
start.pid_ = start.x_ * n + start.y_;
goal.id_ = goal.x_ * n + goal.y_;
start.h_cost_ = abs(start.x_ - goal.x_) + abs(start.y_ - goal.y_);
// Make sure start and goal are not obstacles and their ids are correctly
// assigned.
grid[start.x_][start.y_] = 0;
grid[goal.x_][goal.y_] = 0;
start.PrintStatus();
goal.PrintStatus();
const bool create_random_obstacles = false;
const std::unordered_map<int, std::vector<Node>> time_discovered_obstacles{
{1, {Node(1, 1)}},
{2, {Node(2, 2)}},
{3, {Node(5, 5)}},
{4,
{Node(6, 6), Node(7, 7), Node(8, 8), Node(9, 9), Node(10, 10),
Node(7, 6)}}};
DStarLite d_star_lite(grid);
d_star_lite.SetDynamicObstacles(create_random_obstacles,
time_discovered_obstacles);
const auto [found_path, path_vector] = d_star_lite.Plan(start, goal);
PrintPath(path_vector, start, goal, grid);
return 0;
}
#endif // BUILD_INDIVIDUAL