00001
00002
00003
00004
00005
00006
00007
00008
00009
00017 #include <cmath>
00018 #include <fstream>
00019 #include <iostream>
00020 #include <map>
00021
00022 #include <ros/ros.h>
00023 #include <sensor_msgs/PointCloud.h>
00024
00025 #include <velodyne/data.h>
00026
00027 #define NODE "ringcomp"
00028
00029 using namespace velodyne_common;
00030
00031 static int qDepth = 1;
00032
00033
00034 static velodyne::DataXYZ *data = NULL;
00035 static ros::Publisher output;
00036
00037
00038 velodyne::laserscan_xyz_t data_mat[360][64];
00039
00040
00041 bool first_run = true;
00042
00043
00044 std::map<int, int> MAP_ORDER;
00045
00046
00047 const int VEL_HEIGHT = 2.2;
00048
00049
00050 float MIN_OBST = .15;
00051
00052 const int TEMP_LAZ_ORDER[64] = {6,7,10,11,0,1,4,5,8,9,14,15,18,19,22,
00053 23,12,13,16,17,20,21,26,27,30,31,2,3,
00054 24,25,28,29,38,39,42,43,32,33,36,37,40,
00055 41,46,47,50,51,54,55,44,45,48,49,52,53,
00056 58,59,62,63,34,35,56,57,60,61};
00057
00058
00059 const float LAZ_ANG[64] = {
00060 65.28896700,
00061 65.72367900,
00062 66.23703200,
00063 66.74982800,
00064 67.26211400,
00065 67.77392800,
00066 68.28531500,
00067 68.79631200,
00068 69.30696900,
00069 69.81731800,
00070 70.32740600,
00071 70.83727100,
00072 71.44216500,
00073 71.85649700,
00074 72.36593800,
00075 72.87531900,
00076 73.38468200,
00077 73.89406200,
00078 74.40350400,
00079 74.91304600,
00080 75.42272900,
00081 75.93259500,
00082 76.44268200,
00083 76.95303200,
00084 77.46368700,
00085 77.97468600,
00086 78.48607200,
00087 78.99788600,
00088 79.51017100,
00089 80.02296830,
00090 80.53632070,
00091 81.05027200,
00092 81.47918800,
00093 81.82011130,
00094 82.16085960,
00095 82.50144530,
00096 82.84188080,
00097 83.18217850,
00098 83.52234980,
00099 83.86240720,
00100 84.20236300,
00101 84.54222920,
00102 84.88201760,
00103 85.22174020,
00104 85.56140950,
00105 85.90103630,
00106 86.24063370,
00107 86.58021330,
00108 86.91978670,
00109 87.25936630,
00110 87.59896350,
00111 87.93859080,
00112 88.27825960,
00113 88.61798240,
00114 88.95777070,
00115 89.29763699,
00116 89.63759261,
00117 89.97765022,
00118 90.31782165,
00119 90.65811908,
00120 90.99855500,
00121 91.33914100,
00122 91.67988900,
00123 92.02081230};
00124
00125
00126 const float FLAT_COMP[63] = {
00127 0.09711589596,
00128 0.11897830436,
00129 0.12378418455,
00130 0.12892017590,
00131 0.13441452666,
00132 0.14030307990,
00133 0.14662184047,
00134 0.15341750055,
00135 0.16073317108,
00136 0.16862812847,
00137 0.17716167015,
00138 0.22232028841,
00139 0.16052564727,
00140 0.20735797309,
00141 0.21926581262,
00142 0.23228723239,
00143 0.24656171665,
00144 0.26226037120,
00145 0.27957481708,
00146 0.29873614251,
00147 0.32001696732,
00148 0.34373865361,
00149 0.37029194867,
00150 0.40014576254,
00151 0.43386762661,
00152 0.47215933933,
00153 0.51588306306,
00154 0.56611903612,
00155 0.62422533335,
00156 0.69193812767,
00157 0.77149948941,
00158 0.71448352613,
00159 0.62093965520,
00160 0.67420617492,
00161 0.73471590764,
00162 0.80384430580,
00163 0.88330959147,
00164 0.97527762014,
00165 1.08251992717,
00166 1.20861618705,
00167 1.35825959140,
00168 1.53770104317,
00169 1.75541534995,
00170 2.02312275695,
00171 2.35738526852,
00172 2.78227842586,
00173 3.33380543850,
00174 4.06783875008,
00175 5.07489914418,
00176 6.50953337943,
00177 8.65372736099,
00178 12.06773066628,
00179 18.00087834321,
00180 29.73996140445,
00181 58.52760804860,
00182 168.35270037068,
00183 5292.09791678684,
00184 -6036.51251234878,
00185 205.08091492193,
00186 65.30300971227,
00187 32.10944334797,
00188 19.09725472764,
00189 12.66324881604};
00190
00191
00192
00193 float COMP_BASE[63];
00194
00195 float CASE_1_RANGES[64];
00196 const int NUM_LAZERS = 64;
00197
00198 int CASE_1_LIM;
00199 int CASE_3_LIM = 58;
00200
00201
00202
00203 float twodDistance(velodyne::laserscan_xyz_t p1, velodyne::laserscan_xyz_t p2){
00204
00205 float result;
00206 float dx;
00207 float dy;
00208
00209 dx = p1.x - p2.x;
00210 dy = p1.y - p2.y;
00211
00212 result = sqrt( (dx*dx) + (dy*dy));
00213
00214 return result;
00215 }
00216
00217 void mapInitialize(){
00218
00219 for (int i = 0; i < NUM_LAZERS; i++){
00220 MAP_ORDER[ TEMP_LAZ_ORDER[i] ] = i;
00221 }
00222
00223 }
00224
00225
00226 void compInitialize(){
00227
00228 int i;
00229 for (i = 0; i < 64; i++){
00230 COMP_BASE[i] = FLAT_COMP[i] - (MIN_OBST * tan(LAZ_ANG[i+1] * (M_PI/180)));
00231 }
00232
00233
00234 i = 0;
00235 while(COMP_BASE[i] < 0 && i < 64){
00236 i++;
00237 }
00238 CASE_1_LIM = i;
00239
00240 i = 0;
00241 float tang;
00242 while (i < CASE_1_LIM){
00243 tang = tan(LAZ_ANG[i+1] * (M_PI/180));
00244 CASE_1_RANGES[i] = tang * (VEL_HEIGHT - MIN_OBST);
00245 i++;
00246 }
00247
00248 }
00249
00250
00251 int radtodeg(float rad){
00252
00253
00254 rad = rad * (180 / M_PI);
00255
00256
00257 if ( rad > 0 )
00258 rad = rad + 0.5;
00259 if ( rad < 0 )
00260 rad = rad - 0.5;
00261
00262
00263 int deg = static_cast<int>(rad);
00264
00265
00266 if (deg < 0)
00267 deg = deg + 360;
00268
00269 return deg;
00270
00271 }
00272
00273 sensor_msgs::PointCloud pc;
00274
00275 void ringMeasure(velodyne::laserscan_xyz_t vect[][64]){
00276 int pcindex = 0;
00277 #define DEBUG_TO_FILE 0
00278 #if DEBUG_TO_FILE
00279 std::ofstream fout;
00280 fout.open("velodyne_ringcomp_output.txt");
00281 #endif
00282 velodyne::laserscan_xyz_t p;
00283 pc.points.resize(100000);
00284 for(int i = 0; i < 360; i++){
00285 for(int j = 0; j < CASE_3_LIM; j++){
00286 if( j < CASE_1_LIM){
00287 if( twodDistance(vect[i][j], vect[i][j+1]) < .03){
00288 if (vect[i][j+1].x < CASE_1_RANGES[j]){
00289 p = vect[i][j+1];
00290 pc.points[pcindex].x = p.x;
00291 pc.points[pcindex].y = p.y;
00292 pc.points[pcindex].z = p.z;
00293 ++pcindex;
00294 #if DEBUG_TO_FILE
00295 fout << p.x << ',' << p.y << ',' << p.z << ',';
00296 fout << 255 << ',' << 0 << ',' << 0;
00297 fout << '\n';
00298 #endif
00299 }
00300 }
00301 }
00302 else{
00303 if(twodDistance(vect[i][j], vect[i][j+1]) < COMP_BASE[j]){
00304 p = vect[i][j+1];
00305 pc.points[pcindex].x = p.x;
00306 pc.points[pcindex].y = p.y;
00307 pc.points[pcindex].z = p.z;
00308 ++pcindex;
00309 #if DEBUG_TO_FILE
00310 fout << p.x << ',' << p.y << ',' << p.z << ',';
00311 fout << 255 << ',' << 0 << ',' << 0;
00312 fout << '\n';
00313 #endif
00314 }
00315 }
00316 }
00317 }
00318 pc.points.resize(pcindex);
00319 output.publish(pc);
00320
00321 }
00322
00323 void printmatrix(velodyne::laserscan_xyz_t mat[][64]){
00324
00325 for(int i = 0; i < 360; i++){
00326 for(int j = 0; j < 64; j++){
00327 std::cout << mat[i][j].x << " " << mat[i][j].y << " " << mat[i][j].z << '\n';
00328 }
00329 }
00330
00331 }
00337 void processXYZ(const std::vector<velodyne::laserscan_xyz_t> &scan)
00338 {
00339
00340 data->getMsgHeaderFields(pc.header.stamp, pc.header.frame_id);
00341
00342 if (first_run)
00343 {
00344 compInitialize();
00345 mapInitialize();
00346 first_run = false;
00347 }
00348
00349
00350 velodyne::laserscan_xyz_t p;
00351 for (unsigned i = 0; i < scan.size(); ++i)
00352 {
00353
00354 p = scan[i];
00355 data_mat[radtodeg(p.heading)][ MAP_ORDER[p.laser_number] ] = p;
00356
00357
00358 }
00359 ringMeasure(data_mat);
00360 }
00361
00362 void displayHelp()
00363 {
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 }
00377
00378
00383 int getParameters(int argc, char *argv[])
00384 {
00385
00386 char ch;
00387 const char* optflags = "hq:?";
00388 while(-1 != (ch = getopt(argc, argv, optflags)))
00389 {
00390 switch(ch)
00391 {
00392 case 'q':
00393 qDepth = atoi(optarg);
00394 if (qDepth < 1)
00395 qDepth = 1;
00396 break;
00397 default:
00398 ROS_WARN("unknown parameter: %c", ch);
00399
00400 case 'h':
00401 case '?':
00402 displayHelp();
00403 return 1;
00404 }
00405 }
00406
00407 ROS_INFO("topic queue depth = %d", qDepth);
00408
00409 data = new velodyne::DataXYZ();
00410 data->getParams();
00411 data->subscribeXYZ(processXYZ);
00412
00413 return 0;
00414 }
00415
00416 int main(int argc, char *argv[])
00417 {
00418 ros::init(argc, argv, NODE);
00419 ros::NodeHandle node;
00420
00421 if (0 != getParameters(argc, argv))
00422 return 9;
00423
00424 if (0 != data->setup())
00425 return 2;
00426
00427
00428
00429
00430 ros::Subscriber velodyne_scan =
00431 node.subscribe("velodyne/rawscan", qDepth,
00432 &velodyne::Data::processRawScan, (velodyne::Data *) data,
00433 ros::TransportHints().tcpNoDelay(true));
00434
00435 output = node.advertise<sensor_msgs::PointCloud>("velodyne/obstacles",
00436 qDepth);
00437
00438 ros::spin();
00439
00440 data->shutdown();
00441 delete data;
00442 return 0;
00443 }