Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00028 #include <fstream>
00029 #include <math.h>
00030
00031 #include <ros/ros.h>
00032 #include <ros/package.h>
00033 #include <angles/angles.h>
00034
00035 #include <velodyne_pointcloud/rawdata.h>
00036
00037 namespace velodyne_rawdata
00038 {
00040
00041
00042
00044
00045 RawData::RawData() {}
00046
00048 void RawData::setParameters(double min_range,
00049 double max_range,
00050 double view_direction,
00051 double view_width)
00052 {
00053 config_.min_range = min_range;
00054 config_.max_range = max_range;
00055
00056
00057 config_.tmp_min_angle = view_direction + view_width/2;
00058 config_.tmp_max_angle = view_direction - view_width/2;
00059
00060
00061 config_.tmp_min_angle = fmod(fmod(config_.tmp_min_angle,2*M_PI) + 2*M_PI,2*M_PI);
00062 config_.tmp_max_angle = fmod(fmod(config_.tmp_max_angle,2*M_PI) + 2*M_PI,2*M_PI);
00063
00064
00065
00066 config_.min_angle = 100 * (2*M_PI - config_.tmp_min_angle) * 180 / M_PI + 0.5;
00067 config_.max_angle = 100 * (2*M_PI - config_.tmp_max_angle) * 180 / M_PI + 0.5;
00068 if (config_.min_angle == config_.max_angle)
00069 {
00070
00071 config_.min_angle = 0;
00072 config_.max_angle = 36000;
00073 }
00074 }
00075
00077 int RawData::setup(ros::NodeHandle private_nh)
00078 {
00079
00080 if (!private_nh.getParam("calibration", config_.calibrationFile))
00081 {
00082 ROS_ERROR_STREAM("No calibration angles specified! Using test values!");
00083
00084
00085 std::string pkgPath = ros::package::getPath("velodyne_pointcloud");
00086 config_.calibrationFile = pkgPath + "/params/64e_utexas.yaml";
00087 }
00088
00089 ROS_INFO_STREAM("correction angles: " << config_.calibrationFile);
00090
00091 calibration_.read(config_.calibrationFile);
00092 if (!calibration_.initialized) {
00093 ROS_ERROR_STREAM("Unable to open calibration file: " <<
00094 config_.calibrationFile);
00095 return -1;
00096 }
00097
00098 ROS_INFO_STREAM("Data will be processed as a VLP-16...num_lasers: " << calibration_.num_lasers);
00099
00100
00101 for (uint16_t rot_index = 0; rot_index < ROTATION_MAX_UNITS; ++rot_index) {
00102 float rotation = angles::from_degrees(ROTATION_RESOLUTION * rot_index);
00103 cos_rot_table_[rot_index] = cosf(rotation);
00104 sin_rot_table_[rot_index] = sinf(rotation);
00105 }
00106 return 0;
00107 }
00108
00114 void RawData::unpack(const velodyne_msgs::VelodynePacket &pkt,
00115 VPointCloud &pc)
00116 {
00117 ROS_DEBUG_STREAM("Received packet, time: " << pkt.stamp);
00118
00120 if (calibration_.num_lasers == 16)
00121 {
00122 unpack_vlp16(pkt, pc);
00123 return;
00124 }
00125
00126 const raw_packet_t *raw = (const raw_packet_t *) &pkt.data[0];
00127
00128 for (int i = 0; i < BLOCKS_PER_PACKET; i++) {
00129
00130
00131
00132 int bank_origin = 0;
00133 if (raw->blocks[i].header == LOWER_BANK) {
00134
00135 bank_origin = 32;
00136 }
00137
00138 for (int j = 0, k = 0; j < SCANS_PER_BLOCK; j++, k += RAW_SCAN_SIZE) {
00139
00140 float x, y, z;
00141 float intensity;
00142 uint8_t laser_number;
00143
00144 laser_number = j + bank_origin;
00145 velodyne_pointcloud::LaserCorrection &corrections =
00146 calibration_.laser_corrections[laser_number];
00147
00150 union two_bytes tmp;
00151 tmp.bytes[0] = raw->blocks[i].data[k];
00152 tmp.bytes[1] = raw->blocks[i].data[k+1];
00153
00154
00155 if ((raw->blocks[i].rotation >= config_.min_angle
00156 && raw->blocks[i].rotation <= config_.max_angle
00157 && config_.min_angle < config_.max_angle)
00158 ||(config_.min_angle > config_.max_angle
00159 && (raw->blocks[i].rotation <= config_.max_angle
00160 || raw->blocks[i].rotation >= config_.min_angle))){
00161 float distance = tmp.uint * DISTANCE_RESOLUTION;
00162 distance += corrections.dist_correction;
00163
00164 float cos_vert_angle = corrections.cos_vert_correction;
00165 float sin_vert_angle = corrections.sin_vert_correction;
00166 float cos_rot_correction = corrections.cos_rot_correction;
00167 float sin_rot_correction = corrections.sin_rot_correction;
00168
00169
00170
00171 float cos_rot_angle =
00172 cos_rot_table_[raw->blocks[i].rotation] * cos_rot_correction +
00173 sin_rot_table_[raw->blocks[i].rotation] * sin_rot_correction;
00174 float sin_rot_angle =
00175 sin_rot_table_[raw->blocks[i].rotation] * cos_rot_correction -
00176 cos_rot_table_[raw->blocks[i].rotation] * sin_rot_correction;
00177
00178 float horiz_offset = corrections.horiz_offset_correction;
00179 float vert_offset = corrections.vert_offset_correction;
00180
00181
00186 float xy_distance = distance * cos_vert_angle + vert_offset * sin_vert_angle;
00187
00188
00189 float xx = xy_distance * sin_rot_angle - horiz_offset * cos_rot_angle;
00190
00191 float yy = xy_distance * cos_rot_angle + horiz_offset * sin_rot_angle;
00192 if (xx < 0) xx=-xx;
00193 if (yy < 0) yy=-yy;
00194
00195
00196
00197
00198 float distance_corr_x = 0;
00199 float distance_corr_y = 0;
00200 if (corrections.two_pt_correction_available) {
00201 distance_corr_x =
00202 (corrections.dist_correction - corrections.dist_correction_x)
00203 * (xx - 2.4) / (25.04 - 2.4)
00204 + corrections.dist_correction_x;
00205 distance_corr_x -= corrections.dist_correction;
00206 distance_corr_y =
00207 (corrections.dist_correction - corrections.dist_correction_y)
00208 * (yy - 1.93) / (25.04 - 1.93)
00209 + corrections.dist_correction_y;
00210 distance_corr_y -= corrections.dist_correction;
00211 }
00212
00213 float distance_x = distance + distance_corr_x;
00218 xy_distance = distance_x * cos_vert_angle + vert_offset * sin_vert_angle ;
00220 x = xy_distance * sin_rot_angle - horiz_offset * cos_rot_angle;
00221
00222 float distance_y = distance + distance_corr_y;
00223 xy_distance = distance_y * cos_vert_angle + vert_offset * sin_vert_angle ;
00228 y = xy_distance * cos_rot_angle + horiz_offset * sin_rot_angle;
00229
00230
00231
00236 z = distance_y * sin_vert_angle + vert_offset*cos_vert_angle;
00237
00239 float x_coord = y;
00240 float y_coord = -x;
00241 float z_coord = z;
00242
00245 float min_intensity = corrections.min_intensity;
00246 float max_intensity = corrections.max_intensity;
00247
00248 intensity = raw->blocks[i].data[k+2];
00249
00250 float focal_offset = 256
00251 * (1 - corrections.focal_distance / 13100)
00252 * (1 - corrections.focal_distance / 13100);
00253 float focal_slope = corrections.focal_slope;
00254 intensity += focal_slope * (abs(focal_offset - 256 *
00255 (1 - static_cast<float>(tmp.uint)/65535)*(1 - static_cast<float>(tmp.uint)/65535)));
00256 intensity = (intensity < min_intensity) ? min_intensity : intensity;
00257 intensity = (intensity > max_intensity) ? max_intensity : intensity;
00258
00259 if (pointInRange(distance)) {
00260
00261
00262 VPoint point;
00263 point.ring = corrections.laser_ring;
00264 point.x = x_coord;
00265 point.y = y_coord;
00266 point.z = z_coord;
00267 point.intensity = (uint8_t) intensity;
00268
00269
00270 pc.points.push_back(point);
00271 ++pc.width;
00272 }
00273 }
00274 }
00275 }
00276 }
00277
00283 void RawData::unpack_vlp16(const velodyne_msgs::VelodynePacket &pkt,
00284 VPointCloud &pc)
00285 {
00286 float azimuth;
00287 float azimuth_diff;
00288 float last_azimuth_diff;
00289 float azimuth_corrected_f;
00290 int azimuth_corrected;
00291 float x, y, z;
00292 float intensity;
00293 uint8_t dsr;
00294
00295 const raw_packet_t *raw = (const raw_packet_t *) &pkt.data[0];
00296
00297 for (int block = 0; block < BLOCKS_PER_PACKET; block++) {
00298 assert(0xEEFF == raw->blocks[block].header);
00299 azimuth = (float)(raw->blocks[block].rotation);
00300 if (block < (BLOCKS_PER_PACKET-1)){
00301 azimuth_diff = (float)((36000 + raw->blocks[block+1].rotation - raw->blocks[block].rotation)%36000);
00302 last_azimuth_diff = azimuth_diff;
00303 }else{
00304 azimuth_diff = last_azimuth_diff;
00305 }
00306
00307 for (int firing=0, k=0; firing < VLP16_FIRINGS_PER_BLOCK; firing++){
00308 for (int dsr=0; dsr < VLP16_SCANS_PER_FIRING; dsr++, k+=RAW_SCAN_SIZE){
00309 velodyne_pointcloud::LaserCorrection &corrections =
00310 calibration_.laser_corrections[dsr];
00311
00313 union two_bytes tmp;
00314 tmp.bytes[0] = raw->blocks[block].data[k];
00315 tmp.bytes[1] = raw->blocks[block].data[k+1];
00316
00318 azimuth_corrected_f = azimuth + (azimuth_diff * ((dsr*VLP16_DSR_TOFFSET) + (firing*VLP16_FIRING_TOFFSET)) / VLP16_BLOCK_TDURATION);
00319 azimuth_corrected = ((int)round(azimuth_corrected_f)) % 36000;
00320
00321
00322
00323 if ((azimuth_corrected >= config_.min_angle
00324 && azimuth_corrected <= config_.max_angle
00325 && config_.min_angle < config_.max_angle)
00326 ||(config_.min_angle > config_.max_angle
00327 && (azimuth_corrected <= config_.max_angle
00328 || azimuth_corrected >= config_.min_angle))){
00329 float distance = tmp.uint * DISTANCE_RESOLUTION;
00330 distance += corrections.dist_correction;
00331
00332 float cos_vert_angle = corrections.cos_vert_correction;
00333 float sin_vert_angle = corrections.sin_vert_correction;
00334 float cos_rot_correction = corrections.cos_rot_correction;
00335 float sin_rot_correction = corrections.sin_rot_correction;
00336
00337
00338
00339 float cos_rot_angle =
00340 cos_rot_table_[azimuth_corrected] * cos_rot_correction +
00341 sin_rot_table_[azimuth_corrected] * sin_rot_correction;
00342 float sin_rot_angle =
00343 sin_rot_table_[azimuth_corrected] * cos_rot_correction -
00344 cos_rot_table_[azimuth_corrected] * sin_rot_correction;
00345
00346 float horiz_offset = corrections.horiz_offset_correction;
00347 float vert_offset = corrections.vert_offset_correction;
00348
00349
00354 float xy_distance = distance * cos_vert_angle + vert_offset * sin_vert_angle;
00355
00356
00357 float xx = xy_distance * sin_rot_angle - horiz_offset * cos_rot_angle;
00358
00359 float yy = xy_distance * cos_rot_angle + horiz_offset * sin_rot_angle;
00360 if (xx < 0) xx=-xx;
00361 if (yy < 0) yy=-yy;
00362
00363
00364
00365
00366 float distance_corr_x = 0;
00367 float distance_corr_y = 0;
00368 if (corrections.two_pt_correction_available) {
00369 distance_corr_x =
00370 (corrections.dist_correction - corrections.dist_correction_x)
00371 * (xx - 2.4) / (25.04 - 2.4)
00372 + corrections.dist_correction_x;
00373 distance_corr_x -= corrections.dist_correction;
00374 distance_corr_y =
00375 (corrections.dist_correction - corrections.dist_correction_y)
00376 * (yy - 1.93) / (25.04 - 1.93)
00377 + corrections.dist_correction_y;
00378 distance_corr_y -= corrections.dist_correction;
00379 }
00380
00381 float distance_x = distance + distance_corr_x;
00386 xy_distance = distance_x * cos_vert_angle + vert_offset * sin_vert_angle ;
00387 x = xy_distance * sin_rot_angle - horiz_offset * cos_rot_angle;
00388
00389 float distance_y = distance + distance_corr_y;
00394 xy_distance = distance_y * cos_vert_angle + vert_offset * sin_vert_angle ;
00395 y = xy_distance * cos_rot_angle + horiz_offset * sin_rot_angle;
00396
00397
00398
00403 z = distance_y * sin_vert_angle + vert_offset*cos_vert_angle;
00404
00405
00407 float x_coord = y;
00408 float y_coord = -x;
00409 float z_coord = z;
00410
00413 float min_intensity = corrections.min_intensity;
00414 float max_intensity = corrections.max_intensity;
00415
00416 intensity = raw->blocks[block].data[k+2];
00417
00418 float focal_offset = 256
00419 * (1 - corrections.focal_distance / 13100)
00420 * (1 - corrections.focal_distance / 13100);
00421 float focal_slope = corrections.focal_slope;
00422 intensity += focal_slope * (abs(focal_offset - 256 *
00423 (1 - tmp.uint/65535)*(1 - tmp.uint/65535)));
00424 intensity = (intensity < min_intensity) ? min_intensity : intensity;
00425 intensity = (intensity > max_intensity) ? max_intensity : intensity;
00426
00427 if (pointInRange(distance)) {
00428
00429
00430 VPoint point;
00431 point.ring = corrections.laser_ring;
00432 point.x = x_coord;
00433 point.y = y_coord;
00434 point.z = z_coord;
00435 point.intensity = (uint8_t) intensity;
00436
00437
00438 pc.points.push_back(point);
00439 ++pc.width;
00440 }
00441 }
00442 }
00443 }
00444 }
00445 }
00446
00447 }