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 <gazebo/Sensor.hh>
00034 #include <gazebo/Global.hh>
00035 #include <gazebo/XMLConfig.hh>
00036 #include <gazebo/HingeJoint.hh>
00037 #include <gazebo/World.hh>
00038 #include <gazebo/Simulator.hh>
00039 #include <gazebo/gazebo.h>
00040 #include <gazebo/GazeboError.hh>
00041 #include <gazebo/ControllerFactory.hh>
00042 #include <gazebo/RaySensor.hh>
00043
00044 namespace gazebo
00045 {
00046
00047 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_laser", GazeboRosLaser);
00048
00050
00051 GazeboRosLaser::GazeboRosLaser(Entity *parent)
00052 : Controller(parent)
00053 {
00054 this->myParent = dynamic_cast<RaySensor*>(this->parent);
00055
00056 if (!this->myParent)
00057 gzthrow("GazeboRosLaser controller requires a Ray Sensor as its parent");
00058
00059 Param::Begin(&this->parameters);
00060 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0);
00061 this->hokuyoMinIntensityP = new ParamT<double>("hokuyoMinIntensity", 101.0, 0);
00062 this->gaussianNoiseP = new ParamT<double>("gaussianNoise", 0.0, 0);
00063 this->topicNameP = new ParamT<std::string>("topicName", "", 1);
00064 this->deprecatedTopicNameP = new ParamT<std::string>("deprecatedTopicName", "", 0);
00065 this->frameNameP = new ParamT<std::string>("frameName", "default_gazebo_ros_laser_frame", 0);
00066 Param::End();
00067
00068 this->laserConnectCount = 0;
00069 this->deprecatedLaserConnectCount = 0;
00070 }
00071
00073
00074 GazeboRosLaser::~GazeboRosLaser()
00075 {
00076 delete this->robotNamespaceP;
00077 delete this->hokuyoMinIntensityP;
00078 delete this->gaussianNoiseP;
00079 delete this->topicNameP;
00080 delete this->deprecatedTopicNameP;
00081 delete this->frameNameP;
00082 delete this->rosnode_;
00083 }
00084
00086
00087 void GazeboRosLaser::LoadChild(XMLConfigNode *node)
00088 {
00089 this->robotNamespaceP->Load(node);
00090 this->robotNamespace = this->robotNamespaceP->GetValue();
00091
00092 if (!ros::isInitialized())
00093 {
00094 int argc = 0;
00095 char** argv = NULL;
00096 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00097 }
00098
00099 this->rosnode_ = new ros::NodeHandle(this->robotNamespace);
00100
00101 this->hokuyoMinIntensityP->Load(node);
00102 this->hokuyoMinIntensity = this->hokuyoMinIntensityP->GetValue();
00103 ROS_INFO("INFO: gazebo_ros_laser plugin artifically sets minimum intensity to %f due to cutoff in hokuyo filters." , this->hokuyoMinIntensity);
00104
00105 this->topicNameP->Load(node);
00106 this->topicName = this->topicNameP->GetValue();
00107 this->deprecatedTopicNameP->Load(node);
00108 this->deprecatedTopicName = this->deprecatedTopicNameP->GetValue();
00109 this->frameNameP->Load(node);
00110 this->frameName = this->frameNameP->GetValue();
00111 this->gaussianNoiseP->Load(node);
00112 this->gaussianNoise = this->gaussianNoiseP->GetValue();
00113
00114 if (this->topicName != "")
00115 {
00116 #ifdef USE_CBQ
00117 ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::LaserScan>(
00118 this->topicName,1,
00119 boost::bind( &GazeboRosLaser::LaserConnect,this),
00120 boost::bind( &GazeboRosLaser::LaserDisconnect,this), ros::VoidPtr(), &this->laser_queue_);
00121 this->pub_ = this->rosnode_->advertise(ao);
00122 #else
00123 this->pub_ = this->rosnode_->advertise<sensor_msgs::LaserScan>(this->topicName,1,
00124 boost::bind( &GazeboRosLaser::LaserConnect, this),
00125 boost::bind( &GazeboRosLaser::LaserDisconnect, this));
00126 #endif
00127 }
00128
00129 if (this->deprecatedTopicName != "")
00130 {
00131 #ifdef USE_CBQ
00132 ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::LaserScan>(
00133 this->deprecatedTopicName,1,
00134 boost::bind( &GazeboRosLaser::DeprecatedLaserConnect,this),
00135 boost::bind( &GazeboRosLaser::DeprecatedLaserDisconnect,this), ros::VoidPtr(), &this->laser_queue_);
00136 this->deprecated_pub_ = this->rosnode_->advertise(ao);
00137 #else
00138 this->deprecated_pub_ = this->rosnode_->advertise<sensor_msgs::LaserScan>(this->deprecatedTopicName,1,
00139 boost::bind( &GazeboRosLaser::DeprecatedLaserConnect, this),
00140 boost::bind( &GazeboRosLaser::DeprecatedLaserDisconnect, this));
00141 #endif
00142 }
00143 }
00144
00146
00147 void GazeboRosLaser::InitChild()
00148 {
00149
00150 this->myParent->SetActive(false);
00151 #ifdef USE_CBQ
00152
00153 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosLaser::LaserQueueThread,this ) );
00154 #endif
00155 }
00156
00158
00159 void GazeboRosLaser::LaserConnect()
00160 {
00161 this->laserConnectCount++;
00162 }
00164
00165 void GazeboRosLaser::LaserDisconnect()
00166 {
00167 this->laserConnectCount--;
00168
00169 if (this->laserConnectCount == 0 && this->deprecatedLaserConnectCount == 0)
00170 this->myParent->SetActive(false);
00171 }
00172
00174
00175 void GazeboRosLaser::DeprecatedLaserConnect()
00176 {
00177 ROS_WARN("you are subscribing to a deprecated ROS topic %s, please change your code/launch script to use new ROS topic %s",
00178 this->deprecatedTopicName.c_str(), this->topicName.c_str());
00179 this->deprecatedLaserConnectCount++;
00180 }
00182
00183 void GazeboRosLaser::DeprecatedLaserDisconnect()
00184 {
00185 this->deprecatedLaserConnectCount--;
00186
00187 if (this->laserConnectCount == 0 && this->deprecatedLaserConnectCount == 0)
00188 this->myParent->SetActive(false);
00189 }
00190
00192
00193 void GazeboRosLaser::UpdateChild()
00194 {
00195
00196
00197 if (!this->myParent->IsActive())
00198 {
00199
00200 if ((this->laserConnectCount > 0 && this->topicName != "") ||
00201 (this->deprecatedLaserConnectCount > 0 && this->deprecatedTopicName != ""))
00202 this->myParent->SetActive(true);
00203 }
00204 else
00205 {
00206 this->PutLaserData();
00207 }
00208 }
00209
00211
00212 void GazeboRosLaser::FiniChild()
00213 {
00214 this->rosnode_->shutdown();
00215 sleep(1);
00216 #ifdef USE_CBQ
00217 this->callback_queue_thread_.join();
00218 #endif
00219 }
00220
00222
00223 void GazeboRosLaser::PutLaserData()
00224 {
00225 int i, ja, jb;
00226 double ra, rb, r, b;
00227 double intensity;
00228
00229 Angle maxAngle = this->myParent->GetMaxAngle();
00230 Angle minAngle = this->myParent->GetMinAngle();
00231
00232 double maxRange = this->myParent->GetMaxRange();
00233 double minRange = this->myParent->GetMinRange();
00234 int rayCount = this->myParent->GetRayCount();
00235 int rangeCount = this->myParent->GetRangeCount();
00236
00237
00238
00239
00240
00241
00242 this->lock.lock();
00243
00244 this->laserMsg.header.frame_id = this->frameName;
00245 this->laserMsg.header.stamp.sec = (Simulator::Instance()->GetSimTime()).sec;
00246 this->laserMsg.header.stamp.nsec = (Simulator::Instance()->GetSimTime()).nsec;
00247
00248
00249 double tmp_res_angle = (maxAngle.GetAsRadian() - minAngle.GetAsRadian())/((double)(rangeCount -1));
00250 this->laserMsg.angle_min = minAngle.GetAsRadian();
00251 this->laserMsg.angle_max = maxAngle.GetAsRadian();
00252 this->laserMsg.angle_increment = tmp_res_angle;
00253 this->laserMsg.time_increment = 0;
00254 this->laserMsg.scan_time = 0;
00255 this->laserMsg.range_min = minRange;
00256 this->laserMsg.range_max = maxRange;
00257 this->laserMsg.ranges.clear();
00258 this->laserMsg.intensities.clear();
00259
00260
00261 for (i = 0; i<rangeCount; i++)
00262 {
00263 b = (double) i * (rayCount - 1) / (rangeCount - 1);
00264 ja = (int) floor(b);
00265 jb = std::min(ja + 1, rayCount - 1);
00266 b = b - floor(b);
00267
00268 assert(ja >= 0 && ja < rayCount);
00269 assert(jb >= 0 && jb < rayCount);
00270
00271 ra = std::min(this->myParent->GetRange(ja) , maxRange-minRange);
00272 rb = std::min(this->myParent->GetRange(jb) , maxRange-minRange);
00273
00274
00275
00276
00277 r = (1 - b) * ra + b * rb;
00278
00279
00280
00281 intensity = 0.5*( this->myParent->GetRetro(ja) + (int) this->myParent->GetRetro(jb));
00282
00283
00284
00285
00286
00287
00288 this->laserMsg.ranges.push_back(std::min(r + minRange + this->GaussianKernel(0,this->gaussianNoise), maxRange));
00289 this->laserMsg.intensities.push_back(std::max(this->hokuyoMinIntensity,intensity + this->GaussianKernel(0,this->gaussianNoise)));
00290 }
00291
00292
00293 if (this->laserConnectCount > 0 && this->topicName != "")
00294 this->pub_.publish(this->laserMsg);
00295
00296 if (this->deprecatedLaserConnectCount > 0 && this->deprecatedTopicName != "")
00297 this->deprecated_pub_.publish(this->laserMsg);
00298
00299 this->lock.unlock();
00300
00301 }
00302
00304
00305 double GazeboRosLaser::GaussianKernel(double mu,double sigma)
00306 {
00307
00308
00309 double U = (double)rand()/(double)RAND_MAX;
00310 double V = (double)rand()/(double)RAND_MAX;
00311 double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
00312
00313
00314
00315 X = sigma * X + mu;
00316 return X;
00317 }
00318
00319 #ifdef USE_CBQ
00320
00321
00322 void GazeboRosLaser::LaserQueueThread()
00323 {
00324 static const double timeout = 0.01;
00325
00326 while (this->rosnode_->ok())
00327 {
00328 this->laser_queue_.callAvailable(ros::WallDuration(timeout));
00329 }
00330 }
00331 #endif
00332
00333 }