segbot_logical_translator.cpp
Go to the documentation of this file.
00001 
00037 #include <dynamic_reconfigure/Reconfigure.h>
00038 #include <tf/transform_datatypes.h>
00039 
00040 #include <boost/algorithm/string/classification.hpp>
00041 #include <boost/algorithm/string/join.hpp>
00042 #include <boost/algorithm/string/split.hpp>
00043 #include <boost/filesystem.hpp>
00044 #include <boost/foreach.hpp>
00045 #include <boost/thread/thread.hpp>
00046 #include <bwi_mapper/map_inflator.h>
00047 #include <bwi_mapper/map_loader.h>
00048 #include <bwi_mapper/map_utils.h>
00049 #include <bwi_mapper/point_utils.h>
00050 
00051 #include <segbot_logical_translator/segbot_logical_translator.h>
00052 
00053 #define SCALAR 1.1
00054 
00055 namespace segbot_logical_translator {
00056 
00057   SegbotLogicalTranslator::SegbotLogicalTranslator() : 
00058       make_plan_client_initialized_(false), 
00059       static_costmap_toggle_client_initialized_(false), 
00060       initialized_(false) {
00061 
00062     nh_.reset(new ros::NodeHandle);
00063     ros::param::param<std::string>("~global_frame_id", global_frame_id_, "level_mux/map");
00064   }
00065 
00066   bool SegbotLogicalTranslator::initialize() {
00067     ROS_INFO_STREAM("SegbotLogicalTranslator: Initializing...");
00068 
00069     std::string map_file, data_directory;
00070     std::vector<std::string> required_parameters;
00071     if (!ros::param::get("~map_file", map_file)) {
00072       required_parameters.push_back("~map_file");
00073     }
00074     if (!ros::param::get("~data_directory", data_directory)) {
00075       required_parameters.push_back("~data_directory");
00076     }
00077     if (required_parameters.size() != 0) {
00078       std::string message = "SegbotLogicalTranslator: Required parameters [" +
00079         boost::algorithm::join(required_parameters, ", ") + "] missing!";
00080       ROS_FATAL_STREAM(message);
00081       throw std::runtime_error(message);
00082     }
00083 
00084     std::string door_file = bwi_planning_common::getDoorsFileLocationFromDataDirectory(data_directory);
00085     ROS_INFO_STREAM("SegbotLogicalTranslator: Reading door file: " + door_file);
00086     bwi_planning_common::readDoorFile(door_file, doors_);
00087 
00088     std::string location_file = bwi_planning_common::getLocationsFileLocationFromDataDirectory(data_directory);
00089     ROS_INFO_STREAM("SegbotLogicalTranslator: Reading locations file: " + location_file);
00090     bwi_planning_common::readLocationFile(location_file, locations_, location_map_);
00091 
00092     std::string object_file = bwi_planning_common::getObjectsFileLocationFromDataDirectory(data_directory);
00093     ROS_INFO_STREAM("SegbotLogicalTranslator: Checking if objects file exists: " + object_file);
00094     if (boost::filesystem::exists(object_file)) {
00095       ROS_INFO_STREAM("SegbotLogicalTranslator:   Objects file exists. Reading now!");
00096       bwi_planning_common::readObjectApproachFile(object_file, object_approach_map_);
00097     }
00098 
00099     bwi_mapper::MapLoader mapper(map_file);
00100     mapper.getMap(map_);
00101     map_.header.stamp = ros::Time::now();
00102     map_.header.frame_id = global_frame_id_;
00103     info_ = map_.info;
00104 
00105     std::string map_with_doors_file = bwi_planning_common::getDoorsMapLocationFromDataDirectory(data_directory);
00106     mapper = bwi_mapper::MapLoader(map_with_doors_file);
00107     mapper.getMap(map_with_doors_);
00108     map_with_doors_.header.stamp = ros::Time::now();
00109     map_with_doors_.header.frame_id = global_frame_id_;
00110 
00111     // Inflating map by 20cm should get rid of any tiny paths to the goal.
00112     bwi_mapper::inflateMap(0.2, map_with_doors_, inflated_map_with_doors_);
00113 
00114     // We'll do lazy initialization of the approachable space. Just clear it for now, and we'll populate it as
00115     // necessary.
00116     door_approachable_space_1_.clear();
00117     door_approachable_space_2_.clear();
00118     object_approachable_space_.clear();
00119 
00120     initialized_ = true;
00121     return true;
00122   }
00123 
00124   bool SegbotLogicalTranslator::isDoorOpen(size_t idx) {
00125 
00126     if (!initialized_) {
00127       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00128       return false;
00129     }
00130 
00131     if (idx > doors_.size()) {
00132       return false;
00133     }
00134 
00135     enableStaticCostmap(false);
00136     // TODO: this should not be necesary, since we make service calls 
00137     boost::this_thread::sleep(boost::posix_time::milliseconds(250));
00138 
00139     bwi_mapper::Point2f start_pt, goal_pt;
00140     float start_yaw, goal_yaw;
00141 
00142     start_pt = doors_[idx].approach_points[0];
00143     goal_pt = doors_[idx].approach_points[1];
00144     start_yaw = doors_[idx].approach_yaw[0];
00145     goal_yaw = doors_[idx].approach_yaw[1];
00146 
00147     nav_msgs::GetPlan srv;
00148     geometry_msgs::PoseStamped &start = srv.request.start;
00149     geometry_msgs::PoseStamped &goal = srv.request.goal;
00150     start.header.frame_id = goal.header.frame_id = global_frame_id_;
00151     start.header.stamp = goal.header.stamp = ros::Time::now();
00152 
00153     start.pose.position.x = start_pt.x;
00154     start.pose.position.y = start_pt.y;
00155     start.pose.position.z = 0;
00156     start.pose.orientation = tf::createQuaternionMsgFromYaw(start_yaw);
00157 
00158     goal.pose.position.x = goal_pt.x;
00159     goal.pose.position.y = goal_pt.y;
00160     goal.pose.position.z = 0;
00161     goal.pose.orientation = tf::createQuaternionMsgFromYaw(goal_yaw);
00162     srv.request.tolerance = -1.0f;//0.5 + 1e-6;
00163 
00164     float min_distance = cv::norm(start_pt - goal_pt);
00165 
00166     int counter = 0;
00167 
00168     if (!make_plan_client_initialized_) {
00169       ROS_INFO_STREAM("SegbotLogicalTranslator: Waiting for make_plan service..");
00170       make_plan_client_ = nh_->serviceClient<nav_msgs::GetPlan>("move_base/NavfnROS/make_plan");
00171       make_plan_client_.waitForExistence();
00172       ROS_INFO_STREAM("SegbotLogicalTranslator: make_plan service found!");
00173       make_plan_client_initialized_ = true;
00174     }
00175 
00176     // Check three times if this door is open. Sometimes, the costmap is out of sync or something, and the global
00177     // planner returns paths through obstacles. This bug is true for both navfn and global_planner.
00178     for (int i = 0; i < 3; i++) {
00179       if (make_plan_client_.call(srv)) {
00180         if (srv.response.plan.poses.size() != 0) {
00181           // Valid plan received. Check if plan distance seems reasonable
00182           float distance = 0;
00183           geometry_msgs::Point old_pt =
00184             srv.response.plan.poses[0].pose.position;
00185           for (size_t i = 1; i < srv.response.plan.poses.size(); ++i) {
00186             geometry_msgs::Point current_pt =
00187               srv.response.plan.poses[i].pose.position;
00188             distance += sqrt(pow(current_pt.x - old_pt.x, 2) +
00189                              pow(current_pt.y - old_pt.y, 2));
00190             old_pt = current_pt;
00191           }
00192                                         ROS_INFO_STREAM("SegbotLogicalTranslator: plan distance to go through door is: " << distance);
00193                                         ROS_INFO_STREAM("Comparing this plan to distance threshhold of " << SCALAR * min_distance);
00194           if (distance <  SCALAR *  min_distance) {
00195             //return true;
00196             counter++;
00197                                                 ROS_INFO_STREAM("SegbotLogicalTranslator: door open, counter is " << counter);
00198           } else {
00199             //return false; // returned path probably through some other door
00200             ROS_INFO_STREAM("SegbotLogicalTranslator: isDoorOpen: Returned path is too long.");
00201             counter = 0;
00202           }
00203         } else {
00204           //return false; // this is ok. it means the door is closed
00205           ROS_INFO_STREAM("SegbotLogicalTranslator: isDoorOpen: Could not find path, door is likely closed.");
00206           counter = 0;
00207         }
00208       } else {
00209         //return false; // shouldn't be here. the service has failed
00210         counter = 0;
00211       }
00212     }
00213 
00214     // TODO: set this to whatever state it was in.
00215     enableStaticCostmap(true);
00216 
00217     if (counter == 3) {
00218       // we have see the door open 3 consequitive times
00219       return true;
00220     } else {
00221       return false;
00222     }
00223   }
00224 
00225   bool SegbotLogicalTranslator::getApproachPoint(size_t idx,
00226       const bwi_mapper::Point2f& current_location,
00227       bwi_mapper::Point2f& point, float &yaw) {
00228 
00229     if (!initialized_) {
00230       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00231       return false;
00232     }
00233 
00234     if (idx > doors_.size()) {
00235       return false;
00236     }
00237 
00238     // See if we've calculated the approachable space for this door.
00239     if (door_approachable_space_1_.find(idx) == door_approachable_space_1_.end()) {
00240       const bwi_planning_common::Door& door = doors_[idx];
00241       const bwi_mapper::Point2d approach_pt_1(bwi_mapper::toGrid(door.approach_points[0], info_));
00242       door_approachable_space_1_[idx] = boost::shared_ptr<bwi_mapper::PathFinder>(new bwi_mapper::PathFinder(inflated_map_with_doors_, approach_pt_1));
00243     }
00244     if (door_approachable_space_2_.find(idx) == door_approachable_space_2_.end()) {
00245       const bwi_planning_common::Door& door = doors_[idx];
00246       const bwi_mapper::Point2d approach_pt_2(bwi_mapper::toGrid(door.approach_points[1], info_));
00247       door_approachable_space_2_[idx] = boost::shared_ptr<bwi_mapper::PathFinder>(new bwi_mapper::PathFinder(inflated_map_with_doors_, approach_pt_2));
00248     }
00249 
00250     // Find the approach point to which we can find a path. If both approach points can be reached, fine the approach
00251     // point which is closer.
00252     bwi_mapper::Point2d grid(bwi_mapper::toGrid(current_location, info_));
00253     int distance_1 = door_approachable_space_1_[idx]->getManhattanDistance(grid);
00254     int distance_2 = door_approachable_space_2_[idx]->getManhattanDistance(grid);
00255     if (distance_1 >= 0 || distance_2 >= 0) {
00256       if (distance_1 >= 0 && (distance_1 < distance_2 || distance_2 < 0)) {
00257         point = doors_[idx].approach_points[0];
00258         yaw = doors_[idx].approach_yaw[0];
00259       } else {
00260         point = doors_[idx].approach_points[1];
00261         yaw = doors_[idx].approach_yaw[1];
00262       }
00263       return true;
00264     }
00265 
00266     /* The door is not approachable from the current location */
00267     return false;
00268   }
00269 
00270   bool SegbotLogicalTranslator::isObjectApproachable(const std::string& object_name,
00271                                                      const bwi_mapper::Point2f& current_location) {
00272 
00273     if (!initialized_) {
00274       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00275       return false;
00276     }
00277 
00278     if (object_approachable_space_.find(object_name) == object_approachable_space_.end()) {
00279       const geometry_msgs::Pose& object_pose = object_approach_map_[object_name];
00280       const bwi_mapper::Point2d approach_pt(bwi_mapper::toGrid(bwi_mapper::Point2f(object_pose.position.x,
00281                                                                                    object_pose.position.y),
00282                                                                info_));
00283       object_approachable_space_[object_name] = boost::shared_ptr<bwi_mapper::PathFinder>(new bwi_mapper::PathFinder(inflated_map_with_doors_, approach_pt));
00284     }
00285 
00286     bwi_mapper::Point2d grid_pt(bwi_mapper::toGrid(current_location, info_));
00287     return object_approachable_space_[object_name]->pathExists(grid_pt);
00288   }
00289 
00290   bool SegbotLogicalTranslator::getThroughDoorPoint(size_t idx,
00291       const bwi_mapper::Point2f& current_location,
00292       bwi_mapper::Point2f& point, float& yaw) {
00293 
00294     if (!initialized_) {
00295       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00296       return false;
00297     }
00298 
00299     if (idx > doors_.size()) {
00300       return false;
00301     }
00302 
00303     bwi_mapper::Point2f approach_point;
00304 
00305     float unused_approach_yaw;
00306     bool door_approachable = getApproachPoint(idx, current_location, approach_point, unused_approach_yaw);
00307     if (door_approachable) {
00308       if (approach_point.x == doors_[idx].approach_points[0].x &&
00309           approach_point.y == doors_[idx].approach_points[0].y) {
00310         point = doors_[idx].approach_points[1];
00311         yaw = doors_[idx].approach_yaw[1] + M_PI;
00312       } else {
00313         point = doors_[idx].approach_points[0];
00314         yaw = doors_[idx].approach_yaw[0] + M_PI;
00315       }
00316       return true;
00317     }
00318 
00319     return false;
00320   }
00321 
00322   bool SegbotLogicalTranslator::isRobotFacingDoor(
00323       const bwi_mapper::Point2f& current_location,
00324       float yaw, float threshold, size_t idx) {
00325 
00326     if (!initialized_) {
00327       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00328       return false;
00329     }
00330 
00331     bwi_mapper::Point2f& center_pt = doors_[idx].door_center;
00332     if (bwi_mapper::getMagnitude(center_pt - current_location) >
00333         threshold) {
00334       return false;
00335     }
00336 
00337     bwi_mapper::Point2f diff_pt = center_pt - current_location;
00338     float orientation_to_door = atan2f(diff_pt.y, diff_pt.x);
00339     while (orientation_to_door > yaw + M_PI) orientation_to_door -= 2*M_PI;
00340     while (orientation_to_door <= yaw - M_PI) orientation_to_door += 2*M_PI;
00341     if (fabs(orientation_to_door - yaw) > M_PI / 3) {
00342       return false;
00343     }
00344 
00345     return true;
00346   }
00347 
00348   bool SegbotLogicalTranslator::isRobotBesideDoor(
00349       const bwi_mapper::Point2f& current_location,
00350       float yaw, float threshold, size_t idx) {
00351 
00352     if (!initialized_) {
00353       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00354       return false;
00355     }
00356 
00357     bwi_mapper::Point2f& center_pt = doors_[idx].door_center;
00358     if (bwi_mapper::getMagnitude(center_pt - current_location) >
00359         threshold) {
00360       return false;
00361     }
00362 
00363     return true;
00364   }
00365 
00366   size_t SegbotLogicalTranslator::getLocationIdx(
00367       const bwi_mapper::Point2f& current_location) {
00368 
00369     if (!initialized_) {
00370       ROS_ERROR_STREAM("SegbotLogicalTranslator : requesting data without being initialized!");
00371       return false;
00372     }
00373 
00374     bwi_mapper::Point2f grid = bwi_mapper::toGrid(current_location, info_);
00375     size_t map_idx = MAP_IDX(info_.width, (int) grid.x, (int) grid.y);
00376     if (map_idx > location_map_.size()) {
00377       return (size_t) -1;
00378     }
00379     return (size_t) location_map_[map_idx];
00380 
00381   }
00382 
00383   void SegbotLogicalTranslator::initializeStaticCostmapToggleService() {
00384     ROS_INFO_STREAM("SegbotLogicalTranslator: Waiting for static_costmap dyn reconfigure service..");
00385     static_costmap_toggle_client_ = 
00386       nh_->serviceClient<dynamic_reconfigure::Reconfigure>("move_base/global_costmap/static_layer/set_parameters");
00387     static_costmap_toggle_client_.waitForExistence();
00388     ROS_INFO_STREAM("SegbotLogicalTranslator: static_costmap dyn reconfigure service found!");
00389     static_costmap_toggle_client_initialized_ = true;
00390   }
00391 
00392   void SegbotLogicalTranslator::enableStaticCostmap(bool value) {
00393     if (!static_costmap_toggle_client_initialized_) {
00394       initializeStaticCostmapToggleService();
00395     }
00396     dynamic_reconfigure::Reconfigure static_costmap_toggle;
00397     static_costmap_toggle.request.config.bools.resize(1);
00398     static_costmap_toggle.request.config.bools[0].name = "enabled";
00399     static_costmap_toggle.request.config.bools[0].value = value;
00400     static_costmap_toggle_client_.call(static_costmap_toggle);
00401   }
00402 
00403 } /* namespace segbot_logical_translator */


segbot_logical_translator
Author(s): Piyush Khandelwal
autogenerated on Thu Jun 6 2019 21:37:44