Nav2 Navigation Stack - lyrical  lyrical
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 <functional>
16 #include <vector>
17 
18 #include "geometry_msgs/msg/pose_stamped.hpp"
19 
20 #include "nav2_core/planner_exceptions.hpp"
21 #include "nav2_theta_star_planner/theta_star.hpp"
22 
23 namespace nav2_theta_star_planner
24 {
25 
26 ThetaStar::ThetaStar(Parameters * params)
27 : size_x_(0),
28  size_y_(0),
29  index_generated_(0)
30 {
31  exp_node = new tree_node;
32  params_ = params;
33 }
34 
35 void ThetaStar::setStartAndGoal(
36  const geometry_msgs::msg::PoseStamped & start,
37  const geometry_msgs::msg::PoseStamped & goal)
38 {
39  unsigned int s[2], d[2];
40  costmap_->worldToMap(start.pose.position.x, start.pose.position.y, s[0], s[1]);
41  costmap_->worldToMap(goal.pose.position.x, goal.pose.position.y, d[0], d[1]);
42 
43  src_ = {static_cast<int>(s[0]), static_cast<int>(s[1])};
44  dst_ = {static_cast<int>(d[0]), static_cast<int>(d[1])};
45 }
46 
47 bool ThetaStar::generatePath(std::vector<coordsW> & raw_path, std::function<bool()> cancel_checker)
48 {
49  resetContainers();
50  addToNodesData(index_generated_);
51  double src_g_cost = getTraversalCost(src_.x, src_.y), src_h_cost = getHCost(src_.x, src_.y);
52  nodes_data_[index_generated_] =
53  {src_.x, src_.y, src_g_cost, src_h_cost, &nodes_data_[index_generated_], true,
54  src_g_cost + src_h_cost};
55  queue_.push({&nodes_data_[index_generated_]});
56  addIndex(src_.x, src_.y, &nodes_data_[index_generated_]);
57  tree_node * curr_data = &nodes_data_[index_generated_];
58  index_generated_++;
59  nodes_opened = 0;
60 
61  while (!queue_.empty()) {
62  nodes_opened++;
63 
64  if (nodes_opened % params_->terminal_checking_interval == 0 && cancel_checker()) {
65  clearQueue();
66  throw nav2_core::PlannerCancelled("Planner was canceled");
67  }
68 
69  if (isGoal(*curr_data)) {
70  break;
71  }
72 
73  resetParent(curr_data);
74  setNeighbors(curr_data);
75 
76  curr_data = queue_.top();
77  queue_.pop();
78  }
79 
80  if (queue_.empty()) {
81  raw_path.clear();
82  return false;
83  }
84 
85  backtrace(raw_path, curr_data);
86  clearQueue();
87 
88  return true;
89 }
90 
91 void ThetaStar::resetParent(tree_node * curr_data)
92 {
93  double g_cost, los_cost = 0;
94  curr_data->is_in_queue = false;
95  const tree_node * curr_par = curr_data->parent_id;
96  const tree_node * maybe_par = curr_par->parent_id;
97 
98  if (losCheck(curr_data->x, curr_data->y, maybe_par->x, maybe_par->y, los_cost)) {
99  g_cost = maybe_par->g +
100  getEuclideanCost(curr_data->x, curr_data->y, maybe_par->x, maybe_par->y) + los_cost;
101 
102  if (g_cost < curr_data->g) {
103  curr_data->parent_id = maybe_par;
104  curr_data->g = g_cost;
105  curr_data->f = g_cost + curr_data->h;
106  }
107  }
108 }
109 
110 void ThetaStar::setNeighbors(const tree_node * curr_data)
111 {
112  int mx, my;
113  tree_node * m_id = nullptr;
114  double g_cost, h_cost, cal_cost;
115 
116  for (int i = 0; i < params_->how_many_corners; i++) {
117  mx = curr_data->x + moves[i].x;
118  my = curr_data->y + moves[i].y;
119 
120  if (withinLimits(mx, my)) {
121  if (!isSafe(mx, my)) {
122  continue;
123  }
124  } else {
125  continue;
126  }
127 
128  g_cost = curr_data->g + getEuclideanCost(curr_data->x, curr_data->y, mx, my) +
129  getTraversalCost(mx, my);
130 
131  m_id = getIndex(mx, my);
132 
133  if (m_id == nullptr) {
134  addToNodesData(index_generated_);
135  m_id = &nodes_data_[index_generated_];
136  addIndex(mx, my, m_id);
137  index_generated_++;
138  }
139 
140  exp_node = m_id;
141 
142  h_cost = getHCost(mx, my);
143  cal_cost = g_cost + h_cost;
144  if (exp_node->f > cal_cost) {
145  exp_node->g = g_cost;
146  exp_node->h = h_cost;
147  exp_node->f = cal_cost;
148  exp_node->parent_id = curr_data;
149  if (!exp_node->is_in_queue) {
150  exp_node->x = mx;
151  exp_node->y = my;
152  exp_node->is_in_queue = true;
153  queue_.push({m_id});
154  }
155  }
156  }
157 }
158 
159 void ThetaStar::backtrace(std::vector<coordsW> & raw_points, const tree_node * curr_n) const
160 {
161  std::vector<coordsW> path_rev;
162  coordsW world{};
163  do {
164  costmap_->mapToWorld(curr_n->x, curr_n->y, world.x, world.y);
165  path_rev.push_back(world);
166  if (path_rev.size() > 1) {
167  curr_n = curr_n->parent_id;
168  }
169  } while (curr_n->parent_id != curr_n);
170  costmap_->mapToWorld(curr_n->x, curr_n->y, world.x, world.y);
171  path_rev.push_back(world);
172 
173  raw_points.reserve(path_rev.size());
174  for (int i = static_cast<int>(path_rev.size()) - 1; i >= 0; i--) {
175  raw_points.push_back(path_rev[i]);
176  }
177 }
178 
179 bool ThetaStar::losCheck(
180  const int & x0, const int & y0, const int & x1, const int & y1,
181  double & sl_cost) const
182 {
183  sl_cost = 0;
184 
185  int dx = abs(x1 - x0), sx = (x0 < x1) ? 1 : -1;
186  int dy = abs(y1 - y0), sy = (y0 < y1) ? 1 : -1;
187  int cx = x0, cy = y0, e = dx - dy;
188 
189  while (cx != x1 || cy != y1) {
190  if (!isSafe(cx, cy, sl_cost)) {
191  return false;
192  }
193  int e2 = 2 * e;
194  if (e2 > -dy && e2 <= dx) {
195  if (!isSafe(cx + sx, cy) || !isSafe(cx, cy + sy)) {
196  return false;
197  }
198  cx += sx;
199  cy += sy;
200  e += dx - dy;
201  } else if (e2 > -dy) {
202  cx += sx;
203  e -= dy;
204  } else {
205  cy += sy;
206  e += dx;
207  }
208  }
209 
210  return true;
211 }
212 
213 void ThetaStar::resetContainers()
214 {
215  index_generated_ = 0;
216  int last_size_x = size_x_;
217  int last_size_y = size_y_;
218  int curr_size_x = static_cast<int>(costmap_->getSizeInCellsX());
219  int curr_size_y = static_cast<int>(costmap_->getSizeInCellsY());
220  if (((last_size_x != curr_size_x) || (last_size_y != curr_size_y)) &&
221  static_cast<int>(node_position_.size()) < (curr_size_x * curr_size_y))
222  {
223  initializePosn(curr_size_y * curr_size_x - last_size_y * last_size_x);
224  nodes_data_.reserve(curr_size_x * curr_size_y);
225  } else {
226  initializePosn();
227  }
228  size_x_ = curr_size_x;
229  size_y_ = curr_size_y;
230 }
231 
232 void ThetaStar::initializePosn(int size_inc)
233 {
234  if (!node_position_.empty()) {
235  for (int i = 0; i < size_x_ * size_y_; i++) {
236  node_position_[i] = nullptr;
237  }
238  }
239 
240  for (int i = 0; i < size_inc; i++) {
241  node_position_.push_back(nullptr);
242  }
243 }
244 
245 void ThetaStar::clearStart()
246 {
247  unsigned int mx_start = static_cast<unsigned int>(src_.x);
248  unsigned int my_start = static_cast<unsigned int>(src_.y);
249  costmap_->setCost(mx_start, my_start, nav2_costmap_2d::FREE_SPACE);
250 }
251 
252 } // namespace nav2_theta_star_planner