Costmap2DConverter.hpp
Go to the documentation of this file.
1 /*
2  * CostmapConverter.hpp
3  *
4  * Created on: Nov 23, 2016
5  * Author: Peter Fankhauser, ETH Zurich
6  * Stefan Kohlbrecher, TU Darmstadt
7  * Daniel Stonier, Yujin Robot
8  */
9 
10 #pragma once
11 
13 
14 // ROS
15 #include <costmap_2d/costmap_2d.h>
17 #include <tf/tf.h>
18 
19 // STD
20 #include <vector>
21 
22 namespace grid_map {
23 
32 {
33  public:
35 
36  template<typename DataType>
37  static void create(std::vector<DataType>& costTranslationTable) {
38  costTranslationTable.resize(256);
39  for (unsigned int i = 0; i < costTranslationTable.size(); ++i ) {
40  costTranslationTable[i] = static_cast<DataType>(i);
41  }
42  }
43 };
44 
52 {
53  public:
55 
56  template<typename DataType>
57  static void create(std::vector<DataType>& costTranslationTable) {
58  costTranslationTable.resize(256);
59  costTranslationTable[0] = 0.0; // costmap_2d::FREE_SPACE;
60  costTranslationTable[253] = 99.0; // costmap_2d::INSCRIBED_INFLATED_OBSTACLE;
61  costTranslationTable[254] = 100.0; // costmap_2d::LETHAL_OBSTACLE
62  costTranslationTable[255] = -1.0; // costmap_2d::NO_INFORMATION
63 
64  // Regular cost values scale the range 1 to 252 (inclusive) to fit
65  // into 1 to 98 (inclusive).
66  for (int i = 1; i < 253; i++) {
67  costTranslationTable[i] = char(1 + (97 * (i - 1)) / 251);
68  }
69  }
70 };
71 
72 template<typename DataType>
74 
75 template<>
77 
78 /*****************************************************************************
79 ** Converter
80 *****************************************************************************/
81 
90 template<typename MapType, typename TranslationTable=Costmap2DDefaultTranslationTable<typename MapType::DataType>>
92 {
93 public:
94 
100  {
101  TranslationTable::create(costTranslationTable_);
102  }
103 
105  {
106  }
107 
108  void initializeFromCostmap2D(costmap_2d::Costmap2DROS& costmap2d, MapType& outputMap)
109  {
110  initializeFromCostmap2D(*(costmap2d.getCostmap()), outputMap);
111  outputMap.setFrameId(costmap2d.getGlobalFrameID());
112  }
113 
114  void initializeFromCostmap2D(const costmap_2d::Costmap2D& costmap2d, MapType& outputMap)
115  {
116  const double resolution = costmap2d.getResolution();
117  Length length(costmap2d.getSizeInCellsX()*resolution, costmap2d.getSizeInCellsY()*resolution);
118  Position position(costmap2d.getOriginX(), costmap2d.getOriginY());
119  // Different conventions.
120  position += Position(0.5 * length);
121  outputMap.setGeometry(length, resolution, position);
122  }
123 
133  const std::string& layer,
134  MapType& outputMap)
135  {
136  // Check compliance.
137  Size size(costmap2d.getSizeInCellsX(), costmap2d.getSizeInCellsY());
138  if ((outputMap.getSize() != size).any()) {
139  errorMessage_ = "Costmap2D and output map have different sizes!";
140  return false;
141  }
142  if (!outputMap.getStartIndex().isZero()) {
143  errorMessage_ = "Does not support non-zero start indices!";
144  return false;
145  }
146  // Copy data.
147  // Reverse iteration is required because of different conventions
148  // between Costmap2D and grid map.
149  typename MapType::Matrix data(size(0), size(1));
150  const size_t nCells = outputMap.getSize().prod();
151  for (size_t i = 0, j = nCells - 1; i < nCells; ++i, --j) {
152  const unsigned char cost = costmap2d.getCharMap()[j];
153  data(i) = (float) costTranslationTable_[cost];
154  }
155 
156  outputMap.add(layer, data);
157  return true;
158  }
159 
168  bool addLayerFromCostmap2D(costmap_2d::Costmap2DROS& costmap2d, const std::string& layer,
169  MapType& outputMap)
170  {
171  return addLayerFromCostmap2D(*(costmap2d.getCostmap()), layer, outputMap);
172  }
173 
190  MapType& outputMap)
191  {
192  const double resolution = costmap2d.getCostmap()->getResolution();
193 
194  // Get the Robot Pose Transform.
195 #if ROS_VERSION_MINIMUM(1,14,0)
196  geometry_msgs::PoseStamped tfPose;
197  if(!costmap2d.getRobotPose(tfPose))
198  {
199  errorMessage_ = "Could not get robot pose, is it actually published?";
200  return false;
201  }
202  Position robotPosition(tfPose.pose.position.x, tfPose.pose.position.y);
203 #else
204  tf::Stamped<tf::Pose> tfPose;
205  if(!costmap2d.getRobotPose(tfPose))
206  {
207  errorMessage_ = "Could not get robot pose, is it actually published?";
208  return false;
209  }
210  Position robotPosition(tfPose.getOrigin().x() , tfPose.getOrigin().y());
211 #endif
212  // Determine new costmap origin.
213  Position rosMapOrigin(costmap2d.getCostmap()->getOriginX(), costmap2d.getCostmap()->getOriginY());
214  Position newCostMapOrigin;
215 
216  // Note:
217  // You cannot directly use the robot pose as the new 'costmap center'
218  // since the underlying grid is not necessarily exactly aligned with
219  // that (two cases to consider, rolling window and globally fixed).
220  //
221  // Relevant diagrams:
222  // - https://github.com/anybotics/grid_map
223 
224  // Float versions of the cell co-ordinates, use static_cast<int> to get the indices.
225  Position robotCellPosition = (robotPosition - rosMapOrigin) / resolution;
226 
227  // if there is an odd number of cells
228  // centre of the new grid map in the centre of the current cell
229  // if there is an even number of cells
230  // centre of the new grid map at the closest vertex between cells
231  // of the current cell
232  int numberOfCellsX = length.x()/resolution;
233  int numberOfCellsY = length.y()/resolution;
234  if (numberOfCellsX % 2) { // odd
235  newCostMapOrigin(0) = std::floor(robotCellPosition.x())*resolution + resolution/2.0 + rosMapOrigin.x();
236  } else {
237  newCostMapOrigin(0) = std::round(robotCellPosition.x())*resolution + rosMapOrigin.x();
238  }
239  if (numberOfCellsY % 2) { // odd
240  newCostMapOrigin(1) = std::floor(robotCellPosition.y())*resolution + resolution/2.0 + rosMapOrigin.y();
241  } else {
242  newCostMapOrigin(1) = std::round(robotCellPosition.y())*resolution + rosMapOrigin.y();
243  }
244 
245  // TODO check the robot pose is in the window
246  // TODO check the geometry fits within the costmap2d window
247 
248  // Initialize the output map.
249  outputMap.setFrameId(costmap2d.getGlobalFrameID());
250  outputMap.setTimestamp(ros::Time::now().toNSec());
251  outputMap.setGeometry(length, resolution, newCostMapOrigin);
252  return true;
253  }
254 
265  const std::string& layer, MapType& outputMap)
266  {
267  /****************************************
268  ** Asserts
269  ****************************************/
270  if (outputMap.getResolution() != costmap2d.getCostmap()->getResolution()) {
271  errorMessage_ = "Costmap2D and output map have different resolutions!";
272  return false;
273  }
274  // 1) would be nice to check the output map centre has been initialised where it should be
275  // i.e. the robot pose didn't move since or the initializeFrom wasn't called
276  // but this would mean listening to tf's again and anyway, it gets shifted to make sure
277  // the costmaps align, so these wouldn't be exactly the same anyway
278  // 2) check the geometry fits inside the costmap2d subwindow is done below
279 
280  // Properties.
281  const double resolution = costmap2d.getCostmap()->getResolution();
282  const Length geometry = outputMap.getLength();
283  const Position position = outputMap.getPosition();
284 
285  // Copy data.
286  bool isValidWindow = false;
287  costmap_2d::Costmap2D costmapSubwindow;
288  // TODO
289  isValidWindow = costmapSubwindow.copyCostmapWindow(
290  *(costmap2d.getCostmap()),
291  position.x() - geometry.x() / 2.0, // subwindow_bottom_left_x
292  position.y() - geometry.y() / 2.0, // subwindow_bottom_left_y
293  geometry.x(),
294  geometry.y());
295  if (!isValidWindow) {
296  // handle differently - e.g. copy the internal part only and lethal elsewhere, but other parts would have to handle being outside too
297  errorMessage_ = "Subwindow landed outside the costmap, aborting.";
298  return false;
299  }
300  addLayerFromCostmap2D(costmapSubwindow, layer, outputMap);
301  return true;
302  }
303 
312  std::string errorMessage() const { return errorMessage_; }
313 
314 private:
315  std::vector<typename MapType::DataType> costTranslationTable_;
316  std::string errorMessage_;
317 };
318 
319 } // namespace grid_map
Convert Costmap2DRos objects into cost or grid maps.
bool getRobotPose(tf::Stamped< tf::Pose > &global_pose) const
std::string errorMessage() const
Human readable error message string.
void initializeFromCostmap2D(costmap_2d::Costmap2DROS &costmap2d, MapType &outputMap)
static void create(std::vector< DataType > &costTranslationTable)
Eigen::Array2i Size
std::string getGlobalFrameID()
double getOriginX() const
bool addLayerFromCostmap2DAtRobotPose(costmap_2d::Costmap2DROS &costmap2d, const std::string &layer, MapType &outputMap)
unsigned char * getCharMap() const
Eigen::Vector2d Position
std::vector< typename MapType::DataType > costTranslationTable_
bool addLayerFromCostmap2D(costmap_2d::Costmap2DROS &costmap2d, const std::string &layer, MapType &outputMap)
bool initializeFromCostmap2DAtRobotPose(costmap_2d::Costmap2DROS &costmap2d, const Length &length, MapType &outputMap)
Direct cost translations for costmap_2d -> grid/cost maps.
double getOriginY() const
unsigned int getSizeInCellsY() const
Matrix::Scalar DataType
bool copyCostmapWindow(const Costmap2D &map, double win_origin_x, double win_origin_y, double win_size_x, double win_size_y)
bool addLayerFromCostmap2D(const costmap_2d::Costmap2D &costmap2d, const std::string &layer, MapType &outputMap)
unsigned int getSizeInCellsX() const
static Time now()
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
Cost translations to [0, 100] for costmap_2d -> grid/cost maps.
double getResolution() const
Costmap2D * getCostmap()
void initializeFromCostmap2D(const costmap_2d::Costmap2D &costmap2d, MapType &outputMap)
static void create(std::vector< DataType > &costTranslationTable)
Eigen::Array2d Length


grid_map_costmap_2d
Author(s): Péter Fankhauser
autogenerated on Tue Jun 25 2019 20:02:11