plannerMapServer.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *      * Redistributions of source code must retain the above copyright
00009  *              notice, this list of conditions and the following disclaimer.
00010  *      * Redistributions in binary form must reproduce the above copyright
00011  *              notice, this list of conditions and the following disclaimer in the
00012  *              documentation and/or other materials provided with the distribution.
00013  *      * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *              contributors may be used to endorse or promote products derived from
00015  *              this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00037 #include <fstream>
00038 
00039 #include <youbot_overhead_localization/plannerMapServer.h>
00040 
00041 //TODO: Temporary include until image resizing is moved to vision
00042 #include <opencv2/imgproc/imgproc.hpp>
00043 
00044 using namespace std;
00045 
00046 plannerMapServer::plannerMapServer()
00047 {
00048   mapfname = "";
00049   std::string fname;
00050   n.getParam("/planner_map_server/map_file_yaml", fname);
00051   n.param("frameID", frameID, std::string("map"));
00052 
00053   std::ifstream fin(fname.c_str());
00054   if (fin.fail())
00055   {
00056     ROS_ERROR("Map_server could not open %s.", fname.c_str());
00057     exit(-1);
00058   }
00059   YAML::Parser parser(fin);
00060   YAML::Node doc;
00061   parser.GetNextDocument(doc);
00062   try
00063   {
00064     doc["resolution"] >> resolution;
00065   }
00066   catch (YAML::InvalidScalar &)
00067   {
00068     ROS_ERROR("The map does not contain a resolution tag or it is invalid.");
00069     exit(-1);
00070   }
00071   try
00072   {
00073     doc["negate"] >> negate;
00074   }
00075   catch (YAML::InvalidScalar &)
00076   {
00077     ROS_ERROR("The map does not contain a negate tag or it is invalid.");
00078     exit(-1);
00079   }
00080   try
00081   {
00082     doc["occupied_thresh"] >> occThresh;
00083   }
00084   catch (YAML::InvalidScalar &)
00085   {
00086     ROS_ERROR("The map does not contain an occupied_thresh tag or it is invalid.");
00087     exit(-1);
00088   }
00089   try
00090   {
00091     doc["free_thresh"] >> freeThresh;
00092   }
00093   catch (YAML::InvalidScalar &)
00094   {
00095     ROS_ERROR("The map does not contain a free_thresh tag or it is invalid.");
00096     exit(-1);
00097   }
00098   try
00099   {
00100     doc["origin"][0] >> origin[0];
00101     doc["origin"][1] >> origin[1];
00102     doc["origin"][2] >> origin[2];
00103   }
00104   catch (YAML::InvalidScalar &)
00105   {
00106     ROS_ERROR("The map does not contain an origin tag or it is invalid.");
00107     exit(-1);
00108   }
00109 
00110   service = n.advertiseService("static_map", &plannerMapServer::mapCallback, this);
00111 
00112   // Latched publisher for metadata
00113   metadataPublisher = n.advertise<nav_msgs::MapMetaData>("map_metadata", 1, true);
00114   metadataPublisher.publish(metaDataMessage);
00115 
00116   // Latched publisher for data
00117   mapPublisher = n.advertise<nav_msgs::OccupancyGrid>("/map", 1, true);
00118 
00119   //Subscriber to update the map from new images
00120   mapImageSubscriber = n.subscribe("/image_calibration/image_cal", 1, &plannerMapServer::mapUpdateCallback, this);
00121 }
00122 
00123 void plannerMapServer::mapUpdateCallback(const sensor_msgs::Image& mapImg)
00124 {
00125   cv_bridge::CvImagePtr cvPtr = cv_bridge::toCvCopy(mapImg, "bgr8");
00126   cv::flip(cvPtr->image, cvPtr->image, 0);
00127   loadMapFromMat(&mapResponse, &cvPtr->image, resolution, negate, occThresh, freeThresh, origin);
00128 
00129   mapResponse.map.info.map_load_time = ros::Time::now();
00130   mapResponse.map.header.frame_id = frameID;
00131   mapResponse.map.header.stamp = ros::Time::now();
00132   metaDataMessage = mapResponse.map.info;
00133 
00134   metadataPublisher.publish(metaDataMessage);
00135   mapPublisher.publish(mapResponse.map);
00136 }
00137 
00138 bool plannerMapServer::mapCallback(nav_msgs::GetMap::Request &req, nav_msgs::GetMap::Response &res)
00139 {
00140   // = operator is overloaded to make deep copy (tricky!)
00141   res = mapResponse;
00142   ROS_INFO("Sending map");
00143 
00144   return true;
00145 }
00146 
00147 void plannerMapServer::loadMapFromMat(nav_msgs::GetMap::Response* resp, cv::Mat *opencvimg, double res, bool negate,
00148                                       double occThresh, double freeThresh, double* origin)
00149 {
00150   unsigned char* pixels;
00151   unsigned char* p;
00152   int rowstride, n_channels;
00153   unsigned int i, j;
00154   int k;
00155   double occ;
00156   int color_sum;
00157   double color_avg;
00158 
00159   // Copy the image data into the map structure
00160   resp->map.info.width = opencvimg->cols;
00161   resp->map.info.height = opencvimg->rows;
00162   resp->map.info.resolution = res;
00163   resp->map.info.origin.position.x = *(origin);
00164   resp->map.info.origin.position.y = *(origin + 1);
00165   resp->map.info.origin.position.z = 0.0;
00166   tf::Quaternion q;
00167   q.setRPY(0, 0, *(origin + 2));
00168   resp->map.info.origin.orientation.x = q.x();
00169   resp->map.info.origin.orientation.y = q.y();
00170   resp->map.info.origin.orientation.z = q.z();
00171   resp->map.info.origin.orientation.w = q.w();
00172 
00173   // Allocate space to hold the data
00174   resp->map.data.resize(resp->map.info.width * resp->map.info.height);
00175 
00176   // Get values that we'll need to iterate through the pixels
00177   rowstride = opencvimg->step;
00178   n_channels = opencvimg->channels();
00179 
00180   // Copy pixel data into the map structure
00181   pixels = (unsigned char*)(opencvimg->data);
00182   for (j = 0; j < resp->map.info.height; j++)
00183   {
00184     for (i = 0; i < resp->map.info.width; i++)
00185     {
00186       // Compute mean of RGB for this pixel
00187       p = pixels + j * rowstride + i * n_channels;
00188       color_sum = 0;
00189       for (k = 0; k < n_channels; k++)
00190         color_sum += *(p + (k));
00191       color_avg = color_sum / (double)n_channels;
00192 
00193       // If negate is true, we consider blacker pixels free, and whiter
00194       // pixels free.   Otherwise, it's vice versa.
00195       if (negate)
00196         occ = color_avg / 255.0;
00197       else
00198         occ = (255 - color_avg) / 255.0;
00199 
00200       // Apply thresholds to RGB means to determine occupancy values for
00201       // map.   Note that we invert the graphics-ordering of the pixels to
00202       // produce a map with cell (convert ipl to sdl0,0) in the lower-left corner.
00203       if (occ > occThresh)
00204         resp->map.data[MAP_IDX(resp->map.info.width,i,resp->map.info.height - j - 1)] = +100;
00205       else if (occ < freeThresh)
00206         resp->map.data[MAP_IDX(resp->map.info.width,i,resp->map.info.height - j - 1)] = 0;
00207       else
00208         resp->map.data[MAP_IDX(resp->map.info.width,i,resp->map.info.height - j - 1)] = -1;
00209     }
00210   }
00211 }
00212 
00216 int main(int argc, char **argv)
00217 {
00218   ros::init(argc, argv, "planner_map_server");
00219 
00220   plannerMapServer ms;
00221 
00222   ros::Rate loopRate(30);
00223   while (ros::ok())
00224   {
00225     ros::spinOnce();
00226     loopRate.sleep();
00227   }
00228 
00229   return 0;
00230 }
00231 


youbot_overhead_localization
Author(s): David Kent
autogenerated on Thu Jan 2 2014 12:14:20