6 #include <pcl/conversions.h> 7 #include <pcl/point_cloud.h> 8 #include <pcl/point_types.h> 9 #include <pcl/io/pcd_io.h> 11 #include "sensor_msgs/LaserScan.h" 13 #include <Eigen/Dense> 14 #include <dynamic_reconfigure/server.h> 15 #include <ira_laser_tools/laserscan_virtualizerConfig.h> 27 void scanCallback(
const sensor_msgs::LaserScan::ConstPtr& scan, std::string topic);
28 void pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header,
int pub_index);
29 void pointCloudCallback(
const sensor_msgs::PointCloud2::ConstPtr& pcl_in);
30 void reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level);
41 void virtual_laser_scan_parser();
60 this->angle_min = config.angle_min;
61 this->angle_max = config.angle_max;
62 this->angle_increment = config.angle_increment;
63 this->time_increment = config.time_increment;
64 this->scan_time = config.scan_time;
65 this->range_min = config.range_min;
66 this->range_max = config.range_max;
72 istringstream iss(virtual_laser_scan);
73 vector<string> tokens;
74 copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter<vector<string> >(tokens));
76 vector<string> tmp_output_frames;
78 for(
int i=0;i<tokens.size();++i)
84 cout <<
"Adding: " << tokens[i] << endl;
85 tmp_output_frames.push_back(tokens[i]);
88 cout <<
"Can't transform: '" << tokens[i] +
"' to '" << base_frame <<
"'" << endl;
92 sort(tmp_output_frames.begin(),tmp_output_frames.end());
93 std::vector<string>::iterator last = std::unique(tmp_output_frames.begin(), tmp_output_frames.end());
94 tmp_output_frames.erase(last, tmp_output_frames.end());
97 if( (tmp_output_frames.size() != output_frames.size()) || !equal(tmp_output_frames.begin(),tmp_output_frames.end(),output_frames.begin()) )
100 for(
int i=0; i<virtual_scan_publishers.size(); ++i)
101 virtual_scan_publishers[i].shutdown();
105 output_frames = tmp_output_frames;
106 if(output_frames.size() > 0)
108 virtual_scan_publishers.resize(output_frames.size());
109 ROS_INFO(
"Publishing: %ld virtual scans", virtual_scan_publishers.size() );
110 cout <<
"Advertising topics: " << endl;
111 for(
int i=0; i<output_frames.size(); ++i)
113 if (output_laser_topic.empty())
115 virtual_scan_publishers[i] = node_.advertise<sensor_msgs::LaserScan> (output_frames[i].c_str(), 1);
116 cout <<
"\t\t" << output_frames[i] <<
" on topic " << output_frames[i].c_str() << endl;
120 virtual_scan_publishers[i] = node_.advertise<sensor_msgs::LaserScan> (output_laser_topic.c_str(), 1);
121 cout <<
"\t\t" << output_frames[i] <<
" on topic " << output_laser_topic.c_str() << endl;
126 ROS_INFO(
"Not publishing to any topic.");
135 if(!nh.
getParam(
"/laserscan_virtualizer/base_frame", base_frame)) base_frame =
"/cart_frame";
136 if(!nh.
getParam(
"/laserscan_virtualizer/cloud_topic", cloud_topic)) cloud_topic =
"/cloud_pcd";
137 nh.
getParam(
"/laserscan_virtualizer/output_laser_topic", output_laser_topic);
138 nh.
getParam(
"/laserscan_virtualizer/virtual_laser_scan", virtual_laser_scan);
140 this->virtual_laser_scan_parser();
148 if(cloud_frame.empty())
150 cloud_frame = (*pcl_in).header.frame_id;
151 transform_.resize(output_frames.size());
152 for(
int i=0; i<output_frames.size(); ++i)
154 tfListener_.lookupTransform (output_frames[i] , cloud_frame,
ros::Time(0), transform_[i]);
157 for(
int i=0; i<output_frames.size(); ++i)
160 pcl::PCLPointCloud2 tmpPcl2;
163 pcl::fromPCLPointCloud2(tmpPcl2,tmpPcl);
167 string tmpFrame = output_frames[i] ;
168 pcl_out.header = tmpPcl.header;
172 pcl_out.header.frame_id = tmpFrame;
175 Eigen::MatrixXf tmpEigenMatrix;
176 pcl::toPCLPointCloud2(pcl_out, tmpPcl2);
177 pcl::getPointCloudAsEigen(tmpPcl2,tmpEigenMatrix);
180 pointcloud_to_laserscan(tmpEigenMatrix, pcl_out.header, i);
187 sensor_msgs::LaserScanPtr output(
new sensor_msgs::LaserScan());
189 output->angle_min = this->angle_min;
190 output->angle_max = this->angle_max;
191 output->angle_increment = this->angle_increment;
192 output->time_increment = this->time_increment;
193 output->scan_time = this->scan_time;
194 output->range_min = this->range_min;
195 output->range_max = this->range_max;
197 uint32_t ranges_size = std::ceil((output->angle_max - output->angle_min) / output->angle_increment);
198 output->ranges.assign(ranges_size, output->range_max + 1.0);
200 for(
int i=0; i<points.cols(); i++)
202 const float &
x = points(0,i);
203 const float &
y = points(1,i);
204 const float &
z = points(2,i);
206 if ( std::isnan(x) || std::isnan(y) || std::isnan(z) )
208 ROS_DEBUG(
"rejected for nan in point(%f, %f, %f)\n", x, y, z);
212 if ( std::abs(z) > 0.01 )
220 double range_sq = y*y+x*x;
221 double range_min_sq_ = output->range_min * output->range_min;
222 if (range_sq < range_min_sq_) {
223 ROS_DEBUG(
"rejected for range %f below minimum value %f. Point: (%f, %f, %f)", range_sq, range_min_sq_, x, y, z);
227 double angle = atan2(y, x);
228 if (angle < output->angle_min || angle > output->angle_max)
230 ROS_DEBUG(
"rejected for angle %f not in range (%f, %f)\n", angle, output->angle_min, output->angle_max);
233 int index = (angle - output->angle_min) / output->angle_increment;
236 if (output->ranges[index] * output->ranges[index] > range_sq)
237 output->ranges[index] = sqrt(range_sq);
240 virtual_scan_publishers[pub_index].publish(output);
243 int main(
int argc,
char** argv)
245 ros::init(argc, argv,
"laserscan_virtualizer");
249 dynamic_reconfigure::Server<laserscan_virtualizerConfig> server;
250 dynamic_reconfigure::Server<laserscan_virtualizerConfig>::CallbackType
f;
253 server.setCallback(f);
vector< string > output_frames
string output_laser_topic
string virtual_laser_scan
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &pcl_in)
tf::TransformListener tfListener_
void pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index)
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
ROSCPP_DECL void spin(Spinner &spinner)
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
vector< tf::StampedTransform > transform_
TFSIMD_FORCE_INLINE const tfScalar & x() const
TFSIMD_FORCE_INLINE const tfScalar & z() const
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
bool getParam(const std::string &key, std::string &s) const
void reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level)
int main(int argc, char **argv)
ros::Subscriber point_cloud_subscriber_
pcl::PointCloud< pcl::PointXYZ > myPointCloud
void virtual_laser_scan_parser()
vector< ros::Publisher > virtual_scan_publishers
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)