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 #include <algorithm>
00029 #include <assert.h>
00030
00031 #include <gazebo_plugins/gazebo_ros_laser.h>
00032
00033 #include "physics/World.hh"
00034 #include "physics/HingeJoint.hh"
00035 #include "sensors/Sensor.hh"
00036 #include "sdf/interface/SDF.hh"
00037 #include "sdf/interface/Param.hh"
00038 #include "common/Exception.hh"
00039 #include "sensors/RaySensor.hh"
00040 #include "sensors/SensorTypes.hh"
00041 #include "tf/tf.h"
00042
00043 namespace gazebo
00044 {
00045
00047
00048 GazeboRosLaser::GazeboRosLaser()
00049 {
00050 }
00051
00053
00054 GazeboRosLaser::~GazeboRosLaser()
00055 {
00056 this->laser_queue_.clear();
00057 this->laser_queue_.disable();
00058 this->rosnode_->shutdown();
00059 this->callback_queue_thread_.join();
00060
00061 delete this->rosnode_;
00062 }
00063
00065
00066 void GazeboRosLaser::Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
00067 {
00068
00069 RayPlugin::Load(_parent, _sdf);
00070
00071
00072 this->parent_sensor_ = _parent;
00073
00074
00075 std::string worldName = _parent->GetWorldName();
00076 this->world_ = physics::get_world(worldName);
00077
00078 this->last_update_time_ = common::Time(0);
00079
00080 this->parent_ray_sensor_ = boost::shared_dynamic_cast<sensors::RaySensor>(this->parent_sensor_);
00081
00082 if (!this->parent_ray_sensor_)
00083 gzthrow("GazeboRosLaser controller requires a Ray Sensor as its parent");
00084
00085 this->robot_namespace_ = "";
00086 if (_sdf->HasElement("robotNamespace"))
00087 this->robot_namespace_ = _sdf->GetElement("robotNamespace")->GetValueString() + "/";
00088
00089 if (!_sdf->HasElement("frameName"))
00090 {
00091 ROS_INFO("Laser plugin missing <frameName>, defaults to /world");
00092 this->frame_name_ = "/world";
00093 }
00094 else
00095 this->frame_name_ = _sdf->GetElement("frameName")->GetValueString();
00096
00097 if (!_sdf->HasElement("topicName"))
00098 {
00099 ROS_INFO("Laser plugin missing <topicName>, defaults to /world");
00100 this->topic_name_ = "/world";
00101 }
00102 else
00103 this->topic_name_ = _sdf->GetElement("topicName")->GetValueString();
00104
00105 if (!_sdf->HasElement("gaussianNoise"))
00106 {
00107 ROS_INFO("Laser plugin missing <gaussianNoise>, defaults to 0.0");
00108 this->gaussian_noise_ = 0;
00109 }
00110 else
00111 this->gaussian_noise_ = _sdf->GetElement("gaussianNoise")->GetValueDouble();
00112
00113 if (!_sdf->HasElement("hokuyoMinIntensity"))
00114 {
00115 ROS_INFO("Laser plugin missing <hokuyoMinIntensity>, defaults to 101");
00116 this->hokuyo_min_intensity_ = 101;
00117 }
00118 else
00119 this->hokuyo_min_intensity_ = _sdf->GetElement("hokuyoMinIntensity")->GetValueDouble();
00120
00121 ROS_INFO("INFO: gazebo_ros_laser plugin should set minimum intensity to %f due to cutoff in hokuyo filters." , this->hokuyo_min_intensity_);
00122
00123 if (!_sdf->GetElement("updateRate"))
00124 {
00125 ROS_INFO("Laser plugin missing <updateRate>, defaults to 0");
00126 this->update_rate_ = 0;
00127 }
00128 else
00129 this->update_rate_ = _sdf->GetElement("updateRate")->GetValueDouble();
00130
00131
00132 this->parent_sensor_->SetUpdateRate(this->update_rate_);
00133
00134
00135
00136
00137 if (this->update_rate_ > 0.0)
00138 this->update_period_ = 1.0/this->update_rate_;
00139 else
00140 this->update_period_ = 0.0;
00141
00142 this->laser_connect_count_ = 0;
00143
00144
00145 if (!ros::isInitialized())
00146 {
00147 ROS_FATAL("while loading gazebo_ros_force plugin, ros is not initialized, please load a gazebo system plugin that initializes ros (e.g. libgazebo_ros_api_plugin.so from gazebo ros package)\n");
00148 return;
00149 }
00150
00151 this->rosnode_ = new ros::NodeHandle(this->robot_namespace_);
00152
00153
00154 std::string prefix;
00155 this->rosnode_->getParam(std::string("tf_prefix"), prefix);
00156 this->frame_name_ = tf::resolve(prefix, this->frame_name_);
00157
00158 if (this->topic_name_ != "")
00159 {
00160 ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::LaserScan>(
00161 this->topic_name_,1,
00162 boost::bind( &GazeboRosLaser::LaserConnect,this),
00163 boost::bind( &GazeboRosLaser::LaserDisconnect,this), ros::VoidPtr(), &this->laser_queue_);
00164 this->pub_ = this->rosnode_->advertise(ao);
00165 }
00166
00167
00168
00169
00170
00171 this->parent_ray_sensor_->SetActive(false);
00172
00173 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosLaser::LaserQueueThread,this ) );
00174
00175 }
00176
00178
00179 void GazeboRosLaser::LaserConnect()
00180 {
00181 this->laser_connect_count_++;
00182 this->parent_ray_sensor_->SetActive(true);
00183 }
00185
00186 void GazeboRosLaser::LaserDisconnect()
00187 {
00188 this->laser_connect_count_--;
00189
00190 if (this->laser_connect_count_ == 0)
00191 this->parent_ray_sensor_->SetActive(false);
00192 }
00193
00194
00196
00197 void GazeboRosLaser::OnNewLaserScans()
00198 {
00199 if (this->topic_name_ != "")
00200 {
00201 common::Time cur_time = this->world_->GetSimTime();
00202 if (cur_time - this->last_update_time_ >= this->update_period_)
00203 {
00204 common::Time sensor_update_time = this->parent_sensor_->GetLastUpdateTime();
00205 this->PutLaserData(sensor_update_time);
00206 this->last_update_time_ = cur_time;
00207 }
00208 }
00209 else
00210 {
00211 ROS_INFO("gazebo_ros_laser topic name not set");
00212 }
00213 }
00214
00216
00217 void GazeboRosLaser::PutLaserData(common::Time &_updateTime)
00218 {
00219 int i, ja, jb;
00220 double ra, rb, r, b;
00221 double intensity;
00222
00223 this->parent_ray_sensor_->SetActive(false);
00224
00225 math::Angle maxAngle = this->parent_ray_sensor_->GetAngleMax();
00226 math::Angle minAngle = this->parent_ray_sensor_->GetAngleMin();
00227
00228 double maxRange = this->parent_ray_sensor_->GetRangeMax();
00229 double minRange = this->parent_ray_sensor_->GetRangeMin();
00230 int rayCount = this->parent_ray_sensor_->GetRayCount();
00231 int rangeCount = this->parent_ray_sensor_->GetRangeCount();
00232
00233
00234
00235
00236
00237
00238 this->lock_.lock();
00239
00240 this->laser_msg_.header.frame_id = this->frame_name_;
00241 this->laser_msg_.header.stamp.sec = _updateTime.sec;
00242 this->laser_msg_.header.stamp.nsec = _updateTime.nsec;
00243
00244
00245 double tmp_res_angle = (maxAngle.Radian() - minAngle.Radian())/((double)(rangeCount -1));
00246 this->laser_msg_.angle_min = minAngle.Radian();
00247 this->laser_msg_.angle_max = maxAngle.Radian();
00248 this->laser_msg_.angle_increment = tmp_res_angle;
00249 this->laser_msg_.time_increment = 0;
00250 this->laser_msg_.scan_time = 0;
00251 this->laser_msg_.range_min = minRange;
00252 this->laser_msg_.range_max = maxRange;
00253 this->laser_msg_.ranges.clear();
00254 this->laser_msg_.intensities.clear();
00255
00256
00257 for (i = 0; i<rangeCount; i++)
00258 {
00259 b = (double) i * (rayCount - 1) / (rangeCount - 1);
00260 ja = (int) floor(b);
00261 jb = std::min(ja + 1, rayCount - 1);
00262 b = b - floor(b);
00263
00264 assert(ja >= 0 && ja < rayCount);
00265 assert(jb >= 0 && jb < rayCount);
00266
00267 ra = std::min(this->parent_ray_sensor_->GetLaserShape()->GetRange(ja) , maxRange-minRange);
00268 rb = std::min(this->parent_ray_sensor_->GetLaserShape()->GetRange(jb) , maxRange-minRange);
00269
00270
00271
00272
00273 r = (1 - b) * ra + b * rb;
00274
00275
00276
00277 intensity = 0.5*( this->parent_ray_sensor_->GetLaserShape()->GetRetro(ja)
00278 + this->parent_ray_sensor_->GetLaserShape()->GetRetro(jb));
00279
00280
00281
00282
00283
00284
00285 this->laser_msg_.ranges.push_back(std::min(r + minRange + this->GaussianKernel(0,this->gaussian_noise_), maxRange));
00286 this->laser_msg_.intensities.push_back(std::max(this->hokuyo_min_intensity_,intensity + this->GaussianKernel(0,this->gaussian_noise_)));
00287 }
00288
00289 this->parent_ray_sensor_->SetActive(true);
00290
00291
00292 if (this->laser_connect_count_ > 0 && this->topic_name_ != "")
00293 this->pub_.publish(this->laser_msg_);
00294
00295 this->lock_.unlock();
00296
00297 }
00298
00300
00301 double GazeboRosLaser::GaussianKernel(double mu,double sigma)
00302 {
00303
00304
00305 double U = (double)rand()/(double)RAND_MAX;
00306 double V = (double)rand()/(double)RAND_MAX;
00307 double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
00308
00309
00310
00311 X = sigma * X + mu;
00312 return X;
00313 }
00314
00316
00317 void GazeboRosLaser::LaserQueueThread()
00318 {
00319 static const double timeout = 0.01;
00320
00321 while (this->rosnode_->ok())
00322 {
00323 this->laser_queue_.callAvailable(ros::WallDuration(timeout));
00324 }
00325 }
00326
00327
00328 GZ_REGISTER_SENSOR_PLUGIN(GazeboRosLaser)
00329
00330 }