45 #include <dynamic_reconfigure/server.h> 46 #include <laser_filters/PolygonFilterConfig.h> 47 #include <geometry_msgs/PolygonStamped.h> 56 return x < 0.0 ? -1.0 : (x > 0.0 ? 1.0 : 0.0);
59 void padPolygon(geometry_msgs::Polygon& polygon,
double padding)
62 for (
unsigned int i = 0; i < polygon.points.size(); i++)
64 geometry_msgs::Point32& pt = polygon.points[ i ];
65 pt.x +=
sign0(pt.x) * padding;
66 pt.y +=
sign0(pt.y) * padding;
75 std::string& value_string = value;
76 ROS_FATAL(
"Values in the polygon specification (param %s) must be numbers. Found value %s.",
77 full_param_name.c_str(), value_string.c_str());
78 throw std::runtime_error(
"Values in the polygon specification must be numbers");
84 const std::string& full_param_name)
88 polygon_xmlrpc.
size() > 0 && polygon_xmlrpc.
size() < 3)
90 ROS_FATAL(
"The polygon (parameter %s) must be specified as nested list on the parameter server with at least " 91 "3 points eg: [[x1, y1], [x2, y2], ..., [xn, yn]]",
92 full_param_name.c_str());
94 throw std::runtime_error(
"The polygon must be specified as nested list on the parameter server with at least " 95 "3 points eg: [[x1, y1], [x2, y2], ..., [xn, yn]]");
97 geometry_msgs::Polygon polygon;
98 geometry_msgs::Point32 pt;
100 for (
int i = 0; i < polygon_xmlrpc.
size(); ++i)
106 ROS_FATAL(
"The polygon (parameter %s) must be specified as list of lists on the parameter server eg: " 107 "[[x1, y1], [x2, y2], ..., [xn, yn]], but this spec is not of that form.",
108 full_param_name.c_str());
109 throw std::runtime_error(
"The polygon must be specified as list of lists on the parameter server eg: " 110 "[[x1, y1], [x2, y2], ..., [xn, yn]], but this spec is not of that form");
116 polygon.points.push_back(pt);
121 std::vector<std::vector<float> >
parseVVF(
const std::string& input, std::string& error_return)
123 std::vector<std::vector<float> > result;
125 std::stringstream input_ss(input);
127 std::vector<float> current_vector;
128 while (!!input_ss && !input_ss.eof())
130 switch (input_ss.peek())
138 error_return =
"Array depth greater than 2";
142 current_vector.clear();
148 error_return =
"More close ] than open [";
154 result.push_back(current_vector);
165 std::stringstream err_ss;
166 err_ss <<
"Numbers at depth other than 2. Char was '" << char(input_ss.peek()) <<
"'.";
167 error_return = err_ss.str();
174 current_vector.push_back(value);
182 error_return =
"Unterminated vector string.";
192 geometry_msgs::Polygon
makePolygonFromString(
const std::string& polygon_string,
const geometry_msgs::Polygon& last_polygon)
195 std::vector<std::vector<float> > vvf =
parseVVF(polygon_string, error);
199 ROS_ERROR(
"Error parsing polygon parameter: '%s'", error.c_str());
200 ROS_ERROR(
" Polygon string was '%s'.", polygon_string.c_str());
204 geometry_msgs::Polygon polygon;
205 geometry_msgs::Point32 point;
208 if (vvf.size() < 3 && vvf.size() > 0)
210 ROS_WARN(
"You must specify at least three points for the robot polygon");
214 for (
unsigned int i = 0; i < vvf.size(); i++)
216 if (vvf[ i ].size() == 2)
218 point.x = vvf[ i ][ 0 ];
219 point.y = vvf[ i ][ 1 ];
221 polygon.points.push_back(point);
225 ROS_ERROR(
"Points in the polygon specification must be pairs of numbers. Found a point with %d numbers.",
226 int(vvf[ i ].size()));
236 std::string polygon_string =
"[";
238 for (
auto point : polygon.points) {
240 polygon_string +=
", ";
243 polygon_string +=
"[" + std::to_string(point.x) +
", " + std::to_string(point.y) +
"]";
245 polygon_string +=
"]";
246 return polygon_string;
257 std::string polygon_string;
258 PolygonFilterConfig param_config;
261 dyn_server_.reset(
new dynamic_reconfigure::Server<laser_filters::PolygonFilterConfig>(
own_mutex_, private_nh));
262 dynamic_reconfigure::Server<laser_filters::PolygonFilterConfig>::CallbackType
f;
266 bool polygon_set =
getParam(
"polygon", polygon_xmlrpc);
271 double polygon_padding = 0;
272 getParam(
"polygon_padding", polygon_padding);
275 param_config.polygon = polygon_string;
276 param_config.polygon_padding = polygon_padding;
282 if (!polygon_frame_set)
292 ROS_INFO(
"invert filter not set, assuming false");
296 return polygon_frame_set && polygon_set;
300 sensor_msgs::LaserScan& output_scan)
302 boost::recursive_mutex::scoped_lock lock(
own_mutex_);
304 geometry_msgs::PolygonStamped polygon_stamped;
310 output_scan = input_scan;
312 sensor_msgs::PointCloud2 laser_cloud;
314 std::string error_msg;
318 input_scan.header.stamp +
ros::Duration().
fromSec(input_scan.ranges.size() * input_scan.time_increment),
322 ROS_WARN(
"Could not get transform, ignoring laser scan! %s", error_msg.c_str());
340 if (i_idx_c == -1 || x_idx_c == -1 || y_idx_c == -1 || z_idx_c == -1)
345 const int i_idx_offset = laser_cloud.fields[i_idx_c].offset;
346 const int x_idx_offset = laser_cloud.fields[x_idx_c].offset;
347 const int y_idx_offset = laser_cloud.fields[y_idx_c].offset;
348 const int z_idx_offset = laser_cloud.fields[z_idx_c].offset;
350 const int pstep = laser_cloud.point_step;
351 const long int pcount = laser_cloud.width * laser_cloud.height;
352 const long int limit = pstep * pcount;
354 int i_idx, x_idx, y_idx, z_idx;
355 for (i_idx = i_idx_offset, x_idx = x_idx_offset, y_idx = y_idx_offset, z_idx = z_idx_offset;
359 i_idx += pstep, x_idx += pstep, y_idx += pstep, z_idx += pstep)
363 float x = *((
float*)(&laser_cloud.data[x_idx]));
364 float y = *((
float*)(&laser_cloud.data[y_idx]));
365 float z = *((
float*)(&laser_cloud.data[z_idx]));
366 int index = *((
int*)(&laser_cloud.data[i_idx]));
374 output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
381 output_scan.ranges[index] = std::numeric_limits<float>::quiet_NaN();
395 for (i = 0, j =
polygon_.points.size() - 1; i <
polygon_.points.size(); j = i++)
397 if ((
polygon_.points.at(i).y > point.y() != (
polygon_.points.at(j).y > point.y()) &&
static int getPointCloud2FieldIndex(const sensor_msgs::PointCloud2 &cloud, const std::string &field_name)
laser_geometry::LaserProjection projector_
std::string polygonToString(geometry_msgs::Polygon polygon)
LaserScanMaskFilter removes points on directions defined in a mask from a laser scan.
std::shared_ptr< dynamic_reconfigure::Server< laser_filters::PolygonFilterConfig > > dyn_server_
const std::string & getName() const
double getNumberFromXMLRPC(XmlRpc::XmlRpcValue &value, const std::string &full_param_name)
void padPolygon(geometry_msgs::Polygon &polygon, double padding)
ros::Publisher polygon_pub_
geometry_msgs::Polygon makePolygonFromXMLRPC(const XmlRpc::XmlRpcValue &polygon_xmlrpc, const std::string &full_param_name)
geometry_msgs::Polygon makePolygonFromString(const std::string &polygon_string, const geometry_msgs::Polygon &last_polygon)
Type const & getType() const
void publish(const boost::shared_ptr< M > &message) const
#define ROS_INFO_THROTTLE(period,...)
bool inPolygon(tf::Point &point) const
Duration & fromSec(double t)
tf::TransformListener tf_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void reconfigureCB(laser_filters::PolygonFilterConfig &config, uint32_t level)
std::vector< std::vector< float > > parseVVF(const std::string &input, std::string &error_return)
bool getParam(const std::string &name, std::string &value) const
bool update(const sensor_msgs::LaserScan &input_scan, sensor_msgs::LaserScan &filtered_scan)
double sign0(double x)
Same as sign(x) but returns 0 if x is 0.
boost::recursive_mutex own_mutex_
void transformLaserScanToPointCloud(const std::string &target_frame, const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, tf::Transformer &tf, double range_cutoff, int channel_options=channel_option::Default)
std::string polygon_frame_
geometry_msgs::Polygon polygon_