box_filter.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Robot Operating System code by the University of Osnabrück
5  * Copyright (c) 2015, University of Osnabrück
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  *
21  * 3. Neither the name of the copyright holder nor the names of its
22  * contributors may be used to endorse or promote products derived
23  * from this software without specific prior written permission.
24  *
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  *
39  *
40  * box_filter.cpp
41  *
42  * author: Sebastian Pütz <spuetz@uni-osnabrueck.de>
43  */
44 
46 #include <ros/ros.h>
47 
49 
50 }
51 
52 
54  ros::NodeHandle private_nh("~" + getName());
55  dyn_server_.reset(new dynamic_reconfigure::Server<BoxFilterConfig>(own_mutex_, private_nh));
56  dynamic_reconfigure::Server<BoxFilterConfig>::CallbackType f;
57  f = [this](auto& config, auto level){ reconfigureCB(config, level); };
58  dyn_server_->setCallback(f);
59 
60  up_and_running_ = true;
61 
62  getParam("box_frame", config_.box_frame);
63  getParam("max_x", config_.max_x);
64  getParam("max_y", config_.max_y);
65  getParam("max_z", config_.max_z);
66  getParam("min_x", config_.min_x);
67  getParam("min_y", config_.min_y);
68  getParam("min_z", config_.min_z);
69  getParam("invert", config_.invert);
70  dyn_server_->updateConfig(config_);
71 
72  ROS_INFO("BOX filter started");
73  ROS_INFO("Box frame is: %s", config_.box_frame.c_str());
74  ROS_INFO("Box: x_min %f, x_max, %f, y_min, %f, y_max, %f, min_z %f, max_z %f", config_.min_x,
75  config_.max_x, config_.min_y, config_.max_y, config_.min_z, config_.max_z);
76  ROS_INFO("Box filter invert: %d", config_.invert);
77  return true;
78 }
79 
81  const sensor_msgs::LaserScan& input_scan,
82  sensor_msgs::LaserScan &output_scan)
83 {
84  output_scan = input_scan;
85  sensor_msgs::PointCloud2 laser_cloud;
86 
87  std::string error_msg;
88 
89  bool success = tf_.waitForTransform(
90  config_.box_frame,
91  input_scan.header.frame_id,
92  input_scan.header.stamp + ros::Duration().fromSec(input_scan.ranges.size()*input_scan.time_increment),
93  ros::Duration(1.0),
94  ros::Duration(0.01),
95  &error_msg
96  );
97  if(!success){
98  ROS_WARN("Could not get transform, irgnoring laser scan! %s", error_msg.c_str());
99  return false;
100  }
101 
102  try{
103  projector_.transformLaserScanToPointCloud(config_.box_frame, input_scan, laser_cloud, tf_);
104  }
105  catch(tf::TransformException& ex){
106  if(up_and_running_){
107  ROS_WARN_THROTTLE(1, "Dropping Scan: Tansform unavailable %s", ex.what());
108  return true;
109  }
110  else
111  {
112  ROS_INFO_THROTTLE(.3, "Ignoring Scan: Waiting for TF");
113  }
114  return false;
115  }
116  const int i_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "index");
117  const int x_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "x");
118  const int y_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "y");
119  const int z_idx_c = sensor_msgs::getPointCloud2FieldIndex(laser_cloud, "z");
120 
121  if(i_idx_c == -1 || x_idx_c == -1 || y_idx_c == -1 || z_idx_c == -1){
122  ROS_INFO_THROTTLE(.3, "x, y, z and index fields are required, skipping scan");
123 
124  }
125 
126 
127  const int i_idx_offset = laser_cloud.fields[i_idx_c].offset;
128  const int x_idx_offset = laser_cloud.fields[x_idx_c].offset;
129  const int y_idx_offset = laser_cloud.fields[y_idx_c].offset;
130  const int z_idx_offset = laser_cloud.fields[z_idx_c].offset;
131 
132  const int pstep = laser_cloud.point_step;
133  const long int pcount = laser_cloud.width * laser_cloud.height;
134  const long int limit = pstep * pcount;
135 
136  int i_idx, x_idx, y_idx, z_idx;
137  for(
138  i_idx = i_idx_offset,
139  x_idx = x_idx_offset,
140  y_idx = y_idx_offset,
141  z_idx = z_idx_offset;
142 
143  x_idx < limit;
144 
145  i_idx += pstep,
146  x_idx += pstep,
147  y_idx += pstep,
148  z_idx += pstep)
149  {
150 
151  // TODO works only for float data types and with an index field
152  // I'm working on it, see https://github.com/ros/common_msgs/pull/78
153  float x = *((float*)(&laser_cloud.data[x_idx]));
154  float y = *((float*)(&laser_cloud.data[y_idx]));
155  float z = *((float*)(&laser_cloud.data[z_idx]));
156  int index = *((int*)(&laser_cloud.data[i_idx]));
157 
158  tf::Point point(x, y, z);
159 
160  if(!config_.invert){
161  if(inBox(point)){
162  output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
163  }
164  }
165  else{
166  if(!inBox(point)){
167  output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
168  }
169  }
170 
171  }
172  up_and_running_ = true;
173  return true;
174 }
175 
177  return
178  point.x() < config_.max_x && point.x() > config_.min_x &&
179  point.y() < config_.max_y && point.y() > config_.min_y &&
180  point.z() < config_.max_z && point.z() > config_.min_z;
181 }
182 
183 void laser_filters::LaserScanBoxFilter::reconfigureCB(BoxFilterConfig& config, uint32_t level)
184 {
185  config_ = config;
186 }
187 
DurationBase< Duration >::fromSec
Duration & fromSec(double t)
sensor_msgs::getPointCloud2FieldIndex
static int getPointCloud2FieldIndex(const sensor_msgs::PointCloud2 &cloud, const std::string &field_name)
ROS_WARN_THROTTLE
#define ROS_WARN_THROTTLE(period,...)
ros.h
laser_filters::LaserScanBoxFilter::LaserScanBoxFilter
LaserScanBoxFilter()
Definition: box_filter.cpp:48
getName
ROSCONSOLE_CONSOLE_IMPL_DECL std::string getName(void *handle)
f
f
laser_filters::LaserScanBoxFilter::update
bool update(const sensor_msgs::LaserScan &input_scan, sensor_msgs::LaserScan &filtered_scan)
Definition: box_filter.cpp:80
laser_filters::LaserScanBoxFilter::reconfigureCB
void reconfigureCB(BoxFilterConfig &config, uint32_t level)
Definition: box_filter.cpp:183
box_filter.h
tf::Point
tf::Vector3 Point
ROS_WARN
#define ROS_WARN(...)
laser_filters::LaserScanBoxFilter::configure
bool configure()
Definition: box_filter.cpp:53
tf2::TransformException
ROS_INFO
#define ROS_INFO(...)
ros::Duration
laser_filters::LaserScanBoxFilter::inBox
bool inBox(tf::Point &point)
Definition: box_filter.cpp:176
ros::NodeHandle
ROS_INFO_THROTTLE
#define ROS_INFO_THROTTLE(period,...)


laser_filters
Author(s): Tully Foote
autogenerated on Mon Apr 3 2023 02:51:57