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
00112 bwi_mapper::inflateMap(0.2, map_with_doors_, inflated_map_with_doors_);
00113
00114
00115
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
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;
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
00177
00178 for (int i = 0; i < 3; i++) {
00179 if (make_plan_client_.call(srv)) {
00180 if (srv.response.plan.poses.size() != 0) {
00181
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
00196 counter++;
00197 ROS_INFO_STREAM("SegbotLogicalTranslator: door open, counter is " << counter);
00198 } else {
00199
00200 ROS_INFO_STREAM("SegbotLogicalTranslator: isDoorOpen: Returned path is too long.");
00201 counter = 0;
00202 }
00203 } else {
00204
00205 ROS_INFO_STREAM("SegbotLogicalTranslator: isDoorOpen: Could not find path, door is likely closed.");
00206 counter = 0;
00207 }
00208 } else {
00209
00210 counter = 0;
00211 }
00212 }
00213
00214
00215 enableStaticCostmap(true);
00216
00217 if (counter == 3) {
00218
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
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
00251
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
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 }