Nav2 Navigation Stack - humble  humble
ROS 2 Navigation Stack
theta_star.cpp
1 // Copyright 2020 Anshumaan Singh
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <vector>
16 #include "nav2_theta_star_planner/theta_star.hpp"
17 
18 namespace theta_star
19 {
20 
21 ThetaStar::ThetaStar()
22 : w_traversal_cost_(1.0),
23  w_euc_cost_(2.0),
24  w_heuristic_cost_(1.0),
25  how_many_corners_(8),
26  allow_unknown_(true),
27  size_x_(0),
28  size_y_(0),
29  index_generated_(0)
30 {
31  exp_node = new tree_node;
32 }
33 
34 void ThetaStar::setStartAndGoal(
35  const geometry_msgs::msg::PoseStamped & start,
36  const geometry_msgs::msg::PoseStamped & goal)
37 {
38  unsigned int s[2], d[2];
39  costmap_->worldToMap(start.pose.position.x, start.pose.position.y, s[0], s[1]);
40  costmap_->worldToMap(goal.pose.position.x, goal.pose.position.y, d[0], d[1]);
41 
42  src_ = {static_cast<int>(s[0]), static_cast<int>(s[1])};
43  dst_ = {static_cast<int>(d[0]), static_cast<int>(d[1])};
44 }
45 
46 bool ThetaStar::generatePath(std::vector<coordsW> & raw_path)
47 {
48  resetContainers();
49  addToNodesData(index_generated_);
50  double src_g_cost = getTraversalCost(src_.x, src_.y), src_h_cost = getHCost(src_.x, src_.y);
51  nodes_data_[index_generated_] =
52  {src_.x, src_.y, src_g_cost, src_h_cost, &nodes_data_[index_generated_], true,
53  src_g_cost + src_h_cost};
54  queue_.push({&nodes_data_[index_generated_]});
55  addIndex(src_.x, src_.y, &nodes_data_[index_generated_]);
56  tree_node * curr_data = &nodes_data_[index_generated_];
57  index_generated_++;
58  nodes_opened = 0;
59 
60  while (!queue_.empty()) {
61  nodes_opened++;
62 
63  if (isGoal(*curr_data)) {
64  break;
65  }
66 
67  resetParent(curr_data);
68  setNeighbors(curr_data);
69 
70  curr_data = queue_.top();
71  queue_.pop();
72  }
73 
74  if (queue_.empty()) {
75  raw_path.clear();
76  return false;
77  }
78 
79  backtrace(raw_path, curr_data);
80  clearQueue();
81 
82  return true;
83 }
84 
85 void ThetaStar::resetParent(tree_node * curr_data)
86 {
87  double g_cost, los_cost = 0;
88  curr_data->is_in_queue = false;
89  const tree_node * curr_par = curr_data->parent_id;
90  const tree_node * maybe_par = curr_par->parent_id;
91 
92  if (losCheck(curr_data->x, curr_data->y, maybe_par->x, maybe_par->y, los_cost)) {
93  g_cost = maybe_par->g +
94  getEuclideanCost(curr_data->x, curr_data->y, maybe_par->x, maybe_par->y) + los_cost;
95 
96  if (g_cost < curr_data->g) {
97  curr_data->parent_id = maybe_par;
98  curr_data->g = g_cost;
99  curr_data->f = g_cost + curr_data->h;
100  }
101  }
102 }
103 
104 void ThetaStar::setNeighbors(const tree_node * curr_data)
105 {
106  int mx, my;
107  tree_node * m_id = nullptr;
108  double g_cost, h_cost, cal_cost;
109 
110  for (int i = 0; i < how_many_corners_; i++) {
111  mx = curr_data->x + moves[i].x;
112  my = curr_data->y + moves[i].y;
113 
114  if (withinLimits(mx, my)) {
115  if (!isSafe(mx, my)) {
116  continue;
117  }
118  } else {
119  continue;
120  }
121 
122  g_cost = curr_data->g + getEuclideanCost(curr_data->x, curr_data->y, mx, my) +
123  getTraversalCost(mx, my);
124 
125  m_id = getIndex(mx, my);
126 
127  if (m_id == nullptr) {
128  addToNodesData(index_generated_);
129  m_id = &nodes_data_[index_generated_];
130  addIndex(mx, my, m_id);
131  index_generated_++;
132  }
133 
134  exp_node = m_id;
135 
136  h_cost = getHCost(mx, my);
137  cal_cost = g_cost + h_cost;
138  if (exp_node->f > cal_cost) {
139  exp_node->g = g_cost;
140  exp_node->h = h_cost;
141  exp_node->f = cal_cost;
142  exp_node->parent_id = curr_data;
143  if (!exp_node->is_in_queue) {
144  exp_node->x = mx;
145  exp_node->y = my;
146  exp_node->is_in_queue = true;
147  queue_.push({m_id});
148  }
149  }
150  }
151 }
152 
153 void ThetaStar::backtrace(std::vector<coordsW> & raw_points, const tree_node * curr_n) const
154 {
155  std::vector<coordsW> path_rev;
156  coordsW world{};
157  do {
158  costmap_->mapToWorld(curr_n->x, curr_n->y, world.x, world.y);
159  path_rev.push_back(world);
160  if (path_rev.size() > 1) {
161  curr_n = curr_n->parent_id;
162  }
163  } while (curr_n->parent_id != curr_n);
164  costmap_->mapToWorld(curr_n->x, curr_n->y, world.x, world.y);
165  path_rev.push_back(world);
166 
167  raw_points.reserve(path_rev.size());
168  for (int i = static_cast<int>(path_rev.size()) - 1; i >= 0; i--) {
169  raw_points.push_back(path_rev[i]);
170  }
171 }
172 
173 bool ThetaStar::losCheck(
174  const int & x0, const int & y0, const int & x1, const int & y1,
175  double & sl_cost) const
176 {
177  sl_cost = 0;
178 
179  int cx, cy;
180  int dy = abs(y1 - y0), dx = abs(x1 - x0), f = 0;
181  int sx, sy;
182  sx = x1 > x0 ? 1 : -1;
183  sy = y1 > y0 ? 1 : -1;
184 
185  int u_x = (sx - 1) / 2;
186  int u_y = (sy - 1) / 2;
187  cx = x0;
188  cy = y0;
189 
190  if (dx >= dy) {
191  while (cx != x1) {
192  f += dy;
193  if (f >= dx) {
194  if (!isSafe(cx + u_x, cy + u_y, sl_cost)) {
195  return false;
196  }
197  cy += sy;
198  f -= dx;
199  }
200  if (f != 0 && !isSafe(cx + u_x, cy + u_y, sl_cost)) {
201  return false;
202  }
203  if (dy == 0 && !isSafe(cx + u_x, cy, sl_cost) && !isSafe(cx + u_x, cy - 1, sl_cost)) {
204  return false;
205  }
206  cx += sx;
207  }
208  } else {
209  while (cy != y1) {
210  f = f + dx;
211  if (f >= dy) {
212  if (!isSafe(cx + u_x, cy + u_y, sl_cost)) {
213  return false;
214  }
215  cx += sx;
216  f -= dy;
217  }
218  if (f != 0 && !isSafe(cx + u_x, cy + u_y, sl_cost)) {
219  return false;
220  }
221  if (dx == 0 && !isSafe(cx, cy + u_y, sl_cost) && !isSafe(cx - 1, cy + u_y, sl_cost)) {
222  return false;
223  }
224  cy += sy;
225  }
226  }
227  return true;
228 }
229 
230 void ThetaStar::resetContainers()
231 {
232  index_generated_ = 0;
233  int last_size_x = size_x_;
234  int last_size_y = size_y_;
235  int curr_size_x = static_cast<int>(costmap_->getSizeInCellsX());
236  int curr_size_y = static_cast<int>(costmap_->getSizeInCellsY());
237  if (((last_size_x != curr_size_x) || (last_size_y != curr_size_y)) &&
238  static_cast<int>(node_position_.size()) < (curr_size_x * curr_size_y))
239  {
240  initializePosn(curr_size_y * curr_size_x - last_size_y * last_size_x);
241  nodes_data_.reserve(curr_size_x * curr_size_y);
242  } else {
243  initializePosn();
244  }
245  size_x_ = curr_size_x;
246  size_y_ = curr_size_y;
247 }
248 
249 void ThetaStar::initializePosn(int size_inc)
250 {
251  if (!node_position_.empty()) {
252  for (int i = 0; i < size_x_ * size_y_; i++) {
253  node_position_[i] = nullptr;
254  }
255  }
256 
257  for (int i = 0; i < size_inc; i++) {
258  node_position_.push_back(nullptr);
259  }
260 }
261 } // namespace theta_star