saver.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2020, Locus Robotics
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include <ros/ros.h>
39 #include <boost/filesystem.hpp>
40 #include <opencv2/core/core.hpp>
41 #include <opencv2/highgui/highgui.hpp>
42 #include <fstream>
43 #include <string>
44 #include <vector>
45 
46 class MapSaver
47 {
48 public:
50  {
51  ros::NodeHandle nh, private_nh("~");
52 
53  // Load settings from the parameter server
54  std::string topic;
55  bool use_nav_grid;
56  private_nh.param("topic", topic, std::string("map"));
57  private_nh.param("nav_grid", use_nav_grid, false);
58  private_nh.param("once", once_, true);
59  private_nh.param("write_unstamped", write_unstamped_, true);
60  private_nh.param("write_stamped", write_stamped_, false);
62  {
63  ROS_FATAL_NAMED("MapSaver", "write_unstamped and write_stamped both set to false. Nothing will be written.");
64  exit(EXIT_FAILURE);
65  }
66 
67  bool trinary_output;
68  private_nh.param("trinary_output", trinary_output, true);
69  if (trinary_output)
70  {
72  }
73  else
74  {
76  }
77 
78  private_nh.param("map_extension", map_extension_, std::string("png"));
79  private_nh.param("map_prefix", map_prefix_, std::string("map"));
80  std::string output_directory_str;
81  private_nh.param("output_directory", output_directory_str, std::string("."));
82  output_directory_ = boost::filesystem::path(output_directory_str);
83  // Create the output folder
84  try
85  {
86  boost::filesystem::create_directories(output_directory_);
87  }
88  catch (const std::exception& e)
89  {
90  ROS_FATAL_STREAM("Unable to create the requested output directory (" + output_directory_.string() + "). "
91  "Error: " + e.what());
92  exit(EXIT_FAILURE);
93  }
94 
95  ROS_INFO_NAMED("MapSaver", "Waiting for the map");
97  map_sub_.init(nh, std::bind(&MapSaver::newDataCallback, this, std::placeholders::_1), topic, use_nav_grid, !once_);
98  }
99 
100  boost::filesystem::path generatePath(const std::string& extension, const ros::Time& stamp) const
101  {
102  boost::filesystem::path output;
103  if (stamp == ros::Time())
104  {
105  output = output_directory_ / boost::filesystem::path(map_prefix_ + "." + extension);
106  }
107  else
108  {
109  std::stringstream ss;
110  ss << map_prefix_ << "-" << std::setw(10) << std::setfill('0') << stamp.sec << "." << extension;
111  output = output_directory_ / boost::filesystem::path(ss.str());
112  }
113  return output;
114  }
115 
117  {
118  const nav_grid::NavGridInfo& info = data_.getInfo();
119  ROS_INFO_NAMED("MapSaver", "Writing a new map: %s", info.toString().c_str());
120 
121  // Convert nav_grid into an opencv image
122  cv::Mat image(info.height, info.width, CV_8UC1);
123  for (unsigned int row = 0; row < info.height; ++row)
124  {
125  unsigned char* output_row = image.ptr<unsigned char>(row);
126  for (unsigned int col = 0; col < info.width; ++col)
127  {
128  unsigned char input = data_(col, info.height - row - 1); // flip vertically
130  }
131  }
132 
133  // Save output image and yaml
134  if (write_unstamped_)
135  {
136  writeData(ros::Time(), image, info);
137  }
138 
139  if (write_stamped_)
140  {
141  writeData(ros::Time::now(), image, info);
142  }
143  written_once_ = true;
144  }
145 
146  void writeData(const ros::Time& stamp, const cv::Mat& image, const nav_grid::NavGridInfo& info) const
147  {
148  // Save the Image
149  auto map_path = generatePath(map_extension_, stamp);
150  cv::imwrite(map_path.string(), image);
151 
152  // Save the yaml file
153  auto yaml_path = generatePath("yaml", stamp);
154  std::ofstream yaml_file(yaml_path.c_str(), std::ofstream::out);
155  if (yaml_file.is_open())
156  {
157  yaml_file << "image: " << map_path.filename().string() << "\n";
158  yaml_file << "resolution: " << info.resolution << "\n";
159  yaml_file << "origin: [" << info.origin_x << ", " << info.origin_y << ", 0]\n";
160  yaml_file << "occupied_thresh: 0.65\n";
161  yaml_file << "free_thresh: 0.196\n";
162  yaml_file << "negate: 0\n";
163  yaml_file.close();
164  }
165  else
166  {
167  ROS_WARN_STREAM_THROTTLE(10.0, "Could not open output file '" + yaml_path.string() + "'");
168  }
169  }
170 
171  void spin()
172  {
173  // Keep spinning unless we just want to run once and we wrote our map once
174  while (ros::ok() && !(once_ && written_once_))
175  ros::spinOnce();
176  }
177 
178 protected:
182  boost::filesystem::path output_directory_;
184  std::vector<unsigned char> output_interpretation_;
185 };
186 
187 int main(int argc, char** argv)
188 {
189  ros::init(argc, argv, "map_saver");
190  MapSaver ms;
191  ms.spin();
192  return 0;
193 }
#define ROS_INFO_NAMED(name,...)
std::string map_extension_
Definition: saver.cpp:181
nav_grid::VectorNavGrid< unsigned char > data_
Definition: saver.cpp:180
std::string toString() const
void setCostInterpretation(const std::vector< NumericType > &cost_interpretation_table)
NumericType interpretCost(IntegralType original_value, const std::vector< NumericType > &cost_interpretation_table)
boost::filesystem::path output_directory_
Definition: saver.cpp:182
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void newDataCallback(const nav_core2::UIntBounds &bounds)
Definition: saver.cpp:116
static std::vector< unsigned char > TRINARY_SAVE
void spin()
Definition: saver.cpp:171
bool once_
Definition: saver.cpp:183
int main(int argc, char **argv)
Definition: saver.cpp:187
std::string map_prefix_
Definition: saver.cpp:181
bool write_stamped_
Definition: saver.cpp:183
static std::vector< unsigned char > SCALE_SAVE
nav_grid_pub_sub::NavGridSubscriber map_sub_
Definition: saver.cpp:179
void writeData(const ros::Time &stamp, const cv::Mat &image, const nav_grid::NavGridInfo &info) const
Definition: saver.cpp:146
#define ROS_FATAL_STREAM(args)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ROSCPP_DECL bool ok()
boost::filesystem::path generatePath(const std::string &extension, const ros::Time &stamp) const
Definition: saver.cpp:100
bool write_unstamped_
Definition: saver.cpp:183
MapSaver()
Definition: saver.cpp:49
void init(ros::NodeHandle &nh, NewDataCallback callback, const std::string &topic="map", bool nav_grid=true, bool subscribe_to_updates=true)
#define ROS_WARN_STREAM_THROTTLE(rate, args)
std::vector< unsigned char > getOccupancyInput(bool trinary=false, bool use_unknown_value=false)
std::vector< unsigned char > output_interpretation_
Definition: saver.cpp:184
NavGridInfo getInfo() const
bool written_once_
Definition: saver.cpp:183
#define ROS_FATAL_NAMED(name,...)
static Time now()
ROSCPP_DECL void spinOnce()


nav_grid_server
Author(s):
autogenerated on Sun Jan 10 2021 04:08:55