GazeboMapPublisher.cpp
Go to the documentation of this file.
00001 #include <gazebo_state_plugins/GazeboMapPublisher.h>
00002 #include <gazebo_version_helpers/GazeboVersionHelpers.h>
00003 
00004 #include <gazebo/physics/physics.hh>
00005 
00006 #include <Eigen/Core>
00007 
00008 #include <shape_msgs/SolidPrimitive.h>
00009 #include <geometry_msgs/Pose.h>
00010 
00011 #include <nav_msgs/MapMetaData.h>
00012 #include <std_msgs/Float64.h>
00013 
00014 #define DEFAULT_REQUEST_MAP_SERVICE "dynamic_map"
00015 
00016 //publishing rate
00017 #define DEFAULT_MAP_PUB_FREQ "1" 
00018 
00019 #define MAP_OFFSET_X -10
00020 #define MAP_OFFSET_Y -10
00021 #define MAP_LEN_X 20
00022 #define MAP_LEN_Y 20
00023 //map resolution (m/cell)
00024 #define MAP_RESOLUTION 0.1
00025 
00026 //height of obstacles to consider for generating the map
00027 #define MAP_HEIGHT 1.0
00028 
00029 #define MAP_QUEUE_SIZE 50
00030 
00031 #define MSG_PRINT(o)\
00032     std::cout<<o<<std::endl;
00033 
00034 #define MAX_MAP_VAL 100 
00035 
00036 using gazebo::GazeboMapPublisher;
00037 using gazebo::GzVector3;
00038 
00039 GZ_REGISTER_WORLD_PLUGIN(GazeboMapPublisher)
00040 
00041 class GazeboMapPublisher::CollisionMapRequest {
00042     public:
00043     CollisionMapRequest(): threshold(MAX_MAP_VAL) {
00044     }
00045     CollisionMapRequest(const CollisionMapRequest& o):
00046         upperLeft(o.upperLeft),
00047         upperRight(o.upperRight),
00048         lowerRight(o.lowerRight),
00049         lowerLeft(o.lowerLeft),
00050         height(o.height),
00051         resolution(o.resolution),
00052         threshold(o.threshold){}
00053 
00054     Eigen::Vector2i  upperLeft;
00055     Eigen::Vector2i  upperRight;
00056     Eigen::Vector2i  lowerRight;
00057     Eigen::Vector2i  lowerLeft;
00058     double height;
00059     double resolution;
00060     unsigned int  threshold;
00061 };
00062 
00063 GazeboMapPublisher::GazeboMapPublisher() : WorldPlugin() {
00064    
00065     ros::NodeHandle _node("/gazebo_state_plugins");
00066 
00067     _node.param<std::string>("publish_map_topic", MAP_TOPIC, "");
00068     MSG_PRINT("Got gazebo map topic name :"<<MAP_TOPIC.c_str());
00069     
00070     _node.param<std::string>("map_frame_id", MAP_FRAME, "/map");
00071     MSG_PRINT("Got gazebo map frame id: "<<MAP_FRAME.c_str());
00072     
00073     _node.param<std::string>("map_metadata_topic", METADATA_TOPIC, "map_metadata");
00074     MSG_PRINT("Got gazebo map metadata topic name:"<<METADATA_TOPIC.c_str());
00075     
00076     _node.param<std::string>("request_map_service", REQUEST_MAP_SERVICE, DEFAULT_REQUEST_MAP_SERVICE);
00077     MSG_PRINT("Got gazebo map service name: " <<REQUEST_MAP_SERVICE.c_str());
00078     
00079     _node.param<std::string>("robot_name", ROBOT_NAME, "robot");
00080     MSG_PRINT("Got gazebo map publisher robot name: " <<ROBOT_NAME.c_str());
00081 
00082     std::string MAP_PUB_FREQUENCY;
00083     _node.param<std::string>("map_pub_frequency", MAP_PUB_FREQUENCY, DEFAULT_MAP_PUB_FREQ);
00084     MAP_PUB_FREQ=atoi(MAP_PUB_FREQUENCY.c_str());
00085     MSG_PRINT("Got gazebo map publish frequency: <"<<MAP_PUB_FREQ<<"> from string "<<MAP_PUB_FREQUENCY.c_str());
00086 
00087     map_offset_x=MAP_OFFSET_X;
00088     map_offset_y=MAP_OFFSET_Y;
00089     map_len_x=MAP_LEN_X;
00090     map_len_y=MAP_LEN_Y;
00091     map_resolution=MAP_RESOLUTION;
00092     map_height=MAP_HEIGHT;
00093     
00094     worldChangedSinceLastAdvert=true; 
00095     
00096 }
00097 
00098 void GazeboMapPublisher::Load(physics::WorldPtr _world, sdf::ElementPtr _sdf){
00099     world=_world;    
00100 
00101     request_map_srv = node.advertiseService(REQUEST_MAP_SERVICE, &GazeboMapPublisher::requestMap,this);
00102 
00103     if (MAP_TOPIC.length()==0) {
00104         ROS_WARN("No map being published from gazebo, as the parameter 'gazebo_publish_map' was specified empty. This may be intended.");
00105         return;
00106     }
00107     
00108     update_connection = event::Events::ConnectWorldUpdateBegin(boost::bind(&GazeboMapPublisher::onWorldUpdate, this));
00109 
00110     ros::Rate rate(MAP_PUB_FREQ);
00111     publishTimer=node.createTimer(rate,&GazeboMapPublisher::advertEvent, this);
00112 
00113     map_pub = node.advertise<nav_msgs::OccupancyGrid>(MAP_TOPIC, MAP_QUEUE_SIZE);
00114     meta_pub = node.advertise<nav_msgs::MapMetaData>(METADATA_TOPIC,MAP_QUEUE_SIZE);
00115 }
00116 
00117 
00118 bool GazeboMapPublisher::requestMap(nav_msgs::GetMap::Request &req, nav_msgs::GetMap::Response &res) {
00119     nav_msgs::OccupancyGrid map=getMap();
00120     res.map=map;
00121     MSG_PRINT("Received service request for map!");
00122     return true;
00123 }
00124 
00125 void GazeboMapPublisher::advertEvent(const ros::TimerEvent& e) {
00126 
00127     if (!worldChangedSinceLastAdvert) return;
00128 
00129     if (map_pub.getNumSubscribers()!=0) {
00130         nav_msgs::OccupancyGrid map=getMap();
00131         map_pub.publish(map);
00132     }
00133 
00134     if (meta_pub.getNumSubscribers()!=0) {
00135         nav_msgs::MapMetaData mdata=getMetaData();
00136         meta_pub.publish(mdata);
00137     }
00138 
00139     worldChangedSinceLastAdvert=false;
00140 }
00141 
00142 
00143 void GazeboMapPublisher::onWorldUpdate() {
00144     worldChangedSinceLastAdvert=true; 
00145 }
00146 
00147 //see http://gazebosim.org/wiki/Tutorials/1.4/custom_messages#Collision_Map_Creator_Plugin
00148 bool GazeboMapPublisher::createMap(const CollisionMapRequest &msg, const std::string& map_frame, nav_msgs::OccupancyGrid& map) {
00149     /*MSG_PRINT("Creating collision map with corners at (" <<
00150                  msg.upperLeft.x() << ", " << msg.upperLeft.y() << "), (" <<
00151                  msg.upperRight.x() << ", " << msg.upperRight.y() << "), (" <<
00152                  msg.lowerRight.x() << ", " << msg.lowerRight.y() << "), (" <<
00153                  msg.lowerLeft.x() << ", " << msg.lowerLeft.y() << ") with collision projected from z = " <<
00154                  msg.height << "\nResolution = " << msg.resolution << " m\n" <<
00155                  "Occupied spaces will be filled with: " << msg.threshold);
00156     */
00157     double z = msg.height;
00158     double dX_vertical = msg.upperLeft.x() - msg.lowerLeft.x();
00159     double dY_vertical = msg.upperLeft.y() - msg.lowerLeft.y();
00160     double mag_vertical = sqrt(dX_vertical * dX_vertical + dY_vertical * dY_vertical);
00161     dX_vertical = msg.resolution * dX_vertical / mag_vertical;
00162     dY_vertical = msg.resolution * dY_vertical / mag_vertical;
00163 
00164     double step_s = msg.resolution;
00165 
00166     double dX_horizontal = msg.upperRight.x() - msg.upperLeft.x();
00167     double dY_horizontal = msg.upperRight.y() - msg.upperLeft.y();
00168     double mag_horizontal = sqrt(dX_horizontal * dX_horizontal + dY_horizontal * dY_horizontal);
00169     dX_horizontal = msg.resolution * dX_horizontal / mag_horizontal;
00170     dY_horizontal = msg.resolution * dY_horizontal / mag_horizontal;
00171 
00172 
00173 
00174     int count_vertical = mag_vertical / msg.resolution;
00175     int count_horizontal = mag_horizontal / msg.resolution;
00176 
00177     if (count_vertical == 0 || count_horizontal == 0)
00178     {
00179         MSG_PRINT("Image has a zero dimensions, check coordinates");
00180         return false;
00181     }
00182     double x,y;
00183 
00184     unsigned int threshold=msg.threshold;
00185     if (threshold > MAX_MAP_VAL) threshold=MAX_MAP_VAL;
00186     unsigned int blank=MAX_MAP_VAL-threshold;
00187     unsigned int fill=MAX_MAP_VAL;
00188     std::vector<std::vector<int> > grid;
00189 
00190     double dist;
00191     std::string entityName;
00192     GzVector3 start = gazebo::GetVector(0, 0, msg.height);
00193     GzVector3 end = gazebo::GetVector(0, 0, 0.001);
00194 
00195     gazebo::physics::PhysicsEnginePtr engine = gazebo::GetPhysics(world);
00196     engine->InitForThread();
00197     //gazebo::physics::RayShapePtr ray = boost::shared_dynamic_cast<gazebo::physics::RayShape>(
00198     gazebo::physics::RayShapePtr ray = boost::dynamic_pointer_cast<gazebo::physics::RayShape>(
00199           engine->CreateShape("ray", gazebo::physics::CollisionPtr()));
00200 
00201     //MSG_PRINT("Rasterizing model and checking collisions");
00202     grid.resize(count_horizontal,std::vector<int>(count_vertical,blank));
00203 
00204     for (int i = 0; i < count_vertical; ++i) {
00205         //MSG_PRINT("Percent complete: " << i * 100.0 / count_vertical);
00206         x = i * dX_vertical + msg.lowerLeft.x();
00207         y = i * dY_vertical + msg.lowerLeft.y();
00208         for (int j = 0; j < count_horizontal; ++j) {
00209             x += dX_horizontal;
00210             y += dY_horizontal;
00211 
00212             gazebo::SetX(start, x);
00213             gazebo::SetX(end, x);
00214             gazebo::SetY(start, y);
00215             gazebo::SetY(end, y);
00216             ray->SetPoints(start, end);
00217             ray->GetIntersection(dist, entityName);
00218             if (!entityName.empty()) {
00219                 std::string model=entityName.substr(0,entityName.find("::"));
00220                 //MSG_PRINT("Collides: "<<entityName<<" robot name="<<ROBOT_NAME<<" model: "<<model);
00221                 if (model!=ROBOT_NAME) 
00222                     grid[i][j]=fill;
00223             }
00224         }
00225     }
00226 
00227     map.header.frame_id=map_frame;
00228     map.header.stamp=ros::Time::now();
00229     
00230     nav_msgs::MapMetaData meta=getMetaData();
00231     map.info=meta;
00232 
00233     /*map.info.map_load_time=ros::Time::now();
00234     map.info.resolution=msg.resolution;
00235     map.info.width=count_horizontal;
00236     map.info.height=count_vertical;
00237     map.info.origin.position.x=msg.lowerLeft.x();
00238     map.info.origin.position.y=msg.lowerLeft.y();
00239     map.info.origin.position.z=0;
00240     map.info.origin.orientation.x=0;
00241     map.info.origin.orientation.y=0;
00242     map.info.origin.orientation.z=0;
00243     map.info.origin.orientation.w=1;
00244     MSG_PRINT("Meta compare: "<<std::endl<<meta<<"===="<<std::endl<<map.info);
00245     */
00246 
00247     //MSG_PRINT("Completed calculations, created map");
00248     
00249     int _x=0;
00250     int _y=0;
00251     for (std::vector<std::vector<int> >::iterator yIt=grid.begin(); yIt!=grid.end(); ++yIt) {
00252         _x=0;
00253         for (std::vector<int>::iterator xIt=yIt->begin(); xIt!=yIt->end(); ++xIt) {
00254             map.data.push_back(*xIt);
00255             ++_x;
00256         }
00257         ++_y;
00258     }
00259     return true;
00260 }
00261 
00262 GazeboMapPublisher::CollisionMapRequest GazeboMapPublisher::getCollisionRequest(){
00263     CollisionMapRequest r;
00264     r.lowerLeft= Eigen::Vector2i(map_offset_x,map_offset_y);
00265     r.lowerRight=Eigen::Vector2i(map_offset_x+map_len_x,map_offset_y);
00266     r.upperLeft= Eigen::Vector2i(map_offset_x,map_offset_y+map_len_y);
00267     r.upperRight=Eigen::Vector2i(map_offset_x+map_len_x,map_offset_y+map_len_y);
00268     r.resolution=map_resolution;
00269     r.height=map_height;
00270     r.threshold=MAX_MAP_VAL;
00271     return r;
00272 }
00273 
00274 
00275 nav_msgs::MapMetaData GazeboMapPublisher::getMetaData() {
00276     nav_msgs::MapMetaData mdata;
00277     mdata.map_load_time=ros::Time::now();
00278     mdata.resolution=map_resolution;
00279     mdata.width=map_len_x/map_resolution;
00280     mdata.height=map_len_y/map_resolution;
00281     mdata.origin.position.x=map_offset_x;
00282     mdata.origin.position.y=map_offset_y;
00283     mdata.origin.position.z=0;
00284     mdata.origin.orientation.w=0;
00285     return mdata;
00286 }
00287 
00288 
00289 nav_msgs::OccupancyGrid GazeboMapPublisher::getMap() {
00290     nav_msgs::OccupancyGrid map;
00291 
00292 #if 1
00293     CollisionMapRequest r=getCollisionRequest();    
00294     if (!createMap(r,MAP_FRAME,map)) {
00295         ROS_ERROR("Could not request map");
00296     }    
00297 #else
00298     map.header.frame_id=MAP_FRAME;
00299     map.header.stamp=ros::Time::now();
00300     
00301     map.info=getMetaData();
00302 
00303     float map_cells_x=floor(map_len_x/map_resolution);
00304     float map_cells_y=floor(map_len_y/map_resolution);
00305     //create an empty occupancy grid
00306     map.data.resize(map_cells_x*map_cells_y,0);
00307     
00308     //... fill it with data!
00309     //for each object found in gazebo, locate it on the map and check if it intersects a cell,
00310     //and put a value of 100 in that cell.
00311 
00312     //skip the robot from the occupancy grid!
00313 #endif
00314     return map;
00315 }
00316 
00317 


gazebo_state_plugins
Author(s): Jennifer Buehler
autogenerated on Tue May 7 2019 03:29:35