Costmap2DConverter.hpp
Go to the documentation of this file.
00001 /*
00002  * CostmapConverter.hpp
00003  *
00004  *  Created on: Nov 23, 2016
00005  *      Author: Peter Fankhauser, ETH Zurich
00006  *              Stefan Kohlbrecher, TU Darmstadt
00007  *              Daniel Stonier, Yujin Robot
00008  */
00009 
00010 #pragma once
00011 
00012 #include <grid_map_core/grid_map_core.hpp>
00013 
00014 // ROS
00015 #include <costmap_2d/costmap_2d.h>
00016 #include <costmap_2d/costmap_2d_ros.h>
00017 #include <tf/tf.h>
00018 
00019 // STD
00020 #include <vector>
00021 
00022 namespace grid_map {
00023 
00031 class Costmap2DDirectTranslationTable
00032 {
00033  public:
00034   Costmap2DDirectTranslationTable() {}
00035 
00036   template<typename DataType>
00037   static void create(std::vector<DataType>& costTranslationTable) {
00038     costTranslationTable.resize(256);
00039     for (unsigned int i = 0; i < costTranslationTable.size(); ++i ) {
00040       costTranslationTable[i] = static_cast<DataType>(i);
00041     }
00042   }
00043 };
00044 
00051 class Costmap2DCenturyTranslationTable
00052 {
00053  public:
00054   Costmap2DCenturyTranslationTable() {}
00055 
00056   template<typename DataType>
00057   static void create(std::vector<DataType>& costTranslationTable) {
00058     costTranslationTable.resize(256);
00059     costTranslationTable[0] = 0.0;     // costmap_2d::FREE_SPACE;
00060     costTranslationTable[253] = 99.0;  // costmap_2d::INSCRIBED_INFLATED_OBSTACLE;
00061     costTranslationTable[254] = 100.0; // costmap_2d::LETHAL_OBSTACLE
00062     costTranslationTable[255] = -1.0;  // costmap_2d::NO_INFORMATION
00063 
00064     // Regular cost values scale the range 1 to 252 (inclusive) to fit
00065     // into 1 to 98 (inclusive).
00066     for (int i = 1; i < 253; i++) {
00067       costTranslationTable[i] = char(1 + (97 * (i - 1)) / 251);
00068     }
00069   }
00070 };
00071 
00072 template<typename DataType>
00073 class Costmap2DDefaultTranslationTable : public Costmap2DDirectTranslationTable {};
00074 
00075 template<>
00076 class Costmap2DDefaultTranslationTable<float> : public Costmap2DCenturyTranslationTable {};
00077 
00078 /*****************************************************************************
00079 ** Converter
00080 *****************************************************************************/
00081 
00090 template<typename MapType, typename TranslationTable=Costmap2DDefaultTranslationTable<typename MapType::DataType>>
00091 class Costmap2DConverter
00092 {
00093 public:
00094 
00099   Costmap2DConverter()
00100   {
00101     TranslationTable::create(costTranslationTable_);
00102   }
00103 
00104   virtual ~Costmap2DConverter()
00105   {
00106   }
00107 
00108   void initializeFromCostmap2D(costmap_2d::Costmap2DROS& costmap2d, MapType& outputMap)
00109   {
00110     initializeFromCostmap2D(*(costmap2d.getCostmap()), outputMap);
00111     outputMap.setFrameId(costmap2d.getGlobalFrameID());
00112   }
00113 
00114   void initializeFromCostmap2D(const costmap_2d::Costmap2D& costmap2d, MapType& outputMap)
00115   {
00116     const double resolution = costmap2d.getResolution();
00117     Length length(costmap2d.getSizeInCellsX()*resolution, costmap2d.getSizeInCellsY()*resolution);
00118     Position position(costmap2d.getOriginX(), costmap2d.getOriginY());
00119     // Different conventions.
00120     position += Position(0.5 * length);
00121     outputMap.setGeometry(length, resolution, position);
00122   }
00123 
00132   bool addLayerFromCostmap2D(const costmap_2d::Costmap2D& costmap2d,
00133                              const std::string& layer,
00134                              MapType& outputMap)
00135   {
00136     // Check compliance.
00137     Size size(costmap2d.getSizeInCellsX(), costmap2d.getSizeInCellsY());
00138     if ((outputMap.getSize() != size).any()) {
00139       errorMessage_ = "Costmap2D and output map have different sizes!";
00140       return false;
00141     }
00142     if (!outputMap.getStartIndex().isZero()) {
00143       errorMessage_ = "Does not support non-zero start indices!";
00144       return false;
00145     }
00146     // Copy data.
00147     // Reverse iteration is required because of different conventions
00148     // between Costmap2D and grid map.
00149     typename MapType::Matrix data(size(0), size(1));
00150     const size_t nCells = outputMap.getSize().prod();
00151     for (size_t i = 0, j = nCells - 1; i < nCells; ++i, --j) {
00152       const unsigned char cost = costmap2d.getCharMap()[j];
00153       data(i) = (float) costTranslationTable_[cost];
00154     }
00155 
00156     outputMap.add(layer, data);
00157     return true;
00158   }
00159 
00168   bool addLayerFromCostmap2D(costmap_2d::Costmap2DROS& costmap2d, const std::string& layer,
00169                              MapType& outputMap)
00170   {
00171     return addLayerFromCostmap2D(*(costmap2d.getCostmap()), layer, outputMap);
00172   }
00173 
00189   bool initializeFromCostmap2DAtRobotPose(costmap_2d::Costmap2DROS& costmap2d, const Length& length,
00190                                           MapType& outputMap)
00191   {
00192     const double resolution = costmap2d.getCostmap()->getResolution();
00193 
00194     // Get the Robot Pose Transform.
00195 #if ROS_VERSION_MINIMUM(1,14,0)
00196     geometry_msgs::PoseStamped tfPose;
00197     if(!costmap2d.getRobotPose(tfPose))
00198     {
00199       errorMessage_ =  "Could not get robot pose, is it actually published?";
00200       return false;
00201     }
00202     Position robotPosition(tfPose.pose.position.x, tfPose.pose.position.y);
00203 #else
00204     tf::Stamped<tf::Pose> tfPose;
00205     if(!costmap2d.getRobotPose(tfPose))
00206     {
00207       errorMessage_ =  "Could not get robot pose, is it actually published?";
00208       return false;
00209     }
00210     Position robotPosition(tfPose.getOrigin().x() , tfPose.getOrigin().y());
00211 #endif
00212     // Determine new costmap origin.
00213     Position rosMapOrigin(costmap2d.getCostmap()->getOriginX(), costmap2d.getCostmap()->getOriginY());
00214     Position newCostMapOrigin;
00215 
00216     // Note:
00217     //   You cannot directly use the robot pose as the new 'costmap center'
00218     //   since the underlying grid is not necessarily exactly aligned with
00219     //   that (two cases to consider, rolling window and globally fixed).
00220     //
00221     // Relevant diagrams:
00222     //  - https://github.com/anybotics/grid_map
00223 
00224     // Float versions of the cell co-ordinates, use static_cast<int> to get the indices.
00225     Position robotCellPosition = (robotPosition - rosMapOrigin) / resolution;
00226 
00227     // if there is an odd number of cells
00228     //   centre of the new grid map in the centre of the current cell
00229     // if there is an even number of cells
00230     //   centre of the new grid map at the closest vertex between cells
00231     // of the current cell
00232     int numberOfCellsX = length.x()/resolution;
00233     int numberOfCellsY = length.y()/resolution;
00234     if (numberOfCellsX % 2) {  // odd
00235       newCostMapOrigin(0) = std::floor(robotCellPosition.x())*resolution + resolution/2.0 + rosMapOrigin.x();
00236     } else {
00237       newCostMapOrigin(0) = std::round(robotCellPosition.x())*resolution + rosMapOrigin.x();
00238     }
00239     if (numberOfCellsY % 2) {  // odd
00240       newCostMapOrigin(1) = std::floor(robotCellPosition.y())*resolution + resolution/2.0 + rosMapOrigin.y();
00241     } else {
00242       newCostMapOrigin(1) = std::round(robotCellPosition.y())*resolution + rosMapOrigin.y();
00243     }
00244 
00245     // TODO check the robot pose is in the window
00246     // TODO check the geometry fits within the costmap2d window
00247 
00248     // Initialize the output map.
00249     outputMap.setFrameId(costmap2d.getGlobalFrameID());
00250     outputMap.setTimestamp(ros::Time::now().toNSec());
00251     outputMap.setGeometry(length, resolution, newCostMapOrigin);
00252     return true;
00253   }
00254 
00264   bool addLayerFromCostmap2DAtRobotPose(costmap_2d::Costmap2DROS& costmap2d,
00265                                         const std::string& layer, MapType& outputMap)
00266   {
00267     /****************************************
00268     ** Asserts
00269     ****************************************/
00270     if (outputMap.getResolution() != costmap2d.getCostmap()->getResolution()) {
00271       errorMessage_ = "Costmap2D and output map have different resolutions!";
00272       return false;
00273     }
00274     // 1) would be nice to check the output map centre has been initialised where it should be
00275     //      i.e. the robot pose didn't move since or the initializeFrom wasn't called
00276     //    but this would mean listening to tf's again and anyway, it gets shifted to make sure
00277     //    the costmaps align, so these wouldn't be exactly the same anyway
00278     // 2) check the geometry fits inside the costmap2d subwindow is done below
00279 
00280     // Properties.
00281     const double resolution = costmap2d.getCostmap()->getResolution();
00282     const Length geometry = outputMap.getLength();
00283     const Position position = outputMap.getPosition();
00284 
00285     // Copy data.
00286     bool isValidWindow = false;
00287     costmap_2d::Costmap2D costmapSubwindow;
00288     // TODO
00289     isValidWindow = costmapSubwindow.copyCostmapWindow(
00290                             *(costmap2d.getCostmap()),
00291                             position.x() - geometry.x() / 2.0, // subwindow_bottom_left_x
00292                             position.y() - geometry.y() / 2.0, // subwindow_bottom_left_y
00293                             geometry.x(),
00294                             geometry.y());
00295     if (!isValidWindow) {
00296       // handle differently - e.g. copy the internal part only and lethal elsewhere, but other parts would have to handle being outside too
00297       errorMessage_ = "Subwindow landed outside the costmap, aborting.";
00298       return false;
00299     }
00300     addLayerFromCostmap2D(costmapSubwindow, layer, outputMap);
00301     return true;
00302   }
00303 
00312   std::string errorMessage() const { return errorMessage_; }
00313 
00314 private:
00315   std::vector<typename MapType::DataType> costTranslationTable_;
00316   std::string errorMessage_;
00317 };
00318 
00319 } // namespace grid_map


grid_map_costmap_2d
Author(s): Péter Fankhauser
autogenerated on Tue Jul 9 2019 05:06:21