Skip to content

Commit 9a5689e

Browse files
Remove redundant collision checks in the Smac Planners to optimize performance (#4857) (#4858)
* initial prototype to resolve smac planner issue Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * fix test Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * initial prototype for coarse to fine checking for smac: incomplete Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * completed initial prototype; for testing and benchmarking now Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * fix typo Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * adding bounds checking for coarse Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * fix test Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * remove coarse to fine checks Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> --------- Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> (cherry picked from commit 5ff8cc7) Co-authored-by: Steve Macenski <stevenmacenski@gmail.com>
1 parent 65eab41 commit 9a5689e

File tree

10 files changed

+51
-18
lines changed

10 files changed

+51
-18
lines changed

nav2_smac_planner/include/nav2_smac_planner/a_star.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ class AStarAlgorithm
242242
*/
243243
inline void clearGraph();
244244

245+
inline bool onVisitationCheckNode(const NodePtr & node);
246+
245247
/**
246248
* @brief Populate a debug log of expansions for Hybrid-A* for visualization
247249
* @param node Node expanded

nav2_smac_planner/include/nav2_smac_planner/collision_checker.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ class GridCollisionChecker
113113
*/
114114
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> getCostmapROS() {return costmap_ros_;}
115115

116-
private:
117116
/**
118117
* @brief Check if value outside the range
119118
* @param min Minimum value of the range
@@ -128,7 +127,7 @@ class GridCollisionChecker
128127
std::vector<nav2_costmap_2d::Footprint> oriented_footprints_;
129128
nav2_costmap_2d::Footprint unoriented_footprint_;
130129
float center_cost_;
131-
bool footprint_is_radius_;
130+
bool footprint_is_radius_{false};
132131
std::vector<float> angles_;
133132
float possible_collision_cost_{-1};
134133
rclcpp::Logger logger_{rclcpp::get_logger("SmacPlannerCollisionChecker")};

nav2_smac_planner/include/nav2_smac_planner/node_2d.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ class Node2D
277277
uint64_t _index;
278278
bool _was_visited;
279279
bool _is_queued;
280+
bool _in_collision{false};
280281
};
281282

282283
} // namespace nav2_smac_planner

nav2_smac_planner/include/nav2_smac_planner/node_hybrid.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,12 @@ class NodeHybrid
306306
/**
307307
* @brief Check if this node is valid
308308
* @param traverse_unknown If we can explore unknown nodes on the graph
309+
* @param collision_checker: Collision checker object
309310
* @return whether this node is valid and collision free
310311
*/
311-
bool isNodeValid(const bool & traverse_unknown, GridCollisionChecker * collision_checker);
312+
bool isNodeValid(
313+
const bool & traverse_unknown,
314+
GridCollisionChecker * collision_checker);
312315

313316
/**
314317
* @brief Get traversal cost of parent node to child node
@@ -493,6 +496,7 @@ class NodeHybrid
493496
bool _was_visited;
494497
unsigned int _motion_primitive_index;
495498
TurnDirection _turn_dir;
499+
bool _is_node_valid{false};
496500
};
497501

498502
} // namespace nav2_smac_planner

nav2_smac_planner/include/nav2_smac_planner/node_lattice.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ class NodeLattice
436436
bool _was_visited;
437437
MotionPrimitive * _motion_primitive;
438438
bool _backwards;
439+
bool _is_node_valid{false};
439440
};
440441

441442
} // namespace nav2_smac_planner

nav2_smac_planner/src/a_star.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ bool AStarAlgorithm<NodeT>::createPath(
326326

327327
// We allow for nodes to be queued multiple times in case
328328
// shorter paths result in it, but we can visit only once
329-
if (current_node->wasVisited()) {
329+
// Also a chance to perform last-checks necessary.
330+
if (onVisitationCheckNode(current_node)) {
330331
continue;
331332
}
332333

@@ -435,6 +436,12 @@ float AStarAlgorithm<NodeT>::getHeuristicCost(const NodePtr & node)
435436
return heuristic;
436437
}
437438

439+
template<typename NodeT>
440+
bool AStarAlgorithm<NodeT>::onVisitationCheckNode(const NodePtr & current_node)
441+
{
442+
return current_node->wasVisited();
443+
}
444+
438445
template<typename NodeT>
439446
void AStarAlgorithm<NodeT>::clearQueue()
440447
{

nav2_smac_planner/src/node_2d.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ Node2D::Node2D(const uint64_t index)
3131
_accumulated_cost(std::numeric_limits<float>::max()),
3232
_index(index),
3333
_was_visited(false),
34-
_is_queued(false)
34+
_is_queued(false),
35+
_in_collision(false)
3536
{
3637
}
3738

@@ -47,18 +48,21 @@ void Node2D::reset()
4748
_accumulated_cost = std::numeric_limits<float>::max();
4849
_was_visited = false;
4950
_is_queued = false;
51+
_in_collision = false;
5052
}
5153

5254
bool Node2D::isNodeValid(
5355
const bool & traverse_unknown,
5456
GridCollisionChecker * collision_checker)
5557
{
56-
if (collision_checker->inCollision(this->getIndex(), traverse_unknown)) {
57-
return false;
58+
// Already found, we can return the result
59+
if (!std::isnan(_cell_cost)) {
60+
return !_in_collision;
5861
}
5962

63+
_in_collision = collision_checker->inCollision(this->getIndex(), traverse_unknown);
6064
_cell_cost = collision_checker->getCost();
61-
return true;
65+
return !_in_collision;
6266
}
6367

6468
float Node2D::getTraversalCost(const NodePtr & child)

nav2_smac_planner/src/node_hybrid.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ NodeHybrid::NodeHybrid(const uint64_t index)
350350
_accumulated_cost(std::numeric_limits<float>::max()),
351351
_index(index),
352352
_was_visited(false),
353-
_motion_primitive_index(std::numeric_limits<unsigned int>::max())
353+
_motion_primitive_index(std::numeric_limits<unsigned int>::max()),
354+
_is_node_valid(false)
354355
{
355356
}
356357

@@ -369,20 +370,22 @@ void NodeHybrid::reset()
369370
pose.x = 0.0f;
370371
pose.y = 0.0f;
371372
pose.theta = 0.0f;
373+
_is_node_valid = false;
372374
}
373375

374376
bool NodeHybrid::isNodeValid(
375377
const bool & traverse_unknown,
376378
GridCollisionChecker * collision_checker)
377379
{
378-
if (collision_checker->inCollision(
379-
this->pose.x, this->pose.y, this->pose.theta /*bin number*/, traverse_unknown))
380-
{
381-
return false;
380+
// Already found, we can return the result
381+
if (!std::isnan(_cell_cost)) {
382+
return _is_node_valid;
382383
}
383384

385+
_is_node_valid = !collision_checker->inCollision(
386+
this->pose.x, this->pose.y, this->pose.theta /*bin number*/, traverse_unknown);
384387
_cell_cost = collision_checker->getCost();
385-
return true;
388+
return _is_node_valid;
386389
}
387390

