Skip to content

Commit 6bda3f3

Browse files
[Smac Planner] Massive Improvement of Behavior for SE2 Footprint Checking (ie non-circular robots) In Confined Settings (#4067)
* prototype to test SE2 footprint H improvements * some fixes * fixed * invert logic * Working final prototype to be tested * complete unit test conversions * Update inflation_layer.hpp Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> --------- Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
1 parent 1348e52 commit 6bda3f3

20 files changed

+254
-59
lines changed

nav2_costmap_2d/include/nav2_costmap_2d/inflation_layer.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@
4141
#include <map>
4242
#include <vector>
4343
#include <mutex>
44+
#include <memory>
45+
#include <string>
4446

4547
#include "rclcpp/rclcpp.hpp"
4648
#include "nav2_costmap_2d/layer.hpp"
4749
#include "nav2_costmap_2d/layered_costmap.hpp"
50+
#include "nav2_costmap_2d/costmap_2d_ros.hpp"
4851

4952
namespace nav2_costmap_2d
5053
{
@@ -161,6 +164,25 @@ class InflationLayer : public Layer
161164
return cost;
162165
}
163166

167+
static std::shared_ptr<nav2_costmap_2d::InflationLayer> getInflationLayer(
168+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> & costmap_ros,
169+
const std::string layer_name = "")
170+
{
171+
const auto layered_costmap = costmap_ros->getLayeredCostmap();
172+
for (auto layer = layered_costmap->getPlugins()->begin();
173+
layer != layered_costmap->getPlugins()->end();
174+
++layer)
175+
{
176+
auto inflation_layer = std::dynamic_pointer_cast<nav2_costmap_2d::InflationLayer>(*layer);
177+
if (inflation_layer) {
178+
if (layer_name.empty() || inflation_layer->getName() == layer_name) {
179+
return inflation_layer;
180+
}
181+
}
182+
}
183+
return nullptr;
184+
}
185+
164186
// Provide a typedef to ease future code maintenance
165187
typedef std::recursive_mutex mutex_t;
166188

nav2_smac_planner/include/nav2_smac_planner/collision_checker.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License. Reserved.
14+
1415
#include <vector>
16+
#include <memory>
17+
1518
#include "nav2_costmap_2d/footprint_collision_checker.hpp"
19+
#include "nav2_costmap_2d/costmap_2d_ros.hpp"
1620
#include "nav2_smac_planner/constants.hpp"
1721
#include "rclcpp_lifecycle/lifecycle_node.hpp"
1822

@@ -39,7 +43,7 @@ class GridCollisionChecker
3943
* orientations for to speed up collision checking
4044
*/
4145
GridCollisionChecker(
42-
nav2_costmap_2d::Costmap2D * costmap,
46+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap,
4347
unsigned int num_quantizations,
4448
rclcpp_lifecycle::LifecycleNode::SharedPtr node);
4549

@@ -103,6 +107,12 @@ class GridCollisionChecker
103107
return angles_;
104108
}
105109

110+
/**
111+
* @brief Get costmap ros object for inflation layer params
112+
* @return Costmap ros
113+
*/
114+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> getCostmapROS() {return costmap_ros_;}
115+
106116
private:
107117
/**
108118
* @brief Check if value outside the range
@@ -114,6 +124,7 @@ class GridCollisionChecker
114124
bool outsideRange(const unsigned int & max, const float & value);
115125

116126
protected:
127+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros_;
117128
std::vector<nav2_costmap_2d::Footprint> oriented_footprints_;
118129
nav2_costmap_2d::Footprint unoriented_footprint_;
119130
float footprint_cost_;

nav2_smac_planner/include/nav2_smac_planner/node_2d.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,11 @@ class Node2D
223223
* @brief Get cost of heuristic of node
224224
* @param node Node index current
225225
* @param node Node index of new
226-
* @param costmap Costmap ptr to use
227226
* @return Heuristic cost between the nodes
228227
*/
229228
static float getHeuristicCost(
230229
const Coordinates & node_coords,
231-
const Coordinates & goal_coordinates,
232-
const nav2_costmap_2d::Costmap2D * costmap);
230+
const Coordinates & goal_coordinates);
233231

