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 #define NODE_VERSION 1.00
00038
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <stdio.h>
00042 #include <math.h>
00043
00044 #include <ros/ros.h>
00045 #include <boost/thread/mutex.hpp>
00046 #include <boost/thread/thread.hpp>
00047 #include <visualization_msgs/Marker.h>
00048 #include <nav_msgs/Odometry.h>
00049
00050 #include "plumesim/ReadPlumeSim.h"
00051
00052
00053 #include "utils/PSSources.h"
00054
00055 using namespace plumesim;
00056
00057 class PlumeSim
00058 {
00059
00060 public:
00068 PlumeSim();
00070
00073 ~PlumeSim();
00074
00083 bool ReadPlumeSim(plumesim::ReadPlumeSim::Request &req, plumesim::ReadPlumeSim::Response &res);
00084
00092 void UpdatePlume();
00093
00101 double getFrequency();
00102
00103 private:
00104
00105 PSSource * source;
00106
00107 ros::NodeHandle n;
00108 ros::Publisher marker_pub;
00109 ros::ServiceServer service;
00110
00111 visualization_msgs::Marker points;
00112
00113 std::string global_frame_id;
00114
00115 double freq;
00116
00117 double plume_color_r, plume_color_g, plume_color_b, plume_color_a;
00118
00119 std::string plume_ns;
00120 int plume_id;
00121 };
00122
00123
00124
00125 PlumeSim::PlumeSim() : n("~")
00126 {
00127 ROS_INFO("PlumeSim for ROS %.2f", NODE_VERSION);
00128
00129 marker_pub = n.advertise<visualization_msgs::Marker>("plumesim_markers", 10);
00130 service = n.advertiseService("read_plumesim", &PlumeSim::ReadPlumeSim, this);
00131
00132
00133 if(!n.hasParam("type"))
00134 {
00135 ROS_FATAL("No type of simulation was defined!");
00136 ROS_BREAK();
00137 }
00138 std::string type;
00139 n.getParam("type", type);
00140
00141 if(type.compare("meadering") == 0)
00142 {
00143 source = new PSMeadering();
00144 PSMeadering * meandering = dynamic_cast<PSMeadering*>(source);
00145
00146 n.param("releasepoint/x", meandering->startPoint.px, 0.0);
00147 n.param("releasepoint/y", meandering->startPoint.py, 0.0);
00148 n.param("releasepoint/z", meandering->startPoint.pz, 0.0);
00149 n.param("arena/start/x", meandering->arenaRect.startPoint.px, 0.0);
00150 n.param("arena/start/y", meandering->arenaRect.startPoint.py, 0.0);
00151 n.param("arena/end/x", meandering->arenaRect.endPoint.px, 0.0);
00152 n.param("arena/end/y", meandering->arenaRect.endPoint.py, 0.0);
00153 n.param("number_of_points", meandering->numOfPlumePoints, 100);
00154 n.param("release_rate", meandering->releaseRate, 10.0);
00155 n.param("dispersion_coeficient", meandering->dispersionCoeficient, 0.06);
00156 n.param("radius", meandering->radius, 0.1);
00157 }
00158 else if(type.compare("gaussian") == 0)
00159 {
00160 source = new PSGaussian();
00161 PSGaussian * gaussian = dynamic_cast<PSGaussian*>(source);
00162
00163 n.getParam("releasepoint/x", gaussian->startPoint.px);
00164 n.getParam("releasepoint/y", gaussian->startPoint.py);
00165 n.getParam("releasepoint/z", gaussian->startPoint.pz);
00166 n.getParam("arena/start/x", gaussian->arenaRect.startPoint.px);
00167 n.getParam("arena/start/y", gaussian->arenaRect.startPoint.py);
00168 n.getParam("arena/end/x", gaussian->arenaRect.endPoint.px);
00169 n.getParam("arena/end/y", gaussian->arenaRect.endPoint.py);
00170 n.getParam("cell_size", gaussian->cellSize);
00171 n.getParam("diffx", gaussian->diffX);
00172 n.getParam("diffy", gaussian->diffY);
00173 n.getParam("radius", gaussian->radius);
00174 n.getParam("max_points_per_cell", gaussian->maxPointsPerCell);
00175 }
00176 else if(type.compare("fluent") == 0)
00177 {
00178 source = new PSFluent();
00179 PSFluent * fluent = dynamic_cast<PSFluent*>(source);
00180
00181 n.getParam("max_points_per_cell", fluent->maxPointsPerCell);
00182 n.getParam("file_name", fluent->fileName);
00183 n.getParam("num_of_frames", fluent->numOfFrames);
00184 n.getParam("cell_size", fluent->cellSize);
00185 n.getParam("max_concentration", fluent->maxOdorValue);
00186 }
00187 else if(type.compare("pslog") == 0)
00188 {
00189 source = new PSLog();
00190 PSLog * log = dynamic_cast<PSLog*>(source);
00191
00192 n.getParam("max_points_per_cell", log->maxPointsPerCell);
00193 n.getParam("file_name", log->logFilePath);
00194 }
00195 else
00196 {
00197 ROS_FATAL("The type of simulation selected is not defined!");
00198 ROS_BREAK();
00199 }
00200
00201 n.param<std::string>("global_frame_id", global_frame_id, "map");
00202
00203
00204 n.param("color/r", this->plume_color_r, 1.0);
00205 n.param("color/g", this->plume_color_g, 0.0);
00206 n.param("color/b", this->plume_color_b, 0.0);
00207 n.param("color/a", this->plume_color_a, 0.9);
00208
00209
00210 plume_ns = "plume";
00211 n.getParam("ns", plume_ns);
00212 n.param("id", plume_id, 0);
00213
00214
00215 n.param("frequency", freq, 1.0);
00216
00217 if(source->setup() == -1)
00218 {
00219 ROS_FATAL("Failed to setup the plume!");
00220 ROS_BREAK();
00221 }
00222 ROS_INFO("Plume setup is complete.");
00223
00224
00225 points.header.frame_id = global_frame_id;
00226 points.header.stamp = ros::Time::now();
00227 points.action = visualization_msgs::Marker::ADD;
00228 points.ns = this->plume_ns;
00229 points.id = this->plume_id;
00230 points.pose.orientation.w = 1.0;
00231 points.type = visualization_msgs::Marker::SPHERE_LIST;
00232
00233
00234 points.scale.x = 0.06;
00235 points.scale.y = 0.06;
00236 points.scale.z = 0.06;
00237
00238 points.color.r = this->plume_color_r;
00239 points.color.g = this->plume_color_g;
00240 points.color.b = this->plume_color_b;
00241 points.color.a = this->plume_color_a;
00242 }
00243
00244
00245
00246 PlumeSim::~PlumeSim()
00247 {
00248 source->cleanup();
00249 delete source;
00250 }
00251
00252
00253
00254 void PlumeSim::UpdatePlume()
00255 {
00256 if(this->source->IsPlaying())
00257 {
00258 if(this->source->generatePoints() == -1)
00259 {
00260 ROS_ERROR("Unable to generate a new plume!");
00261 }
00262 else
00263 {
00264 points.header.stamp = ros::Time::now();
00265 points.points.clear();
00266
00267 for(int i=0 ; i<source->plumePoints.size() ; i++)
00268 {
00269 geometry_msgs::Point p;
00270 p.x = source->plumePoints[i].px;
00271 p.y = source->plumePoints[i].py;
00272
00273 p.z = 0.2;
00274 points.points.push_back(p);
00275 }
00276 }
00277 }
00278
00279 marker_pub.publish(points);
00280 }
00281
00282
00283
00284 double PlumeSim::getFrequency()
00285 {
00286 return this->freq;
00287 }
00288
00289
00290
00291 bool PlumeSim::ReadPlumeSim(plumesim::ReadPlumeSim::Request &req, plumesim::ReadPlumeSim::Response &res)
00292 {
00293 PSOdorData odor_data;
00294 PSPoint3d point;
00295
00296 point.px = req.odom.pose.pose.position.x;
00297 point.py = req.odom.pose.pose.position.y;
00298 point.pz = req.odom.pose.pose.position.z;
00299
00300 source->getChemicalReading(&point, &odor_data);
00301
00302 res.nostril.header.frame_id = req.odom.header.frame_id;
00303 res.nostril.header.stamp = ros::Time::now();
00304 res.nostril.sensor_model = "PlumeSim";
00305 res.nostril.reading = odor_data.chemical;
00306 res.nostril.max_reading = 1.0;
00307 res.nostril.min_reading = 0.0;
00308
00309
00310
00311 return true;
00312 }
00313
00314
00315
00316
00317 int main(int argc, char** argv)
00318 {
00319 ros::init(argc, argv, "plumesim");
00320
00321 PlumeSim * plumesim_node = new PlumeSim();
00322
00323 boost::thread t = boost::thread::thread(boost::bind(&ros::spin));
00324
00325 ros::Rate r(plumesim_node->getFrequency());
00326 while(ros::ok())
00327 {
00328 plumesim_node->UpdatePlume();
00329 r.sleep();
00330 }
00331 t.join();
00332
00333 delete plumesim_node;
00334
00335 exit(0);
00336 }
00337
00338
00339