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