234232
/**
235233
* @brief Initialize the neighborhood to be used in A*

nav2_smac_planner/include/nav2_smac_planner/node_hybrid.hpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "nav2_smac_planner/types.hpp"
3232
#include "nav2_smac_planner/collision_checker.hpp"
3333
#include "nav2_smac_planner/costmap_downsampler.hpp"
34+
#include "nav2_costmap_2d/costmap_2d_ros.hpp"
35+
#include "nav2_costmap_2d/inflation_layer.hpp"
3436

3537
namespace nav2_smac_planner
3638
{
@@ -360,13 +362,11 @@ class NodeHybrid
360362
* @brief Get cost of heuristic of node
361363
* @param node Node index current
362364
* @param node Node index of new
363-
* @param costmap Costmap ptr to use
364365
* @return Heuristic cost between the nodes
365366
*/
366367
static float getHeuristicCost(
367368
const Coordinates & node_coords,
368-
const Coordinates & goal_coordinates,
369-
const nav2_costmap_2d::Costmap2D * costmap);
369+
const Coordinates & goal_coordinates);
370370

371371
/**
372372
* @brief Initialize motion models
@@ -423,14 +423,22 @@ class NodeHybrid
423423

424424
/**
425425
* @brief reset the obstacle heuristic state
426-
* @param costmap Costmap to use
426+
* @param costmap_ros Costmap to use
427427
* @param goal_coords Coordinates to start heuristic expansion at
428428
*/
429429
static void resetObstacleHeuristic(
430-
nav2_costmap_2d::Costmap2D * costmap,
430+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
431431
const unsigned int & start_x, const unsigned int & start_y,
432432
const unsigned int & goal_x, const unsigned int & goal_y);
433433

434+
/**
435+
* @brief Using the inflation layer, find the footprint's adjusted cost
436+
* if the robot is non-circular
437+
* @param cost Cost to adjust
438+
* @return float Cost adjusted
439+
*/
440+
static float adjustedFootprintCost(const float & cost);
441+
434442
/**
435443
* @brief Retrieve all valid neighbors of a node.
436444
* @param validity_checker Functor for state validity checking
@@ -462,6 +470,8 @@ class NodeHybrid
462470
static ObstacleHeuristicQueue obstacle_heuristic_queue;
463471

464472
static nav2_costmap_2d::Costmap2D * sampled_costmap;
473+
static std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros;
474+
static std::shared_ptr<nav2_costmap_2d::InflationLayer> inflation_layer;
465475
static CostmapDownsampler downsampler;
466476
// Dubin / Reeds-Shepp lookup and size for dereferencing
467477
static LookupTable dist_heuristic_lookup_table;

nav2_smac_planner/include/nav2_smac_planner/node_lattice.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,13 +312,11 @@ class NodeLattice
312312
* @brief Get cost of heuristic of node
313313
* @param node Node index current
314314
* @param node Node index of new
315-
* @param costmap Costmap ptr to use
316315
* @return Heuristic cost between the nodes
317316
*/
318317
static float getHeuristicCost(
319318
const Coordinates & node_coords,
320-
const Coordinates & goal_coordinates,
321-
const nav2_costmap_2d::Costmap2D * costmap);
319+
const Coordinates & goal_coordinates);
322320

323321
/**
324322
* @brief Initialize motion models
@@ -355,12 +353,12 @@ class NodeLattice
355353
* @param goal_coords Coordinates to start heuristic expansion at
356354
*/
357355
static void resetObstacleHeuristic(
358-
nav2_costmap_2d::Costmap2D * costmap,
356+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
359357
const unsigned int & start_x, const unsigned int & start_y,
360358
const unsigned int & goal_x, const unsigned int & goal_y)
361359
{
362360
// State Lattice and Hybrid-A* share this heuristics
363-
NodeHybrid::resetObstacleHeuristic(costmap, start_x, start_y, goal_x, goal_y);
361+
NodeHybrid::resetObstacleHeuristic(costmap_ros, start_x, start_y, goal_x, goal_y);
364362
}
365363

