RAPP Platform  v0.6.0
RAPP Platform is a collection of ROS nodes and back-end processes that aim to deliver ready-to-use generic services to robots
 All Classes Namespaces Files Functions Variables Macros
main.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* Author: Brian Gerkey */
31 
32 
33 /* modified by: Wojciech Dudek
34 
35  Now map_server changes the map that is being published. Path to the map is subscibed from the node_name+"/setMap" parameter.
36 */
37 
38 #define USAGE "\nUSAGE: map_server <map.yaml>\n" \
39  " map.yaml: map description file\n" \
40  "DEPRECATED USAGE: map_server <map> <resolution>\n" \
41  " map: image file to load\n"\
42  " resolution: map resolution [meters/pixel]"
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <libgen.h>
47 #include <fstream>
48 #include <boost/filesystem.hpp>
49 #include <sstream>
50 #include "ros/ros.h"
51 #include "ros/console.h"
53 #include "nav_msgs/MapMetaData.h"
54 #include "yaml-cpp/yaml.h"
55 #include "rapp_platform_ros_communications/MapServerGetMapRosSrv.h"
56 #include "rapp_platform_ros_communications/MapServerUploadMapRosSrv.h"
57 #include "std_srvs/Empty.h"
58 //get rapp-platform home directory
59 #include <unistd.h>
60 #include <sys/types.h>
61 #include <pwd.h>
62 
63 
64 #ifdef HAVE_NEW_YAMLCPP
65 // The >> operator disappeared in yaml-cpp 0.5, so this function is
66 // added to provide support for code written under the yaml-cpp 0.3 API.
67 template<typename T>
68 void operator >> (const YAML::Node& node, T& i)
69 {
70  i = node.as<T>();
71 }
72 #endif
73 
74 class MapServer
75 {
76  public:
78  MapServer(std::string fname)
79  {
80  if ((homedir = getenv("HOME")) == NULL) {
81  homedir = getpwuid(getuid())->pw_dir;
82  }
83  map_pub = n.advertise<nav_msgs::OccupancyGrid>("/map", 1, true);
84 
85  bool update_status = updateMap(fname,0);
86  std::string node_name = ros::this_node::getName();
87 
88  get_service = n.advertiseService(node_name+"/get_map", &MapServer::mapCallback, this);
89  //
90  // check if the map_upload service should be advertised
91  //
92  upload_map_trigger_name = "/"+node_name+"/upload_map_trigger";
93  if (n.hasParam(upload_map_trigger_name)){
95  }else{
96  upload_map_trigger = false;
97  }
98  if (upload_map_trigger){
99  upload_service = n.advertiseService(node_name+"/upload_map", &MapServer::mapUploadCallback, this);
100  }
101  // Latched publisher for metadata
102  metadata_pub= n.advertise<nav_msgs::MapMetaData>("map_metadata", 1, true);
103  metadata_pub.publish( meta_data_message_ );
104 
105  // Latched publisher for data
106  map_pub.publish( map_resp_.map );
107 
108  }
109 
110  private:
111  const char *homedir;
114  ros::NodeHandle n;
115  ros::Publisher map_pub;
116  ros::Publisher metadata_pub;
118  std::string fname;
120 
121  bool mapUploadCallback(rapp_platform_ros_communications::MapServerUploadMapRosSrv::Request &req,
122  rapp_platform_ros_communications::MapServerUploadMapRosSrv::Response &res)
123  {
124 
125  YAML::Node yaml_node;
126  yaml_node["image"] = req.map_name+".png";
127  yaml_node["resolution"] = req.resolution;
128  yaml_node["origin"] = req.origin;
129  yaml_node["negate"] = req.negate;
130  yaml_node["occupied_thresh"] = req.occupied_thresh;
131 
132 
133  std::ostringstream ss;
134  yaml_node["free_thresh"] = req.free_thresh;
135 
136  std::string user = req.user_name;
137  std::string map = req.map_name;
138  std::string homedir_str = homedir;
139  std::string map_path = homedir_str+"/rapp_platform_files/maps/"+user;
140 
141  boost::filesystem::create_directories(map_path);
142  std::string yaml_path = map_path+"/"+map+".yaml";
143  std::ofstream fout(yaml_path.c_str());
144  fout << yaml_node;
145  std::string png_path = map_path+"/"+map+".png";
146 
147  std::ofstream outfile (png_path.c_str(),std::ofstream::binary);
148 
149  char* buffer = reinterpret_cast<char*>(req.data.data());
150  long size = strlen(buffer);
151  // write to outfile
152  ROS_INFO_STREAM ("User: "<<user<< " saved map: "<< png_path << "\n size of the map: " << req.file_size << " bytes" );
153 
154  outfile.write (buffer,req.file_size);
155 
156  // // release dynamically-allocated memory
157  outfile.close();
158  res.status = true;
159  return true;
160  }
162  bool mapCallback(rapp_platform_ros_communications::MapServerGetMapRosSrv::Request &req,
163  rapp_platform_ros_communications::MapServerGetMapRosSrv::Response &res )
164  {
165  // request is empty; we ignore it
166  std::string node_name = ros::this_node::getName();
167  std::string param_name = node_name+"/setMap";
168 
169  const char * param_name_char = param_name.c_str();
170 
171  if (n.hasParam(param_name_char)){
172  n.getParam(param_name_char,fname);
173  updateMap(req.map_path,0);
174  }
175  res.map = map_resp_.map;
176  return true;
177  }
178  bool updateMap(const std::string fname, double res){
179  std::string mapfname = "";
180  double origin[3];
181  int negate;
182  double occ_th, free_th;
183  bool trinary = true;
184  std::string frame_id;
185  ros::NodeHandle private_nh("~");
186  private_nh.param("frame_id", frame_id, std::string("map"));
187  deprecated = false;//(res != 0);
188  if (!deprecated) {
189  std::ifstream fin(fname.c_str());
190  if (fin.fail()) {
191  ROS_ERROR("Map_server could not open %s.", fname.c_str());
192  exit(-1);
193  }
194 #ifdef HAVE_NEW_YAMLCPP
195  // The document loading process changed in yaml-cpp 0.5.
196  YAML::Node doc = YAML::Load(fin);
197 #else
198  YAML::Parser parser(fin);
199  YAML::Node doc;
200  parser.GetNextDocument(doc);
201 #endif
202  try {
203  doc["resolution"] >> res;
204  } catch (YAML::InvalidScalar) {
205  ROS_ERROR("The map does not contain a resolution tag or it is invalid.");
206  exit(-1);
207  }
208  try {
209  doc["negate"] >> negate;
210  } catch (YAML::InvalidScalar) {
211  ROS_ERROR("The map does not contain a negate tag or it is invalid.");
212  exit(-1);
213  }
214  try {
215  doc["occupied_thresh"] >> occ_th;
216  } catch (YAML::InvalidScalar) {
217  ROS_ERROR("The map does not contain an occupied_thresh tag or it is invalid.");
218  exit(-1);
219  }
220  try {
221  doc["free_thresh"] >> free_th;
222  } catch (YAML::InvalidScalar) {
223  ROS_ERROR("The map does not contain a free_thresh tag or it is invalid.");
224  exit(-1);
225  }
226  try {
227  doc["trinary"] >> trinary;
228  } catch (YAML::Exception) {
229  ROS_DEBUG("The map does not contain a trinary tag or it is invalid... assuming true");
230  trinary = true;
231  }
232  try {
233  doc["origin"][0] >> origin[0];
234  doc["origin"][1] >> origin[1];
235  doc["origin"][2] >> origin[2];
236  } catch (YAML::InvalidScalar) {
237  ROS_ERROR("The map does not contain an origin tag or it is invalid.");
238  exit(-1);
239  }
240  try {
241  doc["image"] >> mapfname;
242  // TODO: make this path-handling more robust
243  if(mapfname.size() == 0)
244  {
245  ROS_ERROR("The image tag cannot be an empty string.");
246  exit(-1);
247  }
248  if(mapfname[0] != '/')
249  {
250  // dirname can modify what you pass it
251  char* fname_copy = strdup(fname.c_str());
252  mapfname = std::string(dirname(fname_copy)) + '/' + mapfname;
253  free(fname_copy);
254  }
255  } catch (YAML::InvalidScalar) {
256  ROS_ERROR("The map does not contain an image tag or it is invalid.");
257  exit(-1);
258  }
259  } else {
260  private_nh.param("negate", negate, 0);
261  private_nh.param("occupied_thresh", occ_th, 0.65);
262  private_nh.param("free_thresh", free_th, 0.196);
263  mapfname = fname;
264  origin[0] = origin[1] = origin[2] = 0.0;
265  }
266 
267  ROS_INFO("Loading map from image \"%s\"", mapfname.c_str());
268  map_server::loadMapFromFile(&map_resp_,mapfname.c_str(),res,negate,occ_th,free_th, origin, trinary);
269 
270  map_resp_.map.info.map_load_time = ros::Time::now();
271  map_resp_.map.header.frame_id = frame_id;
272  map_resp_.map.header.stamp = ros::Time::now();
273  ROS_INFO("Read a %d X %d map @ %.3lf m/cell",
274  map_resp_.map.info.width,
275  map_resp_.map.info.height,
276  map_resp_.map.info.resolution);
277  meta_data_message_ = map_resp_.map.info;
278  map_pub.publish( map_resp_.map );
279 
280  return true;
281  }
284  nav_msgs::MapMetaData meta_data_message_;
285  nav_msgs::GetMap::Response map_resp_;
286 
287 };
288 int main(int argc, char **argv)
289 {
290  ros::init(argc, argv, "map_server");
291  if(argc != 3 && argc != 2)
292  {
293  ROS_ERROR("%s", USAGE);
294  exit(-1);
295  }
296  if (argc != 2) {
297  ROS_WARN("Using deprecated map server interface. Please switch to new interface.");
298  }
299  std::string fname(argv[1]);
300  double res = (argc == 2) ? 0.0 : atof(argv[2]);
301 
302  try
303  {
304  MapServer ms(fname);
305 
306  ros::spin();
307  }
308  catch(std::runtime_error& e)
309  {
310  ROS_ERROR("map_server exception: %s", e.what());
311  return -1;
312  }
313 
314  return 0;
315 }
316 
317 
ros::Publisher metadata_pub
Definition: main.cpp:116
bool deprecated
Definition: main.cpp:119
MapServer(std::string fname)
Definition: main.cpp:78
const char * homedir
Definition: main.cpp:111
int main(int argc, char **argv)
Definition: main.cpp:288
bool updateMap(const std::string fname, double res)
Definition: main.cpp:178
nav_msgs::MapMetaData meta_data_message_
Definition: main.cpp:284
void loadMapFromFile(nav_msgs::GetMap::Response *resp, const char *fname, double res, bool negate, double occ_th, double free_th, double *origin, bool trinary=true)
std::string fname
Definition: main.cpp:118
#define USAGE
Definition: main.cpp:38
nav_msgs::GetMap::Response map_resp_
Definition: main.cpp:285
bool mapUploadCallback(rapp_platform_ros_communications::MapServerUploadMapRosSrv::Request &req, rapp_platform_ros_communications::MapServerUploadMapRosSrv::Response &res)
Definition: main.cpp:121
ros::ServiceServer test_service
Definition: main.cpp:117
list origin
Definition: crop_map.py:62
bool upload_map_trigger
Definition: main.cpp:113
ros::ServiceServer upload_service
Definition: main.cpp:117
ros::Publisher map_pub
Definition: main.cpp:115
ros::NodeHandle n
Definition: main.cpp:114
ros::ServiceServer get_service
Definition: main.cpp:117
std::string upload_map_trigger_name
Definition: main.cpp:112
bool mapCallback(rapp_platform_ros_communications::MapServerGetMapRosSrv::Request &req, rapp_platform_ros_communications::MapServerGetMapRosSrv::Response &res)
Definition: main.cpp:162