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
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
00024 #define MAP_RESOLUTION 0.1
00025
00026
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
00148 bool GazeboMapPublisher::createMap(const CollisionMapRequest &msg, const std::string& map_frame, nav_msgs::OccupancyGrid& map) {
00149
00150
00151
00152
00153
00154
00155
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
00198 gazebo::physics::RayShapePtr ray = boost::dynamic_pointer_cast<gazebo::physics::RayShape>(
00199 engine->CreateShape("ray", gazebo::physics::CollisionPtr()));
00200
00201
00202 grid.resize(count_horizontal,std::vector<int>(count_vertical,blank));
00203
00204 for (int i = 0; i < count_vertical; ++i) {
00205
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
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
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
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
00306 map.data.resize(map_cells_x*map_cells_y,0);
00307
00308
00309
00310
00311
00312
00313 #endif
00314 return map;
00315 }
00316
00317