388391
float NodeHybrid::getTraversalCost(const NodePtr & child)

nav2_smac_planner/src/node_lattice.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ NodeLattice::NodeLattice(const uint64_t index)
193193
_index(index),
194194
_was_visited(false),
195195
_motion_primitive(nullptr),
196-
_backwards(false)
196+
_backwards(false),
197+
_is_node_valid(false)
197198
{
198199
}
199200

@@ -213,6 +214,7 @@ void NodeLattice::reset()
213214
pose.theta = 0.0f;
214215
_motion_primitive = nullptr;
215216
_backwards = false;
217+
_is_node_valid = false;
216218
}
217219

218220
bool NodeLattice::isNodeValid(
@@ -221,13 +223,20 @@ bool NodeLattice::isNodeValid(
221223
MotionPrimitive * motion_primitive,
222224
bool is_backwards)
223225
{
226+
// Already found, we can return the result
227+
if (!std::isnan(_cell_cost)) {
228+
return _is_node_valid;
229+
}
230+
224231
// Check primitive end pose
225232
// Convert grid quantization of primitives to radians, then collision checker quantization
226233
static const double bin_size = 2.0 * M_PI / collision_checker->getPrecomputedAngles().size();
227234
const double & angle = motion_table.getAngleFromBin(this->pose.theta) / bin_size;
228235
if (collision_checker->inCollision(
229236
this->pose.x, this->pose.y, angle /*bin in collision checker*/, traverse_unknown))
230237
{
238+
_is_node_valid = false;
239+
_cell_cost = collision_checker->getCost();
231240
return false;
232241
}
233242

@@ -269,6 +278,8 @@ bool NodeLattice::isNodeValid(
269278
prim_pose._theta / bin_size /*bin in collision checker*/,
270279
traverse_unknown))
271280
{
281+
_is_node_valid = false;
282+
_cell_cost = std::max(max_cell_cost, collision_checker->getCost());
272283
return false;
273284
}
274285
max_cell_cost = std::max(max_cell_cost, collision_checker->getCost());
@@ -277,7 +288,8 @@ bool NodeLattice::isNodeValid(
277288
}
278289

279290
_cell_cost = max_cell_cost;
280-
return true;
291+
_is_node_valid = true;
292+
return _is_node_valid;
281293
}
282294

283295
float NodeLattice::getTraversalCost(const NodePtr & child)

nav2_smac_planner/test/test_a_star.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ TEST(AStarTest, test_a_star_se2)
201201
EXPECT_TRUE(a_star.createPath(path, num_it, tolerance, dummy_cancel_checker, expansions.get()));
202202

203203
// check path is the right size and collision free
204-
EXPECT_EQ(num_it, 3146);
205-
EXPECT_EQ(path.size(), 63u);
204+
EXPECT_GT(num_it, 2000);
205+
EXPECT_NEAR(path.size(), 63u, 2u);
206206
for (unsigned int i = 0; i != path.size(); i++) {
207207
EXPECT_EQ(costmapA->getCost(path[i].x, path[i].y), 0);
208208
}

0 commit comments

Comments
 (0)