41 #include "tf2/convert.h"
42 #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
44 #include "nav2_costmap_2d/costmap_filters/keepout_filter.hpp"
45 #include "nav2_costmap_2d/costmap_filters/filter_values.hpp"
51 : filter_info_sub_(nullptr), mask_sub_(nullptr), mask_costmap_(nullptr),
52 mask_frame_(
""), global_frame_(
"")
57 const std::string & filter_info_topic)
59 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
61 rclcpp_lifecycle::LifecycleNode::SharedPtr node = node_.lock();
63 throw std::runtime_error{
"Failed to lock node"};
70 "KeepoutFilter: Subscribing to \"%s\" topic for filter info...",
72 filter_info_sub_ = node->create_subscription<nav2_msgs::msg::CostmapFilterInfo>(
74 std::bind(&KeepoutFilter::filterInfoCallback,
this, std::placeholders::_1));
76 global_frame_ = layered_costmap_->getGlobalFrameID();
79 void KeepoutFilter::filterInfoCallback(
80 const nav2_msgs::msg::CostmapFilterInfo::SharedPtr msg)
82 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
84 rclcpp_lifecycle::LifecycleNode::SharedPtr node = node_.lock();
86 throw std::runtime_error{
"Failed to lock node"};
96 "KeepoutFilter: New costmap filter info arrived from %s topic. Updating old filter info.",
103 if (msg->base != BASE_DEFAULT || msg->multiplier != MULTIPLIER_DEFAULT) {
106 "KeepoutFilter: For proper use of keepout filter base and multiplier"
107 " in CostmapFilterInfo message should be set to their default values (%f and %f)",
108 BASE_DEFAULT, MULTIPLIER_DEFAULT);
116 "KeepoutFilter: Subscribing to \"%s\" topic for filter mask...",
118 mask_sub_ = node->create_subscription<nav_msgs::msg::OccupancyGrid>(
119 mask_topic_, rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
120 std::bind(&KeepoutFilter::maskCallback,
this, std::placeholders::_1));
123 void KeepoutFilter::maskCallback(
124 const nav_msgs::msg::OccupancyGrid::SharedPtr msg)
126 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
128 rclcpp_lifecycle::LifecycleNode::SharedPtr node = node_.lock();
130 throw std::runtime_error{
"Failed to lock node"};
133 if (!mask_costmap_) {
136 "KeepoutFilter: Received filter mask from %s topic.",
mask_topic_.c_str());
140 "KeepoutFilter: New filter mask arrived from %s topic. Updating old filter mask.",
142 mask_costmap_.reset();
146 mask_costmap_ = std::make_unique<Costmap2D>(*msg);
147 mask_frame_ = msg->header.frame_id;
149 has_updated_data_ =
true;
151 width_ = msg->info.width;
152 height_ = msg->info.height;
156 double robot_x,
double robot_y,
double robot_yaw,
157 double * min_x,
double * min_y,
double * max_x,
double * max_y)
165 if (!has_updated_data_) {
172 *min_x = std::min(wx, *min_x);
173 *min_y = std::min(wy, *min_y);
176 *max_x = std::max(wx, *max_x);
177 *max_y = std::max(wy, *max_y);
179 has_updated_data_ =
false;
184 int min_i,
int min_j,
int max_i,
int max_j,
185 const geometry_msgs::msg::Pose2D & )
187 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
189 if (!mask_costmap_) {
191 RCLCPP_WARN_THROTTLE(
192 logger_, *(clock_), 2000,
193 "KeepoutFilter: Filter mask was not received");
197 tf2::Transform tf2_transform;
198 tf2_transform.setIdentity();
199 int mg_min_x, mg_min_y;
200 int mg_max_x, mg_max_y;
202 if (mask_frame_ != global_frame_) {
205 geometry_msgs::msg::TransformStamped transform;
207 transform = tf_->lookupTransform(
208 mask_frame_, global_frame_, tf2::TimePointZero,
210 }
catch (tf2::TransformException & ex) {
213 "KeepoutFilter: Failed to get costmap frame (%s) "
214 "transformation to mask frame (%s) with error: %s",
215 global_frame_.c_str(), mask_frame_.c_str(), ex.what());
218 tf2::fromMsg(transform.transform, tf2_transform);
249 const double half_cell_size = 0.5 * mask_costmap_->getResolution();
250 wx = mask_costmap_->getOriginX() + half_cell_size;
251 wy = mask_costmap_->getOriginY() + half_cell_size;
254 if (mg_min_x >= max_i || mg_min_y >= max_j) {
258 mg_min_x = std::max(min_i, mg_min_x);
259 mg_min_y = std::max(min_j, mg_min_y);
263 wx = mask_costmap_->getOriginX() +
264 mask_costmap_->getSizeInCellsX() * mask_costmap_->getResolution() + half_cell_size;
265 wy = mask_costmap_->getOriginY() +
266 mask_costmap_->getSizeInCellsY() * mask_costmap_->getResolution() + half_cell_size;
269 if (mg_max_x <= min_i || mg_max_y <= min_j) {
273 mg_max_x = std::min(max_i, mg_max_x);
274 mg_max_y = std::min(max_j, mg_max_y);
278 unsigned const int mg_min_x_u =
static_cast<unsigned int>(mg_min_x);
279 unsigned const int mg_min_y_u =
static_cast<unsigned int>(mg_min_y);
280 unsigned const int mg_max_x_u =
static_cast<unsigned int>(mg_max_x);
281 unsigned const int mg_max_y_u =
static_cast<unsigned int>(mg_max_y);
286 double msk_wx, msk_wy;
288 unsigned char data, old_data;
292 unsigned char * master_array = master_grid.
getCharMap();
293 for (i = mg_min_x_u; i < mg_max_x_u; i++) {
294 for (j = mg_min_y_u; j < mg_max_y_u; j++) {
296 old_data = master_array[index];
300 if (mask_frame_ != global_frame_) {
302 tf2::Vector3 point(gl_wx, gl_wy, 0);
303 point = tf2_transform * point;
312 if (mask_costmap_->worldToMap(msk_wx, msk_wy, mx, my)) {
313 data = mask_costmap_->getCost(mx, my);
315 if (data == NO_INFORMATION) {
318 if (data > old_data || old_data == NO_INFORMATION) {
319 master_array[index] = data;
328 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
330 filter_info_sub_.reset();
336 std::lock_guard<CostmapFilter::mutex_t> guard(*
getMutex());
346 #include "pluginlib/class_list_macros.hpp"
A 2D costmap provides a mapping between points in the world and their associated "costs".
void mapToWorld(unsigned int mx, unsigned int my, double &wx, double &wy) const
Convert from map coordinates to world coordinates.
unsigned int getIndex(unsigned int mx, unsigned int my) const
Given two map coordinates... compute the associated index.
unsigned char * getCharMap() const
Will return a pointer to the underlying unsigned char array used as the costmap.
void worldToMapNoBounds(double wx, double wy, int &mx, int &my) const
Convert from world coordinates to map coordinates without checking for legal bounds.
std::string filter_info_topic_
: Name of costmap filter info topic
std::string mask_topic_
: Name of filter mask topic
tf2::Duration transform_tolerance_
: mask_frame_->global_frame_ transform tolerance
mutex_t * getMutex()
: returns pointer to a mutex
void updateBounds(double robot_x, double robot_y, double robot_yaw, double *min_x, double *min_y, double *max_x, double *max_y) override
Update the bounds of the master costmap by this layer's update dimensions.
Reads in a keepout mask and marks keepout regions in the map to prevent planning or control in restri...
void process(nav2_costmap_2d::Costmap2D &master_grid, int min_i, int min_j, int max_i, int max_j, const geometry_msgs::msg::Pose2D &pose)
Process the keepout layer at the current pose / bounds / grid.
KeepoutFilter()
A constructor.
void resetFilter()
Reset the costmap filter / topic / info.
void initializeFilter(const std::string &filter_info_topic)
Initialize the filter and subscribe to the info topic.
bool isActive()
If this filter is active.
void updateBounds(double robot_x, double robot_y, double robot_yaw, double *min_x, double *min_y, double *max_x, double *max_y) override
Update the bounds of the master costmap by this layer's update dimensions.
Abstract class for layered costmap plugin implementations.
Costmap2D * getCostmap()
Get the costmap pointer to the master costmap.