-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
obstacles_critic.cpp
217 lines (184 loc) · 7.53 KB
/
obstacles_critic.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Copyright (c) 2022 Samsung Research America, @artofnothingness Alexey Budyakov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include "nav2_mppi_controller/critics/obstacles_critic.hpp"
namespace mppi::critics
{
void ObstaclesCritic::initialize()
{
auto getParam = parameters_handler_->getParamGetter(name_);
getParam(consider_footprint_, "consider_footprint", false);
getParam(power_, "cost_power", 1);
getParam(repulsion_weight_, "repulsion_weight", 1.5);
getParam(critical_weight_, "critical_weight", 20.0);
getParam(collision_cost_, "collision_cost", 10000.0);
getParam(collision_margin_distance_, "collision_margin_distance", 0.10);
getParam(near_goal_distance_, "near_goal_distance", 0.5);
collision_checker_.setCostmap(costmap_);
possibly_inscribed_cost_ = findCircumscribedCost(costmap_ros_);
if (possibly_inscribed_cost_ < 1.0f) {
RCLCPP_ERROR(
logger_,
"Inflation layer either not found or inflation is not set sufficiently for "
"optimized non-circular collision checking capabilities. It is HIGHLY recommended to set"
" the inflation radius to be at MINIMUM half of the robot's largest cross-section. See "
"github.com/ros-planning/navigation2/tree/main/nav2_smac_planner#potential-fields"
" for full instructions. This will substantially impact run-time performance.");
}
RCLCPP_INFO(
logger_,
"ObstaclesCritic instantiated with %d power and %f / %f weights. "
"Critic will collision check based on %s cost.",
power_, critical_weight_, repulsion_weight_, consider_footprint_ ?
"footprint" : "circular");
}
float ObstaclesCritic::findCircumscribedCost(
std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap)
{
double result = -1.0;
bool inflation_layer_found = false;
// check if the costmap has an inflation layer
for (auto layer = costmap->getLayeredCostmap()->getPlugins()->begin();
layer != costmap->getLayeredCostmap()->getPlugins()->end();
++layer)
{
auto inflation_layer = std::dynamic_pointer_cast<nav2_costmap_2d::InflationLayer>(*layer);
if (!inflation_layer) {
continue;
}
inflation_layer_found = true;
const double circum_radius = costmap->getLayeredCostmap()->getCircumscribedRadius();
const double resolution = costmap->getCostmap()->getResolution();
result = inflation_layer->computeCost(circum_radius / resolution);
inflation_scale_factor_ = static_cast<float>(inflation_layer->getCostScalingFactor());
inflation_radius_ = static_cast<float>(inflation_layer->getInflationRadius());
}
if (!inflation_layer_found) {
RCLCPP_WARN(
logger_,
"No inflation layer found in costmap configuration. "
"If this is an SE2-collision checking plugin, it cannot use costmap potential "
"field to speed up collision checking by only checking the full footprint "
"when robot is within possibly-inscribed radius of an obstacle. This may "
"significantly slow down planning times and not avoid anything but absolute collisions!");
}
return static_cast<float>(result);
}
float ObstaclesCritic::distanceToObstacle(const CollisionCost & cost)
{
const float scale_factor = inflation_scale_factor_;
const float min_radius = costmap_ros_->getLayeredCostmap()->getInscribedRadius();
float dist_to_obj = (scale_factor * min_radius - log(cost.cost) + log(253.0f)) / scale_factor;
// If not footprint collision checking, the cost is using the center point cost and
// needs the radius subtracted to obtain the closest distance to the object
if (!cost.using_footprint) {
dist_to_obj -= min_radius;
}
return dist_to_obj;
}
void ObstaclesCritic::score(CriticData & data)
{
using xt::evaluation_strategy::immediate;
if (!enabled_) {
return;
}
// If near the goal, don't apply the preferential term since the goal is near obstacles
bool near_goal = false;
if (utils::withinPositionGoalTolerance(near_goal_distance_, data.state.pose.pose, data.path)) {
near_goal = true;
}
auto && raw_cost = xt::xtensor<float, 1>::from_shape({data.costs.shape(0)});
raw_cost.fill(0.0f);
auto && repulsive_cost = xt::xtensor<float, 1>::from_shape({data.costs.shape(0)});
repulsive_cost.fill(0.0f);
const size_t traj_len = data.trajectories.x.shape(1);
bool all_trajectories_collide = true;
for (size_t i = 0; i < data.trajectories.x.shape(0); ++i) {
bool trajectory_collide = false;
float traj_cost = 0.0f;
const auto & traj = data.trajectories;
CollisionCost pose_cost;
for (size_t j = 0; j < traj_len; j++) {
pose_cost = costAtPose(traj.x(i, j), traj.y(i, j), traj.yaws(i, j));
if (pose_cost.cost < 1.0f) {continue;} // In free space
if (inCollision(pose_cost.cost)) {
trajectory_collide = true;
break;
}
// Cannot process repulsion if inflation layer does not exist
if (inflation_radius_ == 0.0f || inflation_scale_factor_ == 0.0f) {
continue;
}
const float dist_to_obj = distanceToObstacle(pose_cost);
// Let near-collision trajectory points be punished severely
if (dist_to_obj < collision_margin_distance_) {
traj_cost += (collision_margin_distance_ - dist_to_obj);
} else if (!near_goal) { // Generally prefer trajectories further from obstacles
repulsive_cost[i] += (inflation_radius_ - dist_to_obj);
}
}
if (!trajectory_collide) {all_trajectories_collide = false;}
raw_cost[i] = trajectory_collide ? collision_cost_ : traj_cost;
}
data.costs += xt::pow(
(critical_weight_ * raw_cost) +
(repulsion_weight_ * repulsive_cost / traj_len),
power_);
data.fail_flag = all_trajectories_collide;
}
/**
* @brief Checks if cost represents a collision
* @param cost Costmap cost
* @return bool if in collision
*/
bool ObstaclesCritic::inCollision(float cost) const
{
bool is_tracking_unknown =
costmap_ros_->getLayeredCostmap()->isTrackingUnknown();
switch (static_cast<unsigned char>(cost)) {
using namespace nav2_costmap_2d; // NOLINT
case (LETHAL_OBSTACLE):
return true;
case (INSCRIBED_INFLATED_OBSTACLE):
return consider_footprint_ ? false : true;
case (NO_INFORMATION):
return is_tracking_unknown ? false : true;
}
return false;
}
CollisionCost ObstaclesCritic::costAtPose(float x, float y, float theta)
{
CollisionCost collision_cost;
float & cost = collision_cost.cost;
collision_cost.using_footprint = false;
unsigned int x_i, y_i;
if (!collision_checker_.worldToMap(x, y, x_i, y_i)) {
cost = nav2_costmap_2d::NO_INFORMATION;
return collision_cost;
}
cost = collision_checker_.pointCost(x_i, y_i);
if (consider_footprint_ &&
(cost >= possibly_inscribed_cost_ || possibly_inscribed_cost_ < 1.0f))
{
cost = static_cast<float>(collision_checker_.footprintCostAtPose(
x, y, theta, costmap_ros_->getRobotFootprint()));
collision_cost.using_footprint = true;
}
return collision_cost;
}
} // namespace mppi::critics
#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(
mppi::critics::ObstaclesCritic,
mppi::critics::CriticFunction)