366364
/**

nav2_smac_planner/src/a_star.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ void AStarAlgorithm<NodeT>::setGoal(
207207
throw std::runtime_error("Start must be set before goal.");
208208
}
209209

210-
NodeT::resetObstacleHeuristic(_costmap, _start->pose.x, _start->pose.y, mx, my);
210+
NodeT::resetObstacleHeuristic(
211+
_collision_checker->getCostmapROS(), _start->pose.x, _start->pose.y, mx, my);
211212
}
212213

213214
_goal_coordinates = goal_coords;
@@ -403,7 +404,7 @@ float AStarAlgorithm<NodeT>::getHeuristicCost(const NodePtr & node)
403404
const Coordinates node_coords =
404405
NodeT::getCoords(node->getIndex(), getSizeX(), getSizeDim3());
405406
float heuristic = NodeT::getHeuristicCost(
406-
node_coords, _goal_coordinates, _costmap);
407+
node_coords, _goal_coordinates);
407408

408409
if (heuristic < _best_heuristic_node.first) {
409410
_best_heuristic_node = {heuristic, node->getIndex()};

nav2_smac_planner/src/analytic_expansion.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ typename AnalyticExpansion<NodeT>::NodePtr AnalyticExpansion<NodeT>::tryAnalytic
5757
_motion_model == MotionModel::STATE_LATTICE)
5858
{
5959
// See if we are closer and should be expanding more often
60-
auto costmap = _collision_checker->getCostmap();
6160
const Coordinates node_coords =
62-
NodeT::getCoords(current_node->getIndex(), costmap->getSizeInCellsX(), _dim_3_size);
61+
NodeT::getCoords(
62+
current_node->getIndex(), _collision_checker->getCostmap()->getSizeInCellsX(), _dim_3_size);
6363
closest_distance = std::min(
6464
closest_distance,
65-
static_cast<int>(NodeT::getHeuristicCost(node_coords, goal_node->pose, costmap)));
65+
static_cast<int>(NodeT::getHeuristicCost(node_coords, goal_node->pose)));
6666

6767
// We want to expand at a rate of d/expansion_ratio,
6868
// but check to see if we are so close that we would be expanding every iteration

nav2_smac_planner/src/collision_checker.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@ namespace nav2_smac_planner
1818
{
1919

2020
GridCollisionChecker::GridCollisionChecker(
21-
nav2_costmap_2d::Costmap2D * costmap,
21+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
2222
unsigned int num_quantizations,
2323
rclcpp_lifecycle::LifecycleNode::SharedPtr node)
24-
: FootprintCollisionChecker(costmap)
24+
: FootprintCollisionChecker(costmap_ros ? costmap_ros->getCostmap() : nullptr)
2525
{
2626
if (node) {
2727
clock_ = node->get_clock();
2828
logger_ = node->get_logger();
2929
}
3030

31+
if (costmap_ros) {
32+
costmap_ros_ = costmap_ros;
33+
}
34+
3135
// Convert number of regular bins into angles
3236
float bin_size = 2 * M_PI / static_cast<float>(num_quantizations);
3337
angles_.reserve(num_quantizations);

nav2_smac_planner/src/node_2d.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ float Node2D::getTraversalCost(const NodePtr & child)
8181

8282
float Node2D::getHeuristicCost(
8383
const Coordinates & node_coords,
84-
const Coordinates & goal_coordinates,
85-
const nav2_costmap_2d::Costmap2D * /*costmap*/)
84+
const Coordinates & goal_coordinates)
8685
{
8786
// Using Moore distance as it more accurately represents the distances
8887
// even a Van Neumann neighborhood robot can navigate.

nav2_smac_planner/src/node_hybrid.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ HybridMotionTable NodeHybrid::motion_table;
4141
float NodeHybrid::size_lookup = 25;
4242
LookupTable NodeHybrid::dist_heuristic_lookup_table;
4343
nav2_costmap_2d::Costmap2D * NodeHybrid::sampled_costmap = nullptr;
44+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> NodeHybrid::costmap_ros = nullptr;
45+
std::shared_ptr<nav2_costmap_2d::InflationLayer> NodeHybrid::inflation_layer = nullptr;
46+
4447
CostmapDownsampler NodeHybrid::downsampler;
4548
ObstacleHeuristicQueue NodeHybrid::obstacle_heuristic_queue;
4649

@@ -433,8 +436,7 @@ float NodeHybrid::getTraversalCost(const NodePtr & child)
433436

434437
float NodeHybrid::getHeuristicCost(
435438
const Coordinates & node_coords,
436-
const Coordinates & goal_coords,
437-
const nav2_costmap_2d::Costmap2D * /*costmap*/)
439+
const Coordinates & goal_coords)
438440
{
439441
const float obstacle_heuristic =
440442
getObstacleHeuristic(node_coords, goal_coords, motion_table.cost_penalty);
@@ -477,18 +479,20 @@ inline float distanceHeuristic2D(
477479
}
478480

479481
void NodeHybrid::resetObstacleHeuristic(
480-
nav2_costmap_2d::Costmap2D * costmap,
482+
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros_i,
481483
const unsigned int & start_x, const unsigned int & start_y,
482484
const unsigned int & goal_x, const unsigned int & goal_y)
483485
{
484486
// Downsample costmap 2x to compute a sparse obstacle heuristic. This speeds up
485487
// the planner considerably to search through 75% less cells with no detectable
486488
// erosion of path quality after even modest smoothing. The error would be no more
487489
// than 0.05 * normalized cost. Since this is just a search prior, there's no loss in generality
488-
sampled_costmap = costmap;
490+
costmap_ros = costmap_ros_i;
491+
inflation_layer = nav2_costmap_2d::InflationLayer::getInflationLayer(costmap_ros);
492+
sampled_costmap = costmap_ros->getCostmap();
489493
if (motion_table.downsample_obstacle_heuristic) {
490494
std::weak_ptr<nav2_util::LifecycleNode> ptr;
491-
downsampler.on_configure(ptr, "fake_frame", "fake_topic", costmap, 2.0, true);
495+
downsampler.on_configure(ptr, "fake_frame", "fake_topic", sampled_costmap, 2.0, true);
492496
downsampler.on_activate();
493497
sampled_costmap = downsampler.downsample(2.0);
494498
}
@@ -529,13 +533,37 @@ void NodeHybrid::resetObstacleHeuristic(
529533
obstacle_heuristic_lookup_table[goal_index] = -0.00001f;
530534
}
531535

536+
float NodeHybrid::adjustedFootprintCost(const float & cost)
537+
{
538+
if (!inflation_layer) {
539+
return cost;
540+
}
541+
542+
const auto layered_costmap = costmap_ros->getLayeredCostmap();
543+
const float scale_factor = inflation_layer->getCostScalingFactor();
544+
const float min_radius = layered_costmap->getInscribedRadius();
545+
float dist_to_obj = (scale_factor * min_radius - log(cost) + log(253.0f)) / scale_factor;
546+
547+
// Subtract minimum radius for edge cost
548+
dist_to_obj -= min_radius;
549+
if (dist_to_obj < 0.0f) {
550+
dist_to_obj = 0.0f;
551+
}
552+
553+
// Compute cost at this value
554+
return static_cast<float>(
555+
inflation_layer->computeCost(dist_to_obj / layered_costmap->getCostmap()->getResolution()));
556+
}
557+
558+
532559
float NodeHybrid::getObstacleHeuristic(
533560
const Coordinates & node_coords,
534561
const Coordinates & goal_coords,
535562
const double & cost_penalty)
536563
{
537564
// If already expanded, return the cost
538565
const unsigned int size_x = sampled_costmap->getSizeInCellsX();
566+
const bool is_circular = costmap_ros->getUseRadius();
539567

540568
// Divided by 2 due to downsampled costmap.
541569
unsigned int start_y, start_x;
@@ -605,7 +633,14 @@ float NodeHybrid::getObstacleHeuristic(
605633
// if neighbor path is better and non-lethal, set new cost and add to queue
606634
if (new_idx < size_x * size_y) {
607635
cost = static_cast<float>(sampled_costmap->getCost(new_idx));
608-
if (cost >= INSCRIBED) {
636+
637+
if (!is_circular) {
638+
// Adjust cost value if using SE2 footprint checks
639+
cost = adjustedFootprintCost(cost);
640+
if (cost >= OCCUPIED) {
641+
continue;
642+
}
643+
} else if (cost >= INSCRIBED) {
609644
continue;
610645
}
611646

0 commit comments

Comments
 (0)