00001
00002
00003
00004
00005
00006
00007
00008
00015 #include <cmath>
00016
00017 #include <ros/ros.h>
00018 #include <pluginlib/class_list_macros.h>
00019 #include <nodelet/nodelet.h>
00020 #include <geometry_msgs/Point32.h>
00021 #include <sensor_msgs/PointCloud.h>
00022
00023 #include <velodyne/ring_sequence.h>
00024
00025 namespace ringcomp_nodelet
00026 {
00027 class RingCompNodelet: public nodelet::Nodelet
00028 {
00029 public:
00030
00031 RingCompNodelet() {}
00032 void onInit();
00033
00034 private:
00035
00036 void compInitialize();
00037 bool findChannels(const sensor_msgs::PointCloudPtr &scan);
00038 void printmatrix(geometry_msgs::Point32 mat[][velodyne::N_LASERS]);
00039 void processPointCloud(const sensor_msgs::PointCloudPtr &scan);
00040 int radtodeg(float rad);
00041 void ringMeasure(sensor_msgs::PointCloud &pc,
00042 geometry_msgs::Point32 vect[][velodyne::N_LASERS]);
00043
00045 inline void pushPoint(sensor_msgs::PointCloud &pc,
00046 const geometry_msgs::Point32 &pt)
00047 {
00048 pc.points.push_back(pt);
00049 }
00050
00052 inline float twodDistance(const geometry_msgs::Point32 &p1,
00053 const geometry_msgs::Point32 &p2)
00054 {
00055 float dx = p1.x - p2.x;
00056 float dy = p1.y - p2.y;
00057 return sqrt((dx*dx) + (dy*dy));
00058 }
00059
00060 ros::Subscriber velodyne_scan_;
00061 ros::Publisher output_;
00062
00063
00065 typedef struct {
00066 double min_obstacle;
00067 double vel_height;
00068 } Config;
00069 Config config_;
00070
00071 int ring_;
00072 int ringChan_;
00073 float heading_;
00074 int headingChan_;
00075 };
00076
00077 const int N_ANGLES = 360;
00078
00079
00080 const float LAZ_ANG[velodyne::N_LASERS] = {
00081 65.28896700,
00082 65.72367900,
00083 66.23703200,
00084 66.74982800,
00085 67.26211400,
00086 67.77392800,
00087 68.28531500,
00088 68.79631200,
00089 69.30696900,
00090 69.81731800,
00091 70.32740600,
00092 70.83727100,
00093 71.44216500,
00094 71.85649700,
00095 72.36593800,
00096 72.87531900,
00097 73.38468200,
00098 73.89406200,
00099 74.40350400,
00100 74.91304600,
00101 75.42272900,
00102 75.93259500,
00103 76.44268200,
00104 76.95303200,
00105 77.46368700,
00106 77.97468600,
00107 78.48607200,
00108 78.99788600,
00109 79.51017100,
00110 80.02296830,
00111 80.53632070,
00112 81.05027200,
00113 81.47918800,
00114 81.82011130,
00115 82.16085960,
00116 82.50144530,
00117 82.84188080,
00118 83.18217850,
00119 83.52234980,
00120 83.86240720,
00121 84.20236300,
00122 84.54222920,
00123 84.88201760,
00124 85.22174020,
00125 85.56140950,
00126 85.90103630,
00127 86.24063370,
00128 86.58021330,
00129 86.91978670,
00130 87.25936630,
00131 87.59896350,
00132 87.93859080,
00133 88.27825960,
00134 88.61798240,
00135 88.95777070,
00136 89.29763699,
00137 89.63759261,
00138 89.97765022,
00139 90.31782165,
00140 90.65811908,
00141 90.99855500,
00142 91.33914100,
00143 91.67988900,
00144 92.02081230
00145 };
00146
00147
00148 const float FLAT_COMP[velodyne::N_LASERS-1] = {
00149 0.09711589596,
00150 0.11897830436,
00151 0.12378418455,
00152 0.12892017590,
00153 0.13441452666,
00154 0.14030307990,
00155 0.14662184047,
00156 0.15341750055,
00157 0.16073317108,
00158 0.16862812847,
00159 0.17716167015,
00160 0.22232028841,
00161 0.16052564727,
00162 0.20735797309,
00163 0.21926581262,
00164 0.23228723239,
00165 0.24656171665,
00166 0.26226037120,
00167 0.27957481708,
00168 0.29873614251,
00169 0.32001696732,
00170 0.34373865361,
00171 0.37029194867,
00172 0.40014576254,
00173 0.43386762661,
00174 0.47215933933,
00175 0.51588306306,
00176 0.56611903612,
00177 0.62422533335,
00178 0.69193812767,
00179 0.77149948941,
00180 0.71448352613,
00181 0.62093965520,
00182 0.67420617492,
00183 0.73471590764,
00184 0.80384430580,
00185 0.88330959147,
00186 0.97527762014,
00187 1.08251992717,
00188 1.20861618705,
00189 1.35825959140,
00190 1.53770104317,
00191 1.75541534995,
00192 2.02312275695,
00193 2.35738526852,
00194 2.78227842586,
00195 3.33380543850,
00196 4.06783875008,
00197 5.07489914418,
00198 6.50953337943,
00199 8.65372736099,
00200 12.06773066628,
00201 18.00087834321,
00202 29.73996140445,
00203 58.52760804860,
00204 168.35270037068,
00205 5292.09791678684,
00206 -6036.51251234878,
00207 205.08091492193,
00208 65.30300971227,
00209 32.10944334797,
00210 19.09725472764,
00211 12.66324881604};
00212
00213
00214
00215 float COMP_BASE[velodyne::N_LASERS-1];
00216 float CASE_1_RANGES[velodyne::N_LASERS];
00217
00218 int CASE_1_LIM;
00219 int CASE_3_LIM = 58;
00220
00222 void RingCompNodelet::onInit()
00223 {
00224 ros::NodeHandle private_nh = getPrivateNodeHandle();
00225 private_nh.param("min_obstacle", config_.min_obstacle, 0.15);
00226 NODELET_INFO_STREAM("minimum obstacle height: " << config_.min_obstacle);
00227
00230 private_nh.param("vel_height", config_.vel_height, 2.4);
00231 NODELET_INFO_STREAM("height of Velodyne above ground: " << config_.vel_height);
00232
00233
00234
00235
00236 ros::NodeHandle node = getNodeHandle();
00237 velodyne_scan_ = node.subscribe("velodyne/pointcloud", 1,
00238 &RingCompNodelet::processPointCloud, this,
00239 ros::TransportHints().tcpNoDelay(true));
00240
00241 output_ = node.advertise<sensor_msgs::PointCloud>("velodyne/obstacles", 10);
00242
00243 compInitialize();
00244 }
00245
00247 void RingCompNodelet::compInitialize()
00248 {
00249
00250 int i;
00251 for (i = 0; i < velodyne::N_LASERS; i++){
00252 COMP_BASE[i] =
00253 (FLAT_COMP[i]
00254 - (config_.min_obstacle * tan(LAZ_ANG[i+1] * (M_PI/180))));
00255 }
00256
00257 i = 0;
00258 while(COMP_BASE[i] < 0 && i < velodyne::N_LASERS){
00259 i++;
00260 }
00261 CASE_1_LIM = i;
00262
00263 i = 0;
00264 float tang;
00265 while (i < CASE_1_LIM){
00266 tang = tan(LAZ_ANG[i+1] * (M_PI/180));
00267 CASE_1_RANGES[i] = tang * (config_.vel_height - config_.min_obstacle);
00268 i++;
00269 }
00270 }
00271
00273 int RingCompNodelet::radtodeg(float rad)
00274 {
00275
00276 rad = rad * (180 / M_PI);
00277
00278
00279 if ( rad > 0 )
00280 rad = rad + 0.5;
00281 if ( rad < 0 )
00282 rad = rad - 0.5;
00283
00284
00285 int deg = static_cast<int>(rad);
00286
00287
00288 if (deg < 0)
00289 deg = deg + N_ANGLES;
00290
00291 return deg;
00292 }
00293
00294 void RingCompNodelet::ringMeasure(sensor_msgs::PointCloud &pc,
00295 geometry_msgs::Point32 vect[][velodyne::N_LASERS])
00296 {
00297 for(int i = 0; i < N_ANGLES; i++)
00298 {
00299 for(int j = 0; j < CASE_3_LIM; j++)
00300 {
00301 if( j < CASE_1_LIM)
00302 {
00303 if( twodDistance(vect[i][j], vect[i][j+1]) < .03)
00304 {
00305 if (vect[i][j+1].x < CASE_1_RANGES[j])
00306 {
00307 pushPoint(pc, vect[i][j+1]);
00308 }
00309 }
00310 }
00311 else if(twodDistance(vect[i][j], vect[i][j+1]) < COMP_BASE[j])
00312 {
00313 pushPoint(pc, vect[i][j+1]);
00314 }
00315 }
00316 }
00317 }
00318
00319 void RingCompNodelet::printmatrix(geometry_msgs::Point32 mat[][velodyne::N_LASERS])
00320 {
00321 for(int i = 0; i < N_ANGLES; i++)
00322 {
00323 for(int j = 0; j < velodyne::N_LASERS; j++)
00324 {
00325 std::cout << mat[i][j].x << " " << mat[i][j].y << " " << mat[i][j].z << '\n';
00326 }
00327 }
00328 }
00329
00335 bool RingCompNodelet::findChannels(const sensor_msgs::PointCloudPtr &scan)
00336 {
00337 ringChan_ = -1;
00338 headingChan_ = -1;
00339
00340
00341 for (unsigned ch = 0; ch < scan->channels.size(); ++ch)
00342 {
00343 if (scan->channels[ch].name == "ring")
00344 ringChan_ = ch;
00345 else if (scan->channels[ch].name == "heading")
00346 headingChan_ = ch;
00347 }
00348
00349
00350 return (ringChan_ >= 0 && headingChan_ >= 0);
00351 }
00352
00354 void RingCompNodelet::processPointCloud(const sensor_msgs::PointCloudPtr &scan)
00355 {
00356 if (output_.getNumSubscribers() == 0)
00357 return;
00358
00359 if (!findChannels(scan))
00360 {
00361 ROS_ERROR_THROTTLE(10, "ring compression requires heading and ring channels");
00362 return;
00363 }
00364
00365
00366 sensor_msgs::PointCloudPtr outPtr(new sensor_msgs::PointCloud);
00367 outPtr->header.stamp = scan->header.stamp;
00368 outPtr->header.frame_id = scan->header.frame_id;
00369
00370
00371 geometry_msgs::Point32 data_mat[N_ANGLES][velodyne::N_LASERS];
00372
00373
00374 for (unsigned i = 0; i < scan->points.size(); ++i)
00375 {
00376
00377 geometry_msgs::Point32 pt = scan->points[i];
00378 ring_ = (int) rint(scan->channels[ringChan_].values[i]);
00379 heading_ = scan->channels[headingChan_].values[i];
00380 data_mat[radtodeg(heading_)][ring_] = pt;
00381 }
00382
00383
00384 ringMeasure(*outPtr, data_mat);
00385
00386
00387 output_.publish(outPtr);
00388 }
00389
00390
00391
00392
00393 PLUGINLIB_DECLARE_CLASS(velodyne_ringcomp, RingCompNodelet,
00394 ringcomp_nodelet::RingCompNodelet,
00395 nodelet::Nodelet);
00396
00397 };