Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <algorithm>
00032 #include <assert.h>
00033 #include <boost/thread/thread.hpp>
00034 #include <boost/bind.hpp>
00035
00036 #include "sensor_msgs/fill_image.h"
00037 #include "image_transport/image_transport.h"
00038
00039 #include <gazebo_plugins/gazebo_ros_gpu_laser.h>
00040
00041 #include "sensors/Sensor.hh"
00042 #include "sensors/GpuRaySensor.hh"
00043 #include "sdf/interface/SDF.hh"
00044 #include "sensors/SensorTypes.hh"
00045
00046 #include "tf/tf.h"
00047
00048 #include <iostream>
00049 #include <fstream>
00050
00051 namespace gazebo
00052 {
00053
00055
00056 GazeboRosGpuLaser::GazeboRosGpuLaser()
00057 {
00058 this->laser_connect_count_ = 0;
00059 }
00060
00062
00063 GazeboRosGpuLaser::~GazeboRosGpuLaser()
00064 {
00065 this->parentSensor->SetActive(false);
00066 this->rosnode_->shutdown();
00067 this->queue_.clear();
00068 this->queue_.disable();
00069 this->callback_queue_thread_.join();
00070
00071 delete this->rosnode_;
00072 }
00073
00075
00076 void GazeboRosGpuLaser::Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
00077 {
00078 GpuRayPlugin::Load(_parent, _sdf);
00079
00080
00081 this->robot_namespace_ = "";
00082 if (_sdf->HasElement("robotNamespace"))
00083 this->robot_namespace_ = _sdf->GetElement("robotNamespace")->GetValueString() + "/";
00084
00085
00086 if (!_sdf->GetElement("topicName"))
00087 this->laser_topic_name_ = "scan";
00088 else
00089 this->laser_topic_name_ = _sdf->GetElement("topicName")->GetValueString();
00090
00091 if (!_sdf->GetElement("pointCloudCutoff"))
00092 this->point_cloud_cutoff_ = 0.4;
00093 else
00094 this->point_cloud_cutoff_ = _sdf->GetElement("pointCloudCutoff")->GetValueDouble();
00095
00096 this->frame_name_ = "/world";
00097 if (_sdf->HasElement("frameName"))
00098 this->frame_name_ = _sdf->GetElement("frameName")->GetValueString();
00099
00100 if (!_sdf->HasElement("gaussianNoise"))
00101 {
00102 ROS_INFO("Block laser plugin missing <gaussianNoise>, defaults to 0.0");
00103 this->gaussian_noise_ = 0;
00104 }
00105 else
00106 this->gaussian_noise_ = _sdf->GetElement("gaussianNoise")->GetValueDouble();
00107
00108 if (!_sdf->HasElement("hokuyoMinIntensity"))
00109 {
00110 ROS_INFO("Block laser plugin missing <hokuyoMinIntensity>, defaults to 101");
00111 this->hokuyo_min_intensity_ = 101;
00112 }
00113 else
00114 this->hokuyo_min_intensity_ = _sdf->GetElement("hokuyoMinIntensity")->GetValueDouble();
00115
00116 ROS_INFO("INFO: gazebo_ros_laser plugin should set minimum intensity to %f due to cutoff in hokuyo filters." , this->hokuyo_min_intensity_);
00117
00118 if (!_sdf->GetElement("updateRate"))
00119 {
00120 ROS_INFO("Camera plugin missing <updateRate>, defaults to 0");
00121 this->update_rate_ = 0;
00122 }
00123 else
00124 this->update_rate_ = _sdf->GetElement("updateRate")->GetValueDouble();
00125
00126
00127
00128 if (!ros::isInitialized())
00129 {
00130 int argc = 0;
00131 char** argv = NULL;
00132 ros::init( argc, argv, "gazebo",
00133 ros::init_options::NoSigintHandler |
00134 ros::init_options::AnonymousName );
00135 }
00136
00137 this->rosnode_ = new ros::NodeHandle(this->robot_namespace_);
00138
00139
00140 std::string prefix;
00141 this->rosnode_->getParam(std::string("tf_prefix"), prefix);
00142 this->frame_name_ = tf::resolve(prefix, this->frame_name_);
00143
00144 ros::AdvertiseOptions laser_scan_ao;
00145
00146 if (this->parentSensor->GetVerticalRangeCount() != 1)
00147 laser_scan_ao = ros::AdvertiseOptions::create<pcl::PointCloud<pcl::PointXYZI> >(
00148 this->laser_topic_name_,1,
00149 boost::bind( &GazeboRosGpuLaser::LaserConnect,this),
00150 boost::bind( &GazeboRosGpuLaser::LaserDisconnect,this),
00151 ros::VoidPtr(), &this->queue_);
00152 else
00153 laser_scan_ao = ros::AdvertiseOptions::create<sensor_msgs::LaserScan>(
00154 this->laser_topic_name_,1,
00155 boost::bind( &GazeboRosGpuLaser::LaserConnect,this),
00156 boost::bind( &GazeboRosGpuLaser::LaserDisconnect,this),
00157 ros::VoidPtr(), &this->queue_);
00158 this->laser_scan_pub_ = this->rosnode_->advertise(laser_scan_ao);
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 this->Init();
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00220
00221
00222
00223
00224
00227
00228
00229
00230
00231
00232
00233
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00265 void GazeboRosGpuLaser::Init()
00266 {
00267
00268 this->parentSensor->SetUpdateRate(this->update_rate_);
00269
00270
00271
00272
00273 if (this->update_rate_ > 0.0)
00274 this->update_period_ = 1.0/this->update_rate_;
00275 else
00276 this->update_period_ = 0.0;
00277
00278
00279 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosGpuLaser::QueueThread,this ) );
00280
00281 this->last_publish_ = ros::WallTime::now();
00282
00283 }
00284
00286
00287 void GazeboRosGpuLaser::LaserConnect()
00288 {
00289 this->laser_connect_count_++;
00290 this->parentSensor->SetActive(true);
00291 }
00293
00294 void GazeboRosGpuLaser::LaserDisconnect()
00295 {
00296 this->laser_connect_count_--;
00297
00298 if (this->laser_connect_count_ <= 0)
00299 this->parentSensor->SetActive(false);
00300 }
00301
00303
00304 void GazeboRosGpuLaser::OnNewLaserFrame(const float *_image,
00305 unsigned int _width, unsigned int _height, unsigned int _depth,
00306 const std::string &_format)
00307 {
00308 this->sensor_update_time_ = this->parentSensor->GetLastUpdateTime();
00309 if (!this->parentSensor->IsActive())
00310 {
00311 if (this->laser_connect_count_ > 0)
00312
00313 this->parentSensor->SetActive(true);
00314 }
00315 else
00316 {
00317 if (this->laser_connect_count_ > 0)
00318 {
00319 if (this->parentSensor->GetVerticalRangeCount() == 1)
00320 PublishLaserScan(_image, width);
00321 else
00322 PublishPointCloud(_image, width, height);
00323 }
00324 }
00325 }
00326
00328 void GazeboRosGpuLaser::PublishLaserScan(const float *_scan,
00329 unsigned int _width)
00330 {
00331 math::Angle maxAngle = this->parentSensor->GetAngleMax();
00332 math::Angle minAngle = this->parentSensor->GetAngleMin();
00333
00334 this->laser_scan_msg_.header.frame_id = this->frame_name_;
00335 this->laser_scan_msg_.header.stamp.sec = this->sensor_update_time_.sec;
00336 this->laser_scan_msg_.header.stamp.nsec = this->sensor_update_time_.nsec;
00337
00338 this->laser_scan_msg_.angle_min = minAngle.GetAsRadian();
00339 this->laser_scan_msg_.angle_max = maxAngle.GetAsRadian();
00340 this->laser_scan_msg_.angle_increment = (maxAngle.GetAsRadian() - minAngle.GetAsRadian())/((double)(_width -1));
00341 this->laser_scan_msg_.time_increment = 0;
00342 this->laser_scan_msg_.scan_time = 0;
00343 this->laser_scan_msg_.range_min = this->parentSensor->GetRangeMin();
00344 this->laser_scan_msg_.range_max = this->parentSensor->GetRangeMax();
00345 this->laser_scan_msg_.ranges.clear();
00346 this->laser_scan_msg_.intensities.clear();
00347
00348 for(unsigned int i=0; i < width; i++)
00349 {
00350 float range = _scan[3 * i];
00351 if (range < this->parentSensor->GetRangeMin())
00352 range = this->parentSensor->GetRangeMax();
00353 this->laser_scan_msg_.ranges.push_back(range + this->GaussianKernel(0,this->gaussian_noise_));
00354 this->laser_scan_msg_.intensities.push_back(_scan[3*i+1]);
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366 this->laser_scan_pub_.publish(this->laser_scan_msg_);
00367
00368
00369
00370
00371
00372
00373
00374 }
00375
00377 void GazeboRosGpuLaser::PublishPointCloud(const float *_scan,
00378 unsigned int _width, unsigned int _height)
00379 {
00380 this->point_cloud_msg_.header.frame_id = this->frame_name_;
00381 this->point_cloud_msg_.header.stamp.sec = this->sensor_update_time_.sec;
00382 this->point_cloud_msg_.header.stamp.nsec = this->sensor_update_time_.nsec;
00383
00384 this->point_cloud_msg_.points.clear();
00385 this->point_cloud_msg_.is_dense = true;
00386
00387 math::Angle maxAngle = this->parentSensor->GetAngleMax();
00388 math::Angle minAngle = this->parentSensor->GetAngleMin();
00389
00390 math::Angle verticalMaxAngle = this->parentSensor->GetVerticalAngleMax();
00391 math::Angle verticalMinAngle = this->parentSensor->GetVerticalAngleMin();
00392
00393 double dH = (maxAngle.GetAsRadian() - minAngle.GetAsRadian()) / (_width - 1) ;
00394 double dV = (verticalMaxAngle.GetAsRadian() - verticalMinAngle.GetAsRadian()) / (_height - 1);
00395
00396 double alpha = ((minAngle + maxAngle) / 2.0).GetAsRadian();
00397
00398 for (unsigned int j = 0; j < _height; j++)
00399 for (unsigned int i = 0; i < _width; i++)
00400 {
00401 double hAngle = (i * dH) + minAngle.GetAsRadian() - alpha;
00402 double vAngle = (j * dV) + verticalMinAngle.GetAsRadian();
00403 float r = _scan[3 * (i + j * _width)];
00404
00405 pcl::PointXYZI pr;
00406
00407 if ((r < this->parentSensor->GetRangeMin()) ||
00408 (r >= this->parentSensor->GetRangeMax()))
00409 r = this->parentSensor->GetRangeMax();
00410
00411 pcl::PointXYZI p;
00412
00413 if (this->parentSensor->IsHorizontal())
00414 {
00415 p.x = r * cos(vAngle) * cos(hAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00416 p.y = r * sin(hAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00417 p.z = r * sin(vAngle) * cos(hAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00418 }
00419 else
00420 {
00421 p.x = r * cos(vAngle) * cos(hAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00422 p.y = r * cos(vAngle) * sin(hAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00423 p.z = r * sin(vAngle) + this->GaussianKernel(0,this->gaussian_noise_);
00424 }
00425
00426 pr.x = cos(alpha)*p.x - sin(alpha)*p.y;
00427 pr.y = sin(alpha)*p.x + cos(alpha)*p.y;
00428 pr.z = p.z;
00429 pr.intensity = _scan[3 * (i + j * _width) + 1];
00430
00431 this->point_cloud_msg_.points.push_back(pr);
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 this->laser_scan_pub_.publish(this->point_cloud_msg_);
00443
00444
00445 }
00446
00447
00449
00450 double GazeboRosGpuLaser::GaussianKernel(double mu,double sigma)
00451 {
00452
00453
00454 double U = (double)rand()/(double)RAND_MAX;
00455 double V = (double)rand()/(double)RAND_MAX;
00456 double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
00457
00458
00459
00460 X = sigma * X + mu;
00461 return X;
00462 }
00463
00465
00466 void GazeboRosGpuLaser::QueueThread()
00467 {
00468 static const double timeout = 0.001;
00469
00470 while (this->rosnode_->ok())
00471 {
00473 this->queue_.callAvailable(ros::WallDuration(timeout));
00474 }
00475 }
00476
00477
00478 GZ_REGISTER_SENSOR_PLUGIN(GazeboRosGpuLaser)
00479
00480 }