20 #include "nav2_costmap_2d/clear_costmap_service.hpp"
21 #include "nav2_costmap_2d/costmap_2d_ros.hpp"
28 using std::shared_ptr;
30 using ClearExceptRegion = nav2_msgs::srv::ClearCostmapExceptRegion;
31 using ClearAroundRobot = nav2_msgs::srv::ClearCostmapAroundRobot;
32 using ClearAroundPose = nav2_msgs::srv::ClearCostmapAroundPose;
33 using ClearEntirely = nav2_msgs::srv::ClearEntireCostmap;
36 const nav2::LifecycleNode::WeakPtr & parent,
40 auto node = parent.lock();
41 logger_ = node->get_logger();
44 clear_except_service_ = node->create_service<ClearExceptRegion>(
45 std::string(
"clear_except_") + costmap_.
getName(),
47 &ClearCostmapService::clearExceptRegionCallback,
this,
48 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
50 clear_around_service_ = node->create_service<ClearAroundRobot>(
51 std::string(
"clear_around_") + costmap_.
getName(),
53 &ClearCostmapService::clearAroundRobotCallback,
this,
54 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
56 clear_around_pose_service_ = node->create_service<ClearAroundPose>(
57 std::string(
"clear_around_pose_") + costmap_.
getName(),
59 &ClearCostmapService::clearAroundPoseCallback,
this,
60 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
62 clear_entire_service_ = node->create_service<ClearEntirely>(
63 std::string(
"clear_entirely_") + costmap_.
getName(),
65 &ClearCostmapService::clearEntireCallback,
this,
66 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
72 clear_except_service_.reset();
73 clear_around_service_.reset();
74 clear_around_pose_service_.reset();
75 clear_entire_service_.reset();
78 void ClearCostmapService::clearExceptRegionCallback(
79 const shared_ptr<rmw_request_id_t>,
80 const shared_ptr<ClearExceptRegion::Request> request,
81 const shared_ptr<ClearExceptRegion::Response> response)
85 "Received request to clear except a region for " <<
86 (request->plugins.empty() ?
"all layers" :
"specific layers") <<
" in " <<
89 response->success =
clearRegion(request->reset_distance,
true, request->plugins);
92 void ClearCostmapService::clearAroundRobotCallback(
93 const shared_ptr<rmw_request_id_t>,
94 const shared_ptr<ClearAroundRobot::Request> request,
95 const shared_ptr<ClearAroundRobot::Response> response)
99 "Received request to clear around robot for " <<
100 (request->plugins.empty() ?
"all layers" :
"specific layers") <<
" in " <<
103 response->success =
clearRegion(request->reset_distance,
false, request->plugins);
106 void ClearCostmapService::clearAroundPoseCallback(
107 const shared_ptr<rmw_request_id_t>,
108 const shared_ptr<ClearAroundPose::Request> request,
109 const shared_ptr<ClearAroundPose::Response> response)
113 "Received request to clear around pose for " <<
114 (request->plugins.empty() ?
"all layers" :
"specific layers") <<
" in " <<
117 response->success =
clearAroundPose(request->pose, request->reset_distance, request->plugins);
120 void ClearCostmapService::clearEntireCallback(
121 const std::shared_ptr<rmw_request_id_t>,
122 const std::shared_ptr<ClearEntirely::Request> request,
123 const std::shared_ptr<ClearEntirely::Response> response)
127 "Received request to clear entirely for " <<
128 (request->plugins.empty() ?
"all layers" :
"specific layers") <<
" in " <<
135 const geometry_msgs::msg::PoseStamped & pose,
136 const double reset_distance,
137 const std::vector<std::string> & plugins)
142 geometry_msgs::msg::PoseStamped global_pose;
147 costmap_.getTfBuffer()->transform(pose, global_pose, costmap_.
getGlobalFrameID());
149 }
catch (tf2::TransformException & ex) {
152 "Cannot clear map around pose because pose cannot be transformed to costmap frame: %s",
157 x = global_pose.pose.position.x;
158 y = global_pose.pose.position.y;
162 if (!plugins.empty()) {
163 return validateAndClearPlugins(
165 [
this, x, y, reset_distance](std::shared_ptr<CostmapLayer> & layer) {
166 clearLayerRegion(layer, x, y, reset_distance,
false);
168 "clear costmap around pose");
171 for (
auto & layer : *layers) {
172 if (layer->isClearable()) {
173 auto costmap_layer = std::static_pointer_cast<CostmapLayer>(layer);
174 clearLayerRegion(costmap_layer, x, y, reset_distance,
false);
182 const double reset_distance,
bool invert,
183 const std::vector<std::string> & plugins)
187 if (!getPosition(x, y)) {
190 "Cannot clear map because robot pose cannot be retrieved.");
196 if (!plugins.empty()) {
197 return validateAndClearPlugins(
199 [
this, x, y, reset_distance, invert](std::shared_ptr<CostmapLayer> & layer) {
200 clearLayerRegion(layer, x, y, reset_distance, invert);
202 "clear costmap region");
205 for (
auto & layer : *layers) {
206 if (layer->isClearable()) {
207 auto costmap_layer = std::static_pointer_cast<CostmapLayer>(layer);
208 clearLayerRegion(costmap_layer, x, y, reset_distance, invert);
215 void ClearCostmapService::clearLayerRegion(
216 shared_ptr<CostmapLayer> & costmap,
double pose_x,
double pose_y,
double reset_distance,
219 std::unique_lock<Costmap2D::mutex_t> lock(*(costmap->getMutex()));
221 double start_point_x = pose_x - reset_distance / 2;
222 double start_point_y = pose_y - reset_distance / 2;
223 double end_point_x = start_point_x + reset_distance;
224 double end_point_y = start_point_y + reset_distance;
226 int start_x, start_y, end_x, end_y;
227 costmap->worldToMapNoBounds(start_point_x, start_point_y, start_x, start_y);
228 costmap->worldToMapNoBounds(end_point_x, end_point_y, end_x, end_y);
230 costmap->clearArea(start_x, start_y, end_x, end_y, invert);
232 double ox = costmap->getOriginX(), oy = costmap->getOriginY();
233 double width = costmap->getSizeInMetersX(), height = costmap->getSizeInMetersY();
234 costmap->addExtraBounds(ox, oy, ox + width, oy + height);
239 if (plugins.empty()) {
241 std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_.
getCostmap()->getMutex()));
242 RCLCPP_INFO(logger_,
"Clearing all layers in costmap: %s", costmap_.
getName().c_str());
247 std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_.
getCostmap()->getMutex()));
250 bool result = validateAndClearPlugins(
252 [](
const std::shared_ptr<CostmapLayer> & layer) {
253 layer->resetMap(0, 0, layer->getSizeInCellsX(), layer->getSizeInCellsY());
255 "clear costmap entirely");
258 RCLCPP_INFO(logger_,
"Resetting master costmap after plugin clearing");
268 void ClearCostmapService::validatePlugins(
269 const std::vector<std::string> & requested_plugins,
270 const std::vector<std::shared_ptr<Layer>> * layers,
271 std::vector<std::string> & invalid_plugins)
const
273 invalid_plugins.clear();
275 for (
const auto & requested_plugin : requested_plugins) {
277 bool clearable =
false;
279 for (
auto & layer : *layers) {
280 if (layer->getName() == requested_plugin) {
282 clearable = layer->isClearable();
288 invalid_plugins.push_back(requested_plugin +
" (not found)");
289 }
else if (!clearable) {
290 invalid_plugins.push_back(requested_plugin +
" (not clearable)");
295 bool ClearCostmapService::validateAndClearPlugins(
296 const std::vector<std::string> & plugins,
297 const std::vector<std::shared_ptr<Layer>> * layers,
298 std::function<
void(std::shared_ptr<CostmapLayer> &)> clear_callback,
299 const std::string & operation_name)
const
301 std::vector<std::string> invalid_plugins;
303 validatePlugins(plugins, layers, invalid_plugins);
305 if (!invalid_plugins.empty()) {
306 std::string error_msg =
"Invalid plugin(s) requested for clearing: ";
307 for (
size_t i = 0; i < invalid_plugins.size(); ++i) {
308 error_msg += invalid_plugins[i];
309 if (i < invalid_plugins.size() - 1) {
313 RCLCPP_ERROR(logger_,
"%s", error_msg.c_str());
316 "Failed to %s: %zu invalid plugin(s) out of %zu requested. No layers were cleared.",
317 operation_name.c_str(), invalid_plugins.size(), plugins.size());
321 for (
auto & layer : *layers) {
322 if (std::find(plugins.begin(), plugins.end(),
323 layer->getName()) != plugins.end())
325 auto costmap_layer = std::static_pointer_cast<CostmapLayer>(layer);
326 clear_callback(costmap_layer);
327 RCLCPP_INFO(logger_,
"Performed action '%s' on layer: %s", operation_name.c_str(),
328 layer->getName().c_str());
335 bool ClearCostmapService::getPosition(
double & x,
double & y)
const
337 geometry_msgs::msg::PoseStamped pose;
342 x = pose.pose.position.x;
343 y = pose.pose.position.y;
bool clearAroundPose(const geometry_msgs::msg::PoseStamped &pose, double reset_distance, const std::vector< std::string > &plugins)
Clears the region around a specific pose.
~ClearCostmapService()
A destructor.
bool clearEntirely(const std::vector< std::string > &plugins)
Clears the entire layer.
ClearCostmapService()=delete
A constructor.
bool clearRegion(double reset_distance, bool invert, const std::vector< std::string > &plugins)
Clears the region outside of a user-specified area reverting to the static map.
A ROS wrapper for a 2D Costmap. Handles subscribing to topics that provide observations about obstacl...
bool getRobotPose(geometry_msgs::msg::PoseStamped &global_pose)
Get the pose of the robot in the global frame of the costmap.
std::string getName() const
Returns costmap name.
LayeredCostmap * getLayeredCostmap()
Get the layered costmap object used in the node.
void resetLayers()
Reset each individual layer.
std::string getGlobalFrameID()
Returns the global frame of the costmap.
Costmap2D * getCostmap()
Return a pointer to the "master" costmap which receives updates from all the layers.
void resetMap(unsigned int x0, unsigned int y0, unsigned int xn, unsigned int yn)
Reset the costmap in bounds.
unsigned int getSizeInCellsX() const
Accessor for the x size of the costmap in cells.
unsigned int getSizeInCellsY() const
Accessor for the y size of the costmap in cells.
unsigned char getDefaultValue()
Get the default background value of the costmap.
std::vector< std::shared_ptr< Layer > > * getPlugins()
Get the vector of pointers to the costmap plugins.