MapHelper.hpp
Go to the documentation of this file.
00001 
00020 #pragma once
00021 
00022 #include <ros/ros.h>
00023 #include <nav_msgs/GetMap.h>
00024 #include <nav_msgs/OccupancyGrid.h>
00025 #include <nav_msgs/Path.h>
00026 #include <nav_msgs/GetPlan.h>
00027 #include <geometry_msgs/PoseStamped.h>
00028 #include <cmath>
00029 #include <vector>
00030 #include <boost/tuple/tuple.hpp>
00031 #include <costmap_2d/costmap_2d_ros.h>
00032 #include <tf/transform_listener.h>
00033 #include "robot_model_services/helper/DebugHelper.hpp"
00034 #include "robot_model_services/helper/MathHelper.hpp"
00035 #include "robot_model_services/helper/TypeHelper.hpp"
00036 #include "robot_model_services/typedef.hpp"
00037 
00038 namespace robot_model_services {
00039         struct RayTracingIndex {
00040                 int32_t x;
00041                 int32_t y;
00042                 int8_t occupancy;
00043         public:
00044                 static bool topologicalCompare(const RayTracingIndex &source, const RayTracingIndex &firstIndex, const RayTracingIndex &secondIndex) {
00045                         SimpleVector2 sourceVector(source.x, source.y);
00046                         SimpleVector2 firstIndexVector(firstIndex.x, firstIndex.y);
00047                         SimpleVector2 secondIndexVector(secondIndex.x, secondIndex.y);
00048 
00049                         return (firstIndexVector - sourceVector).squaredNorm() < (secondIndexVector - sourceVector).squaredNorm();
00050                 }
00051 
00052                 static bool equals(const RayTracingIndex &firstIndex, const RayTracingIndex &secondIndex) {
00053                         SimpleVector2 firstIndexVector(firstIndex.x, firstIndex.y);
00054                         SimpleVector2 secondIndexVector(secondIndex.x, secondIndex.y);
00055                         return firstIndexVector == secondIndexVector;
00056                 }
00057         };
00058         typedef boost::shared_ptr<RayTracingIndex> RayTracingIndexPtr;
00059         typedef std::vector<RayTracingIndex> Ray;
00060 
00061 
00062         class MapHelper {
00063         private:
00064         DebugHelperPtr mDebugHelperPtr;
00065 
00066         bool mMapReceived;
00067                 int8_t mCollisionThreshold;
00068                 ros::NodeHandle mGlobalNodeHandle;
00069                 ros::ServiceClient mGetPlanServiceClient;
00070                 nav_msgs::OccupancyGrid mMap;
00071         costmap_2d::Costmap2D mCostmap;
00072         nav_msgs::OccupancyGrid mRaytracingMap;
00073         // table to translate from values 0-255 in Costmap2D to values -1 to 100 in OccupancyGrid
00074         int8_t mCostTranslationTable[256];
00075         public:
00076         MapHelper(const std::string &mapTopicName = "map", const std::string &getPlanServiceName = "move_base/make_plan") : mMapReceived(false), mCollisionThreshold(45) {
00077             mDebugHelperPtr = DebugHelper::getInstance();
00078 
00079             // set cost translation table
00080             mCostTranslationTable[0] = 0;  // NO obstacle
00081             mCostTranslationTable[253] = 99;  // INSCRIBED obstacle
00082             mCostTranslationTable[254] = 100;  // LETHAL obstacle
00083             mCostTranslationTable[255] = -1;  // UNKNOWN
00084 
00085             for (int i = 1; i < 253; i++) {
00086                 mCostTranslationTable[i] = int8_t(1 + (97 * (i - 1)) / 251);
00087             }
00088 
00089             ros::Subscriber mapSubscriber = mGlobalNodeHandle.subscribe<nav_msgs::OccupancyGrid>(mapTopicName, 1, &MapHelper::mapReceived, this);
00090             while(ros::ok() && !mMapReceived) {
00091                 mDebugHelperPtr->write(std::stringstream() << "Waiting for map to arrive on topic '" << mapSubscriber.getTopic() << "'",
00092                             DebugHelper::MAP);
00093 
00094                                 ros::spinOnce();
00095                                 ros::Duration(0.5).sleep();
00096                         }
00097 
00098             mDebugHelperPtr->write(std::stringstream() << "waiting for service: " << getPlanServiceName, DebugHelper::MAP);
00099             ros::service::waitForService(getPlanServiceName, -1);
00100                         mGetPlanServiceClient = mGlobalNodeHandle.serviceClient<nav_msgs::GetPlan>(getPlanServiceName, true);
00101                         while(ros::ok() && !mGetPlanServiceClient.exists()) {
00102                 mDebugHelperPtr->write(std::stringstream() << "Waiting for planning server to start on service '"
00103                                         << mGetPlanServiceClient.getService(), DebugHelper::MAP);
00104                                 ros::spinOnce();
00105                                 ros::Duration(0.5).sleep();
00106                         }
00107             this->setCostmap();
00108             this->aggregateRaytracingMap();
00109                 }
00110 
00111                 virtual ~MapHelper() { }
00112         private:
00113                 void mapReceived(nav_msgs::OccupancyGrid map) {
00114             mDebugHelperPtr->write("Map received", DebugHelper::MAP);
00115                         mMap = map;
00116                         mMapReceived = true;
00117             mDebugHelperPtr->write(std::stringstream() << "Map resolution: " << mMap.info.resolution, DebugHelper::MAP);
00118             mDebugHelperPtr->write(std::stringstream() << "Map translation: " << this->getTranslation(), DebugHelper::MAP);
00119             mDebugHelperPtr->write(std::stringstream() << "Map orientation: " << this->getOrientation().w() << ", "
00120                                                                                 << this->getOrientation().x() << ", "
00121                                                                                 << this->getOrientation().y() << ", "
00122                                                                                 << this->getOrientation().z(),
00123                                                                                                         DebugHelper::MAP);
00124             mDebugHelperPtr->write(std::stringstream() << "Map metric width: " << this->getMetricWidth(), DebugHelper::MAP);
00125             mDebugHelperPtr->write(std::stringstream() << "Map metric height: " << this->getMetricHeight(), DebugHelper::MAP);
00126                 }
00127 
00128         void setCostmap() {
00129             tf::TransformListener tf(ros::Duration(10));
00130             std::string name = "global_costmap";
00131             costmap_2d::Costmap2DROS costmapRos(name, tf);
00132             costmapRos.start();
00133             costmapRos.updateMap();
00134             costmapRos.stop();
00135 
00136             mCostmap = *(costmapRos.getCostmap());
00137 
00138             // get output path
00139             std::string path;
00140             mGlobalNodeHandle.getParam("/nbv/mMapsImagePath", path);
00141 
00142             // output costmap
00143             std::string costmapPath = path + "/costmap.pgm";
00144             mDebugHelperPtr->write("Outputting calculated costmap to " + costmapPath,
00145                         DebugHelper::MAP);
00146             mCostmap.saveMap(costmapPath);
00147         }
00148 
00149         void aggregateRaytracingMap() {
00150             mDebugHelperPtr->write("Aggregating raytracing map.", DebugHelper::MAP);
00151             if (mMap.info.width != mCostmap.getSizeInCellsX() || mMap.info.height != mCostmap.getSizeInCellsY()) {
00152                 ROS_ERROR("Cannot aggregate raytracing map. Dimensions of map and costmap do not match!");
00153                 mDebugHelperPtr->write(std::stringstream() << "Map size: " << mMap.info.width << "x" << mMap.info.height, DebugHelper::MAP);
00154                 mDebugHelperPtr->write(std::stringstream() << "Costmap size: " << mCostmap.getSizeInCellsX() << "x" << mCostmap.getSizeInCellsY(), DebugHelper::MAP);
00155                 assert(mMap.info.width == mCostmap.getSizeInCellsX() && mMap.info.height == mCostmap.getSizeInCellsY());
00156             }
00157 
00158             mRaytracingMap.info = mMap.info;
00159             mRaytracingMap.data.reserve(mMap.data.size());
00160             for (unsigned int y = 0; y < mMap.info.height; y++) {
00161                 for (unsigned int x = 0; x < mMap.info.width; x++) {
00162                     unsigned int index = y * mMap.info.width + x;
00163                     int8_t mapOccupancyValue = mMap.data[index];
00164                     int8_t costmapOccupancyValue = mCostTranslationTable[mCostmap.getCost(x, y)];
00165                     int8_t aggregatedOccupancyValue = mapOccupancyValue == -1 ? -1 : costmapOccupancyValue;
00166 
00167                     mRaytracingMap.data[index] = aggregatedOccupancyValue;
00168                 }
00169             }
00170             mDebugHelperPtr->write("Aggregation done.", DebugHelper::MAP);
00171         }
00172 
00173                 int8_t getOccupancyValue(const nav_msgs::OccupancyGrid &map, const SimpleVector3 &position) {
00174                         int32_t mapX, mapY;
00175                         this->worldToMapCoordinates(position, mapX, mapY);
00176                         return this->getOccupancyValue(map, mapX, mapY);
00177                 }
00178 
00179         int8_t getOccupancyValue(const costmap_2d::Costmap2D &costmap, const SimpleVector3 &position) {
00180             int32_t mapX, mapY;
00181             this->worldToMapCoordinates(position, mapX, mapY);
00182             return this->getOccupancyValue(costmap, mapX, mapY);
00183         }
00184 
00185                 int8_t getOccupancyValue(const nav_msgs::OccupancyGrid &map, const int32_t &mapX, const int32_t &mapY) {
00186                         uint32_t width = map.info.width;
00187                         uint32_t height = map.info.height;
00188 
00189             if (mapX < 0 || mapY < 0 || mapX >= (int32_t)width || mapY >= (int32_t)height) {
00190                                 return -1;
00191                         }
00192 
00193                         return map.data[mapX + mapY * width];
00194                 }
00195 
00196         int8_t getOccupancyValue(const costmap_2d::Costmap2D &costmap, const int32_t &mapX, const int32_t &mapY) {
00197             uint32_t width = costmap.getSizeInCellsX();
00198             uint32_t height = costmap.getSizeInCellsY();
00199 
00200             if (mapX < 0 || mapY < 0 || mapX >= (int32_t)width || mapY >= (int32_t)height) {
00201                 return -1;
00202             }
00203 
00204             unsigned char cost = costmap.getCost(mapX, mapY);
00205             return mCostTranslationTable[cost];
00206         }
00207 
00208         public:
00209                 int8_t getMapOccupancyValue(const SimpleVector3 &position) {
00210                         return this->getOccupancyValue(mMap, position);
00211                 }
00212 
00213                 int8_t getMapOccupancyValue(const int32_t &mapX, const int32_t &mapY) {
00214                         return this->getOccupancyValue(mMap, mapX, mapY);
00215                 }
00216 
00217 
00218                 int8_t getCostmapOccupancyValue(const SimpleVector3 &position) {
00219                         return this->getOccupancyValue(mCostmap, position);
00220                 }
00221 
00222                 int8_t getCostmapOccupancyValue(const int32_t &mapX, const int32_t &mapY) {
00223                         return this->getOccupancyValue(mCostmap, mapX, mapY);
00224                 }
00225 
00226 
00227                 int8_t getRaytracingMapOccupancyValue(const SimpleVector3 &position) {
00228                         return this->getOccupancyValue(mRaytracingMap, position);
00229                 }
00230 
00231                 int8_t getRaytracingMapOccupancyValue(const int32_t &mapX, const int32_t &mapY) {
00232                         return this->getOccupancyValue(mRaytracingMap, mapX, mapY);
00233                 }
00234 
00235                 bool doRaytracing(const SimpleVector3 &fromPoint, const SimpleVector3 &toPoint) {
00236                         Ray ray;
00237                         bool retVal = this->doRaytracing(fromPoint, toPoint, ray);
00238                         return retVal;
00239                 }
00240 
00241                 bool doRaytracing(const SimpleVector3 &fromPoint, const SimpleVector3 &toPoint, Ray &ray) {
00242                         // clear ray
00243                         ray.clear();
00244 
00245                         // get the discrete coordinates from world coordinates
00246                         int32_t fromMapX, fromMapY;
00247                         this->worldToMapCoordinates(fromPoint, fromMapX, fromMapY);
00248 
00249                         int32_t toMapX, toMapY;
00250                         this->worldToMapCoordinates(toPoint, toMapX, toMapY);
00251 
00252                         // calculate the distances
00253                         int32_t distanceX = toMapX - fromMapX;
00254                         int32_t distanceY = toMapY - fromMapY;
00255 
00256                         // return the result of a zero length raytracing
00257                         if (distanceX == 0 && distanceY == 0) {
00258                                 int8_t occupancyValue = this->getRaytracingMapOccupancyValue(fromMapX, fromMapY);
00259                                 return this->isOccupancyValueAcceptable(occupancyValue);
00260                         }
00261 
00262                         // get the bounds - needed to prevent non feasible results
00263                         int32_t minX = std::min(fromMapX, toMapX);
00264                         int32_t maxX = std::max(fromMapX, toMapX);
00265                         int32_t minY = std::min(fromMapY, toMapY);
00266                         int32_t maxY = std::max(fromMapY, toMapY);
00267 
00268                         // get the resolution
00269                         float resolution = mRaytracingMap.info.resolution;
00270 
00271                         // get the signum of the distance
00272                         int32_t signumX = distanceX < 0 ? - 1 : 1;
00273                         int32_t signumY = distanceY < 0 ? - 1 : 1;
00274 
00275                         // calculate the difference between the two points
00276                         SimpleVector2 diff = (toPoint - fromPoint).block<2, 1>(0, 0);
00277 
00278                         // contains the value about success of raytracing
00279                         bool rayTracingSucceeded = true;
00280 
00281                         // tracing along the x-axis
00282                         for (int32_t offsetX = 0; offsetX <= abs(distanceX) + 1 && diff[0] != 0; offsetX += 1) {
00283                                 double x = (fromMapX + signumX * offsetX) * resolution;
00284                                 double t = (x - fromPoint[0]) / diff[0];
00285                                 double y = fromPoint[1] + t * diff[1];
00286 
00287                                 RayTracingIndex idx;
00288                                 idx.x = (int32_t) (x / resolution);
00289                                 idx.y = (int32_t) (y / resolution);
00290                                 idx.occupancy = this->getRaytracingMapOccupancyValue(idx.x, idx.y);
00291 
00292                                 if (idx.x < minX || idx.x > maxX || idx.y < minY || idx.y > maxY) {
00293                                         continue;
00294                                 }
00295 
00296                                 if (!this->isOccupancyValueAcceptable(idx.occupancy)) {
00297                                         rayTracingSucceeded = false;
00298                                 }
00299 
00300                                 ray.push_back(idx);
00301                         }
00302 
00303                         // tracing along the y axis.
00304                         for (int32_t offsetY = 0; offsetY <= abs(distanceY) + 1 && diff[1] != 0; offsetY += 1) {
00305                                 double y = (fromMapY + signumY * offsetY) * resolution;
00306                                 double t = (y - fromPoint[1]) / diff[1];
00307                                 double x = fromPoint[0] + t * diff[0];
00308 
00309                                 RayTracingIndex idx;
00310                                 idx.x = (int32_t) (x / resolution);
00311                                 idx.y = (int32_t) (y / resolution);
00312                                 idx.occupancy = this->getRaytracingMapOccupancyValue(idx.x, idx.y);
00313 
00314                                 if (idx.x < minX || idx.x > maxX || idx.y < minY || idx.y > maxY) {
00315                                         continue;
00316                                 }
00317 
00318                                 if (!this->isOccupancyValueAcceptable(idx.occupancy)) {
00319                                         rayTracingSucceeded = false;
00320                                 }
00321 
00322                                 ray.push_back(idx);
00323                         }
00324 
00325                         // do a topological sort by distance to the fromPoint
00326             RayTracingIndex source = {fromMapX, fromMapY, 0};
00327                         std::stable_sort(ray.begin(), ray.end(), boost::bind(&RayTracingIndex::topologicalCompare, source, _1, _2));
00328 
00329                         // remove duplicate values
00330                         Ray::iterator endIterator = std::unique(ray.begin(), ray.end(), &RayTracingIndex::equals);
00331                         ray.resize(std::distance(ray.begin(), endIterator));
00332 
00333                         return rayTracingSucceeded;
00334                 }
00335 
00336                 float getMetricWidth() {
00337                         return mMap.info.width * mMap.info.resolution;
00338                 }
00339 
00340                 float getMetricHeight() {
00341                         return mMap.info.height * mMap.info.resolution;
00342                 }
00343 
00344                 void worldToMapCoordinates(const SimpleVector3 &position, int32_t &x, int32_t &y) {
00345             SimpleVector3 continuousMapCoords;
00346             worldToMapCoordinates(position, continuousMapCoords);
00347 
00348                         // get the map coords
00349                         x = (int32_t) floor(continuousMapCoords[0]);
00350                         y = (int32_t) floor(continuousMapCoords[1]);
00351                 }
00352 
00353         void worldToMapCoordinates(const SimpleVector3 &position, SimpleVector3 &result) {
00354             SimpleVector3 translation = this->getTranslation();
00355             SimpleQuaternion orientation = this->getOrientation();
00356             SimpleMatrix3 rotationMatrix = orientation.toRotationMatrix();
00357 
00358             // the map is rotated by rotation matrix, for back transform do a transpose.
00359             result = (rotationMatrix.transpose() * position - translation) / mMap.info.resolution;
00360         }
00361 
00362                 void mapToWorldCoordinates(const int32_t &x, const int32_t &y, SimpleVector3 &result) {
00363             mapToWorldCoordinates(SimpleVector3(x, y, 0.0), result);
00364                 }
00365 
00366         void mapToWorldCoordinates(const SimpleVector3 &position, SimpleVector3 &result) {
00367             SimpleVector3 translation = this->getTranslation();
00368             SimpleQuaternion orientation = this->getOrientation();
00369             result = orientation.toRotationMatrix() * position * mMap.info.resolution + translation;
00370         }
00371 
00372         void mapToWorldSize(const double &size, double &result) {
00373             result = size * mMap.info.resolution;
00374         }
00375 
00376         void worldToMapSize(const double &size, double &result) {
00377             result = size / mMap.info.resolution;
00378         }
00379 
00380                 SimpleVector3 getTranslation() {
00381                         return SimpleVector3(mMap.info.origin.position.x, mMap.info.origin.position.y, mMap.info.origin.position.z);
00382                 }
00383 
00384                 SimpleQuaternion getOrientation() {
00385                         return TypeHelper::getSimpleQuaternion(mMap.info.origin.orientation);
00386                 }
00387 
00388                 bool isOccupancyValueAcceptable(const int8_t &occupancyValue) {
00389                         return occupancyValue >= 0 && occupancyValue <= mCollisionThreshold;
00390                 }
00391 
00392                 void setCollisionThreshold(int8_t thresholdValue) {
00393                         mCollisionThreshold = thresholdValue;
00394                 }
00395 
00396                 int8_t getCollisionThreshold () {
00397                         return mCollisionThreshold;
00398                 }
00399 
00400                 float getSquaredDistance(const SimpleVector3 &start, const SimpleVector3 &goal) {
00401                         return (goal - start).squaredNorm();
00402                 }
00403         };
00404 
00405         typedef boost::shared_ptr<MapHelper> MapHelperPtr;
00406 }


asr_robot_model_services
Author(s): Aumann Florian, Borella Jocelyn, Heller Florian, Meißner Pascal, Schleicher Ralf, Stöckle Patrick, Stroh Daniel, Trautmann Jeremias, Walter Milena, Wittenbeck Valerij
autogenerated on Sat Jun 8 2019 18:24:52