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
00032
00033
00034
00035
00036
00037 #include "ParticlePlume.h"
00038
00039 #include <cstdlib>
00040 #include <math.h>
00041
00042 particle_plume::ParticlePlume::ParticlePlume() : n_(), pn_("~")
00043 {
00044
00045 pn_.param<std::string>("global_frame_id", global_frame_id_, "map");
00046 pn_.param("bubble_radius", bubble_radius_, 0.10);
00047 pn_.param("max_particles_per_bubble", max_particles_per_bubble_, 1000);
00048 pn_.param("particle_life_time", particle_life_time_, 0);
00049 pn_.param("publish_frequency", publish_frequency_, 2.0);
00050 pn_.param("cell_size", cell_size_, 0.05);
00051 pn_.param<std::string>("sensor_model", sensor_model_, "Figaro 2620");
00052
00053
00054 nose_sub_.subscribe(n_, "nose", 10);
00055 tf_filter_ = new tf::MessageFilter<lse_sensor_msgs::Nostril>(nose_sub_, tf_, global_frame_id_, 10);
00056 tf_filter_->registerCallback( boost::bind(&ParticlePlume::noseCallback, this, _1) );
00057
00058
00059 plume_pub_.advertise(n_, "plume", 1);
00060
00061
00062 cells_pub_ = n_.advertise<nav_msgs::GridCells>("visited_cells", 1, true);
00063
00064 cells_.header.frame_id = global_frame_id_;
00065 cells_.cell_width = cell_size_;
00066 cells_.cell_height = cell_size_;
00067
00068 cells_changed_ = false;
00069 }
00070
00071 particle_plume::ParticlePlume::~ParticlePlume()
00072 {
00073
00074 }
00075
00076 void particle_plume::ParticlePlume::noseCallback(const boost::shared_ptr<const lse_sensor_msgs::Nostril>& msg)
00077 {
00078 if(msg->sensor_model.compare(sensor_model_)!=0) return;
00079
00080
00081 int number_of_particles = (int)((msg->reading-msg->clean_air) * max_particles_per_bubble_ / (msg->max_reading-msg->clean_air));
00082 if(number_of_particles<0) number_of_particles=0;
00083
00084 geometry_msgs::PointStamped bubble_center;
00085 geometry_msgs::PointStamped nose;
00086 nose.header.frame_id = msg->header.frame_id;
00087 nose.header.stamp = msg->header.stamp;
00088 nose.point.x = 0.0;
00089 nose.point.y = 0.0;
00090 nose.point.z = 0.0;
00091
00092 try
00093 {
00094
00095 tf_.transformPoint(global_frame_id_, nose, bubble_center);
00096 }
00097 catch(tf::TransformException &ex)
00098 {
00099 ROS_ERROR("ParticlePlume -- Error: %s", ex.what());
00100 return;
00101 }
00102
00103
00104 if(number_of_particles > 0)
00105 {
00106
00107 BubbleData new_odor_reading;
00108 new_odor_reading.number_of_particles = number_of_particles;
00109 new_odor_reading.bubble_center = bubble_center;
00110
00111 odor_readings_.push_back(new_odor_reading);
00112 }
00113
00114
00115 std::vector<CellCandidate> cell_candidates;
00116 std::vector<CellCandidate>::iterator cell_candidate;
00117
00118 int start_cell_x = ceil((bubble_center.point.x - bubble_radius_) / cell_size_);
00119 int end_cell_x = ceil((bubble_center.point.x + bubble_radius_) / cell_size_);
00120 int start_cell_y = ceil((bubble_center.point.y - bubble_radius_) / cell_size_);
00121 int end_cell_y = ceil((bubble_center.point.y + bubble_radius_) / cell_size_);
00122
00123 for(int x=start_cell_x ; x<end_cell_x ; x++)
00124 {
00125 for(int y=start_cell_y ; y<end_cell_y ; y++)
00126 {
00127 CellCandidate new_cell;
00128 new_cell.point.x = x*cell_size_;
00129 new_cell.point.y = y*cell_size_;
00130 new_cell.point.z = 0.0;
00131 new_cell.push = true;
00132
00133 cell_candidates.push_back(new_cell);
00134 }
00135 }
00136
00137 std::vector<geometry_msgs::Point>::iterator cell;
00138 for(int i=0 ; i<cells_.cells.size() ; i++)
00139 {
00140 cell = cells_.cells.begin()+i;
00141 for(cell_candidate = cell_candidates.begin() ; cell_candidate != cell_candidates.end() ; cell_candidate++)
00142 {
00143 if(cell_candidate->point.x == cell->x && cell_candidate->point.y == cell->y)
00144 {
00145 cell_candidate->push = false;
00146 cells_birth_[i] = ros::Time::now();
00147 }
00148 }
00149 }
00150
00151 for(cell_candidate = cell_candidates.begin() ; cell_candidate != cell_candidates.end() ; cell_candidate++)
00152 {
00153 if(cell_candidate->push == true)
00154 {
00155 cells_.cells.push_back(cell_candidate->point);
00156 cells_birth_.push_back(ros::Time::now());
00157 cells_changed_ = true;
00158 }
00159 }
00160 }
00161
00162 void particle_plume::ParticlePlume::publishPlume()
00163 {
00164 ros::Rate r(publish_frequency_);
00165
00166 std::vector<BubbleData>::iterator reading;
00167 std::vector<BubbleData>::iterator bubble_it;
00168
00169 bool push;
00170 bool publish_plume;
00171
00172
00173 while(n_.ok())
00174 {
00175 publish_plume = false;
00176
00177
00178 if(odor_readings_.size() > 0)
00179 {
00180 pcl::PointCloud<Particle> new_plume;
00181
00182 for(reading=odor_readings_.begin() ; reading!=odor_readings_.end() ; reading++)
00183 {
00184
00185 for(int i=0 ; i<reading->number_of_particles ; i++)
00186 {
00187 double r = drand()*bubble_radius_;
00188 double theta = drand()*M_PI;
00189 double phi = drand()*2*M_PI;
00190
00191 Particle particle;
00192 particle.x = reading->bubble_center.point.x + r*sin(theta)*cos(phi);
00193 particle.y = reading->bubble_center.point.y + r*sin(theta)*sin(phi);
00194 particle.z = reading->bubble_center.point.z + r*cos(theta);
00195 particle.intensity = 100.0;
00196
00197
00198 push = true;
00199 for(bubble_it=odor_readings_.begin() ; bubble_it!=reading ; bubble_it++)
00200 {
00201 double dx = bubble_it->bubble_center.point.x - particle.x;
00202 double dy = bubble_it->bubble_center.point.y - particle.y;
00203 double dz = bubble_it->bubble_center.point.z - particle.z;
00204
00205 if(sqrt(dx*dx + dy*dy + dz*dz) <= bubble_radius_)
00206 {
00207 push = false;
00208 break;
00209 }
00210 }
00211 if(push == true) new_plume.points.push_back(particle);
00212 }
00213 }
00214
00215
00216 for(int i=0 ; i<plume_.width ; i++)
00217 {
00218 Particle particle;
00219 particle.x = plume_.points[i].x;
00220 particle.y = plume_.points[i].y;
00221 particle.z = plume_.points[i].z;
00222 particle.intensity = plume_.points[i].intensity;
00223
00224
00225 if(particle_life_time_ > 0 && particle.intensity > 0.0)
00226 {
00227 particle.intensity -= 100.0/publish_frequency_/(particle_life_time_*60.0);
00228 if(particle.intensity < 0.0) particle.intensity = 0.0;
00229 }
00230
00231
00232 push = true;
00233 for(reading=odor_readings_.begin() ; reading!=odor_readings_.end() ; reading++)
00234 {
00235 double dx = reading->bubble_center.point.x - particle.x;
00236 double dy = reading->bubble_center.point.y - particle.y;
00237 double dz = reading->bubble_center.point.z - particle.z;
00238
00239 if(sqrt(dx*dx + dy*dy + dz*dz) <= bubble_radius_)
00240 {
00241 push=false;
00242 break;
00243 }
00244 }
00245 if(push==true && particle.intensity > 0.0) new_plume.points.push_back(particle);
00246 }
00247
00248
00249 odor_readings_.clear();
00250
00251
00252 plume_ = new_plume;
00253 plume_.width = plume_.points.size();
00254 plume_.height = 1;
00255
00256 publish_plume = true;
00257 }
00258
00259 else if(particle_life_time_ > 0)
00260 {
00261 pcl::PointCloud<Particle> new_plume;
00262 for(int i=0 ; i<plume_.width ; i++)
00263 {
00264 Particle particle;
00265 particle.x = plume_.points[i].x;
00266 particle.y = plume_.points[i].y;
00267 particle.z = plume_.points[i].z;
00268 particle.intensity = plume_.points[i].intensity;
00269
00270 if(particle.intensity > 0.0)
00271 {
00272 particle.intensity -= 100.0/publish_frequency_/(particle_life_time_*60.0);
00273 if(particle.intensity < 0.0) particle.intensity = 0.0;
00274 }
00275
00276 if(particle.intensity > 0.0) new_plume.points.push_back(particle);
00277 }
00278
00279 plume_ = new_plume;
00280 plume_.width = plume_.points.size();
00281 plume_.height = 1;
00282 }
00283
00284
00285 if(particle_life_time_ > 0)
00286 {
00287 std::vector<int> cells_to_delete;
00288 for(int i=0 ; i<cells_birth_.size() ; i++)
00289 {
00290 if((ros::Time::now() - cells_birth_[i]).toSec() > ros::Duration(particle_life_time_*60.0).toSec()) cells_to_delete.push_back(i);
00291 }
00292
00293 for(int i=cells_to_delete.size()-1 ; i>=0 ; i--)
00294 {
00295 cells_.cells.erase(cells_.cells.begin()+cells_to_delete[i]);
00296 cells_birth_.erase(cells_birth_.begin()+cells_to_delete[i]);
00297 }
00298 }
00299
00300
00301
00302 plume_.header.stamp = ros::Time::now();
00303 plume_.header.frame_id = global_frame_id_;
00304 plume_pub_.publish(plume_);
00305
00306
00307
00308
00309 cells_.header.stamp = ros::Time::now();
00310 cells_pub_.publish(cells_);
00311 cells_changed_ = false;
00312
00313
00314
00315 ros::spinOnce();
00316
00317 r.sleep();
00318 }
00319 }
00320
00321 float particle_plume::ParticlePlume::drand()
00322 {
00323 return ((rand()+1.0)/(RAND_MAX+1.0));
00324 }
00325
00326 double particle_plume::ParticlePlume::randomNormal()
00327 {
00328 return (sqrt(-2*log(drand()))*cos(2*M_PI*drand()));
00329 }
00330
00331
00332