00001
00002
00003
00004
00005
00006
00007
00014 #include <ros/ros.h>
00015 #include <geometry_msgs/Point32.h>
00016 #include <nodelet/nodelet.h>
00017 #include <pluginlib/class_list_macros.h>
00018 #include <sensor_msgs/PointCloud.h>
00019 #include <tf/transform_listener.h>
00020
00021 #include <velodyne/ring_sequence.h>
00022 #include <velodyne/data_xyz.h>
00023 using namespace Velodyne;
00024
00025
00026 namespace
00027 {
00028 static const unsigned NCHANNELS = 3;
00029 static const std::string channel_name[NCHANNELS] =
00030 {
00031 "intensity",
00032 "ring",
00033 "heading"
00034 };
00035 }
00036
00037 class TransformNodelet: public nodelet::Nodelet
00038 {
00039 public:
00040 TransformNodelet()
00041 {
00042 data_ = new DataXYZ();
00043 }
00044 ~TransformNodelet()
00045 {
00046 delete data_;
00047 }
00048
00049 private:
00050 virtual void onInit();
00051 void processXYZ(const std::vector<laserscan_xyz_t> &scan,
00052 ros::Time stamp,
00053 const std::string &frame_id);
00054 void allocPacketMsg(sensor_msgs::PointCloud &msg);
00055 void allocSharedMsg();
00056
00058 bool pointInRange(geometry_msgs::Point32 &point)
00059 {
00060 float sum2 = (point.x * point.x
00061 + point.y * point.y
00062 + point.z * point.z);
00063 return (sum2 >= min_range2_ && sum2 <= max_range2_);
00064 }
00065
00066
00067 float max_range2_;
00068 float min_range2_;
00069
00070 DataXYZ *data_;
00071 ros::Subscriber velodyne_scan_;
00072 ros::Publisher output_;
00073 tf::TransformListener listener_;
00074
00076 typedef struct {
00077 std::string frame_id;
00078 double max_range;
00079 double min_range;
00080 int npackets;
00081 } Config;
00082 Config config_;
00083
00084
00085
00086 sensor_msgs::PointCloud inMsg_;
00087 sensor_msgs::PointCloud tfMsg_;
00088 sensor_msgs::PointCloudPtr outPtr_;
00089 int packetCount_;
00090 };
00091
00093 void TransformNodelet::onInit()
00094 {
00095
00096 ros::NodeHandle private_nh = getPrivateNodeHandle();
00097 private_nh.param("frame_id", config_.frame_id, std::string("odom"));
00098 std::string tf_prefix = tf::getPrefixParam(private_nh);
00099 config_.frame_id = tf::resolve(tf_prefix, config_.frame_id);
00100 NODELET_INFO_STREAM("target frame ID: " << config_.frame_id);
00101
00102 private_nh.param("max_range", config_.max_range,
00103 (double) Velodyne::DISTANCE_MAX);
00104 private_nh.param("min_range", config_.min_range, 2.0);
00105 NODELET_INFO_STREAM("data ranges to publish: ["
00106 << config_.min_range << ", "
00107 << config_.max_range << "]");
00108 min_range2_ = config_.min_range * config_.min_range;
00109 max_range2_ = config_.max_range * config_.max_range;
00110
00111 private_nh.param("npackets", config_.npackets, PACKETS_PER_REV);
00112 NODELET_INFO_STREAM("number of packets to accumulate: " << config_.npackets);
00113
00114 data_->getParams();
00115
00116 if (0 != data_->setup())
00117 return;
00118
00119
00120 allocSharedMsg();
00121 packetCount_ = 0;
00122
00123
00124 allocPacketMsg(inMsg_);
00125 allocPacketMsg(tfMsg_);
00126
00127
00128 ros::NodeHandle node = getNodeHandle();
00129 output_ = node.advertise<sensor_msgs::PointCloud>("velodyne/pointcloud", 10);
00130
00131
00132 velodyne_scan_ =
00133 data_->subscribe(node, "velodyne/packets", 10,
00134 boost::bind(&TransformNodelet::processXYZ,
00135 this, _1, _2, _3),
00136 ros::TransportHints().tcpNoDelay(true));
00137 }
00138
00143 void TransformNodelet::allocPacketMsg(sensor_msgs::PointCloud &msg)
00144 {
00145 msg.points.reserve(SCANS_PER_PACKET);
00146 msg.channels.resize(NCHANNELS);
00147 for (unsigned ch = 0; ch < NCHANNELS; ++ch)
00148 {
00149 msg.channels[ch].name = channel_name[ch];
00150 msg.channels[ch].values.reserve(SCANS_PER_PACKET);
00151 }
00152 }
00153
00159 void TransformNodelet::allocSharedMsg()
00160 {
00161
00162 outPtr_ = sensor_msgs::PointCloudPtr(new sensor_msgs::PointCloud);
00163
00164
00165 outPtr_->points.reserve(config_.npackets*SCANS_PER_PACKET);
00166 outPtr_->channels.resize(NCHANNELS);
00167 for (unsigned ch = 0; ch < NCHANNELS; ++ch)
00168 {
00169 outPtr_->channels[ch].name = channel_name[ch];
00170 outPtr_->channels[ch].values.reserve(config_.npackets*SCANS_PER_PACKET);
00171 }
00172 }
00173
00181 void TransformNodelet::processXYZ(const std::vector<laserscan_xyz_t> &scan,
00182 ros::Time stamp,
00183 const std::string &frame_id)
00184 {
00185 if (output_.getNumSubscribers() == 0)
00186 return;
00187
00188
00189
00190 inMsg_.points.clear();
00191 tfMsg_.points.clear();
00192 for (unsigned ch = 0; ch < NCHANNELS; ++ch)
00193 {
00194 inMsg_.channels[ch].values.clear();
00195 tfMsg_.channels[ch].values.clear();
00196 }
00197
00198
00199 inMsg_.header.stamp = stamp;
00200 inMsg_.header.frame_id = frame_id;
00201 for (unsigned i = 0; i < scan.size(); ++i)
00202 {
00203 geometry_msgs::Point32 p;
00204 p.x = scan[i].x;
00205 p.y = scan[i].y;
00206 p.z = scan[i].z;
00207 if (pointInRange(p))
00208 {
00209 inMsg_.points.push_back(p);
00210 inMsg_.channels[0].values.push_back((float) scan[i].intensity);
00211 inMsg_.channels[1].values.push_back((float) velodyne::LASER_RING[scan[i].laser_number]);
00212 inMsg_.channels[2].values.push_back((float) scan[i].heading);
00213 }
00214 }
00215
00216
00217 try
00218 {
00219 NODELET_DEBUG_STREAM("transforming from" << inMsg_.header.frame_id
00220 << " to " << config_.frame_id);
00221 listener_.transformPointCloud(config_.frame_id, stamp,
00222 inMsg_, frame_id, tfMsg_);
00223 }
00224 catch (tf::TransformException ex)
00225 {
00226
00227 ROS_WARN_THROTTLE(20, "%s", ex.what());
00228 return;
00229 }
00230
00231
00232 outPtr_->points.insert(outPtr_->points.end(),
00233 tfMsg_.points.begin(),
00234 tfMsg_.points.end());
00235 for (unsigned ch = 0; ch < NCHANNELS; ++ch)
00236 {
00237 outPtr_->channels[ch].values.insert(outPtr_->channels[ch].values.end(),
00238 tfMsg_.channels[ch].values.begin(),
00239 tfMsg_.channels[ch].values.end());
00240 }
00241
00242 if (++packetCount_ >= config_.npackets)
00243 {
00244
00245 NODELET_DEBUG_STREAM("Publishing " << outPtr_->points.size()
00246 << " Velodyne points.");
00247
00248
00249 outPtr_->header.stamp = stamp;
00250 outPtr_->header.frame_id = config_.frame_id;
00251 output_.publish(outPtr_);
00252
00253
00254
00255 allocSharedMsg();
00256 packetCount_ = 0;
00257 }
00258 }
00259
00260
00261
00262
00263 PLUGINLIB_DECLARE_CLASS(velodyne_common, TransformNodelet,
00264 TransformNodelet, nodelet::Nodelet);