Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
node_2d.cpp
1 // Copyright (c) 2020, Samsung Research America
2 // Copyright (c) 2020, Applied Electric Vehicles Pty Ltd
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License. Reserved.
15 
16 #include "nav2_smac_planner/node_2d.hpp"
17 
18 #include <vector>
19 #include <limits>
20 
21 namespace nav2_smac_planner
22 {
23 
24 // defining static member for all instance to share
25 std::vector<int> Node2D::_neighbors_grid_offsets;
26 float Node2D::cost_travel_multiplier = 2.0;
27 
28 Node2D::Node2D(const uint64_t index)
29 : parent(nullptr),
30  _cell_cost(std::numeric_limits<float>::quiet_NaN()),
31  _accumulated_cost(std::numeric_limits<float>::max()),
32  _index(index),
33  _was_visited(false),
34  _is_queued(false),
35  _in_collision(false)
36 {
37 }
38 
40 {
41  parent = nullptr;
42 }
43 
45 {
46  parent = nullptr;
47  _cell_cost = std::numeric_limits<float>::quiet_NaN();
48  _accumulated_cost = std::numeric_limits<float>::max();
49  _was_visited = false;
50  _is_queued = false;
51  _in_collision = false;
52 }
53 
55  const bool & traverse_unknown,
56  GridCollisionChecker * collision_checker)
57 {
58  // Already found, we can return the result
59  if (!std::isnan(_cell_cost)) {
60  return !_in_collision;
61  }
62 
63  _in_collision = collision_checker->inCollision(this->getIndex(), traverse_unknown);
64  _cell_cost = collision_checker->getCost();
65  return !_in_collision;
66 }
67 
68 float Node2D::getTraversalCost(const NodePtr & child)
69 {
70  float normalized_cost = child->getCost() / 252.0;
71  const Coordinates A = getCoords(child->getIndex());
72  const Coordinates B = getCoords(this->getIndex());
73  const float & dx = A.x - B.x;
74  const float & dy = A.y - B.y;
75  static float sqrt_2 = sqrt(2);
76 
77  // If a diagonal move, travel cost is sqrt(2) not 1.0.
78  if ((dx * dx + dy * dy) > 1.05) {
79  return sqrt_2 * (1.0 + cost_travel_multiplier * normalized_cost);
80  }
81 
82  // Length = 1.0
83  return 1.0 + cost_travel_multiplier * normalized_cost;
84 }
85 
87  const Coordinates & node_coords,
88  const CoordinateVector & goals_coords)
89 {
90  // Using Moore distance as it more accurately represents the distances
91  // even a Van Neumann neighborhood robot can navigate.
92  auto dx = goals_coords[0].x - node_coords.x;
93  auto dy = goals_coords[0].y - node_coords.y;
94  return std::sqrt(dx * dx + dy * dy);
95 }
96 
98  const MotionModel & motion_model,
99  unsigned int & x_size_uint,
100  unsigned int & /*size_y*/,
101  unsigned int & /*num_angle_quantization*/,
102  SearchInfo & search_info)
103 {
104  if (motion_model != MotionModel::TWOD) {
105  throw std::runtime_error("Invalid motion model for 2D node.");
106  }
107 
108  int x_size = static_cast<int>(x_size_uint);
109  cost_travel_multiplier = search_info.cost_penalty;
110  _neighbors_grid_offsets = {-1, +1, -x_size, +x_size, -x_size - 1,
111  -x_size + 1, +x_size - 1, +x_size + 1};
112 }
113 
115  std::function<bool(const uint64_t &,
116  nav2_smac_planner::Node2D * &)> & NeighborGetter,
117  GridCollisionChecker * collision_checker,
118  const bool & traverse_unknown,
119  NodeVector & neighbors)
120 {
121  // NOTE(stevemacenski): Irritatingly, the order here matters. If you start in free
122  // space and then expand 8-connected, the first set of neighbors will be all cost
123  // 1.0. Then its expansion will all be 2 * 1.0 but now multiple
124  // nodes are touching that node so the last cell to update the back pointer wins.
125  // Thusly, the ordering ends with the cardinal directions for both sets such that
126  // behavior is consistent in large free spaces between them.
127  // 100 50 0
128  // 100 50 50
129  // 100 100 100 where lower-middle '100' is visited with same cost by both bottom '50' nodes
130  // Therefore, it is valuable to have some low-potential across the entire map
131  // rather than a small inflation around the obstacles
132  uint64_t index;
133  NodePtr neighbor;
134  uint64_t node_i = this->getIndex();
135  const Coordinates coord_parent = getCoords(this->getIndex());
136  Coordinates child;
137 
138  for (unsigned int i = 0; i != _neighbors_grid_offsets.size(); ++i) {
139  index = node_i + _neighbors_grid_offsets[i];
140 
141  // Check for wrap around conditions
142  child = getCoords(index);
143  if (fabs(coord_parent.x - child.x) > 1 || fabs(coord_parent.y - child.y) > 1) {
144  continue;
145  }
146 
147  if (NeighborGetter(index, neighbor)) {
148  if (neighbor->isNodeValid(traverse_unknown, collision_checker) && !neighbor->wasVisited()) {
149  neighbors.push_back(neighbor);
150  }
151  }
152  }
153 }
154 
155 bool Node2D::backtracePath(CoordinateVector & path)
156 {
157  if (!this->parent) {
158  return false;
159  }
160 
161  NodePtr current_node = this;
162 
163  while (current_node->parent) {
164  path.push_back(
165  Node2D::getCoords(current_node->getIndex()));
166  current_node = current_node->parent;
167  }
168 
169  // add the start pose
170  path.push_back(Node2D::getCoords(current_node->getIndex()));
171 
172  return true;
173 }
174 
175 } // namespace nav2_smac_planner
A costmap grid collision checker.
bool inCollision(const float &x, const float &y, const float &theta, const bool &traverse_unknown)
Check if in collision with costmap and footprint at pose.
float getCost()
Get cost at footprint pose in costmap.
Node2D implementation for graph.
Definition: node_2d.hpp:36
bool wasVisited()
Gets if cell has been visited in search.
Definition: node_2d.hpp:141
Node2D(const uint64_t index)
A constructor for nav2_smac_planner::Node2D.
Definition: node_2d.cpp:28
bool isNodeValid(const bool &traverse_unknown, GridCollisionChecker *collision_checker)
Check if this node is valid.
Definition: node_2d.cpp:54
bool backtracePath(CoordinateVector &path)
Set the starting pose for planning, as a node index.
Definition: node_2d.cpp:155
float getTraversalCost(const NodePtr &child)
get traversal cost from this node to child node
Definition: node_2d.cpp:68
static Coordinates getCoords(const uint64_t &index, const unsigned int &width, const unsigned int &angles)
Get index.
Definition: node_2d.hpp:217
uint64_t getIndex()
Gets cell index.
Definition: node_2d.hpp:176
void getNeighbors(std::function< bool(const uint64_t &, nav2_smac_planner::Node2D *&)> &validity_checker, GridCollisionChecker *collision_checker, const bool &traverse_unknown, NodeVector &neighbors)
Retrieve all valid neighbors of a node.
Definition: node_2d.cpp:114
~Node2D()
A destructor for nav2_smac_planner::Node2D.
Definition: node_2d.cpp:39
static float getHeuristicCost(const Coordinates &node_coords, const CoordinateVector &goals_coords)
Get cost of heuristic of node.
Definition: node_2d.cpp:86
void reset()
Reset method for new search.
Definition: node_2d.cpp:44
float getCost()
Gets the costmap cost at this node.
Definition: node_2d.hpp:123
static void initMotionModel(const MotionModel &motion_model, unsigned int &size_x, unsigned int &size_y, unsigned int &num_angle_quantization, SearchInfo &search_info)
Initialize the neighborhood to be used in A* We support 4-connect (VON_NEUMANN) and 8-connect (MOORE)
Definition: node_2d.cpp:97
Node2D implementation of coordinate structure.
Definition: node_2d.hpp:47
Search properties and penalties.
Definition: types.hpp:36