door_handler.cpp
Go to the documentation of this file.
00001 #include <boost/algorithm/string/join.hpp>
00002 #include <boost/foreach.hpp>
00003 #include <boost/regex.hpp>
00004 #include <bwi_planning_common/utils.h>
00005 #include <bwi_tools/resource_resolver.h>
00006 #include <gazebo_msgs/GetModelState.h>
00007 #include <gazebo_msgs/SetModelState.h>
00008 #include <gazebo_msgs/SpawnModel.h>
00009 #include <stdexcept>
00010 #include <tf/transform_datatypes.h>
00011 
00012 #include <bwi_tools/point.h>
00013 #include <segbot_simulation_apps/door_handler.h>
00014 
00015 namespace segbot_simulation_apps {
00016 
00017   DoorHandler::DoorHandler() {
00018 
00019     ros::NodeHandle nh, private_nh("~");
00020 
00021     std::vector<std::string> unavailable_parameters;
00022     if (!(private_nh.getParam("obstacle_urdf", obstacle_urdf_))) {
00023       unavailable_parameters.push_back("obstacle_urdf");
00024     }
00025     if (!(private_nh.getParam("door_urdf", door_urdf_))) {
00026       unavailable_parameters.push_back("door_urdf");
00027     }
00028 
00029     if (unavailable_parameters.size() != 0) {
00030       std::string message = "Following neccessary params not available: " +
00031         boost::algorithm::join(unavailable_parameters, ", ");
00032       ROS_INFO_STREAM(message);
00033       throw std::runtime_error(message);
00034     }
00035 
00036     get_gazebo_model_client_ =
00037       nh.serviceClient<gazebo_msgs::GetModelState>(
00038           "/gazebo/get_model_state");
00039     bool gazebo_available = 
00040       get_gazebo_model_client_.waitForExistence(ros::Duration(30));
00041 
00042     if (!gazebo_available) {
00043       ROS_FATAL_STREAM("ClingoGazeboHandler: Gazebo is NOT AVAILABLE");
00044       throw 
00045         std::runtime_error("ClingoGazeboHandler: Gazebo is NOT AVAILABLE");
00046     }
00047 
00048     set_gazebo_model_client_ =
00049       nh.serviceClient<gazebo_msgs::SetModelState>(
00050           "/gazebo/set_model_state");
00051     set_gazebo_model_client_.waitForExistence();
00052 
00053     spawn_model_client_ =
00054       nh.serviceClient<gazebo_msgs::SpawnModel>(
00055           "/gazebo/spawn_urdf_model");
00056     set_gazebo_model_client_.waitForExistence();
00057 
00058     multimap_subscriber_ = nh.subscribe("map_metadata", 1, &DoorHandler::multimapHandler, this);
00059 
00060     initialized_ = false;
00061   }
00062 
00063   void DoorHandler::initialize() {
00064 
00065     // Spawn all necessary doors
00066     door_open_status_.resize(doors_.size());
00067     door_to_true_door_map_.resize(doors_.size());
00068     for (unsigned i = 0; i < doors_.size(); ++i) {
00069       // Check if this door is too close to a previously spawned door (in which case they are probably the same door).
00070       int parent_door = i; // i.e. no parent
00071       for (unsigned j = 0; j < i; ++j) {
00072         if (door_to_true_door_map_[j] != -1) {
00073           // This is a true door. Get its location.
00074           float diffx = doors_[j].door_center.x - doors_[i].door_center.x;
00075           float diffy = doors_[j].door_center.y - doors_[i].door_center.y;
00076           if (sqrtf(diffx*diffx + diffy*diffy) < 0.25f) {
00077             parent_door = j;
00078             break;
00079           }
00080         }
00081       }
00082 
00083       door_to_true_door_map_[i] = parent_door;
00084       if (parent_door == i) {
00085         // This is a new door. Yay!
00086         spawnObject(true, i);
00087         door_open_status_[i] = false;
00088       }
00089     }
00090 
00091     // Don't use obstacles for now
00092     // Spawn 30 obstacle objects
00093     num_obstacles_ = 0;
00094     // for (unsigned i = 0; i < 30; ++i) {
00095     //   spawnObject(false, i);
00096     // }
00097     
00098     initialized_ = true;
00099   }
00100 
00101   void DoorHandler::multimapHandler(const multi_level_map_msgs::MultiLevelMapData::ConstPtr& multimap) {
00102 
00103     if (!initialized_) {
00104       doors_.clear();
00105       // Read in the objects for each level.
00106       BOOST_FOREACH(const multi_level_map_msgs::LevelMetaData &level, multimap->levels) {
00107         std::string resolved_data_directory = bwi_tools::resolveRosResource(level.data_directory);
00108         std::string door_file = bwi_planning_common::getDoorsFileLocationFromDataDirectory(resolved_data_directory);
00109         std::vector<bwi_planning_common::Door> level_doors;
00110         readDoorFile(door_file, level_doors);
00111         doors_.insert(doors_.end(), level_doors.begin(), level_doors.end());
00112       }
00113 
00114       initialize();
00115     }
00116   }
00117 
00118   geometry_msgs::Pose DoorHandler::getDefaultLocation(bool is_door, int index) {
00119     geometry_msgs::Pose retval;
00120     retval.position.y = 500.0f + index * 2;
00121     retval.position.z = 0.0f;
00122     retval.orientation.x = 0.0f;
00123     retval.orientation.y = 0.0f;
00124     retval.orientation.z = 0.0f;
00125     retval.orientation.w = 1.0f;
00126     if (is_door) {
00127       retval.position.x = 500.0f;
00128     } else {
00129       retval.position.x = 600.0f;
00130     }
00131     return retval;
00132   }
00133 
00134   float DoorHandler::getDoorWidth(int index) {
00135     return 0.75f * doors_[index].width;
00136   }
00137 
00138   geometry_msgs::Pose DoorHandler::getDoorLocation(int index) {
00139     geometry_msgs::Pose retval;
00140 
00141     retval.position.x = doors_[index].door_center.x;
00142     retval.position.y = doors_[index].door_center.y;
00143     retval.position.z = 0;
00144 
00145     bwi::Point2f diff = 
00146       (doors_[index].door_corners[0] -
00147        doors_[index].door_corners[1]);
00148     float door_yaw = atan2f(diff.y, diff.x) + M_PI / 2;
00149     retval.orientation = tf::createQuaternionMsgFromYaw(door_yaw);
00150 
00151     return retval;
00152   }
00153 
00154   bool DoorHandler::openDoor(const std::string& door) {
00155     size_t idx = bwi_planning_common::resolveDoor(door, doors_);
00156     if (idx == bwi_planning_common::NO_DOOR_IDX) {
00157       return false;
00158     }
00159     return openDoor(idx); 
00160   }
00161 
00162   bool DoorHandler::openDoor(int index) {
00163     if (index >= doors_.size()) {
00164       return false;
00165     }
00166     index = door_to_true_door_map_[index];
00167     if (door_open_status_[index]) 
00168       return true;
00169     std::string prefix = "auto_door_";
00170     std::string model_name = prefix +
00171       boost::lexical_cast<std::string>(index);
00172     geometry_msgs::Pose pose = getDefaultLocation(true, index);
00173     bool success = teleportEntity(model_name, pose);
00174     door_open_status_[index] = true;
00175     return success;
00176   }
00177 
00178   void DoorHandler::openAllDoors() {
00179     for (unsigned i = 0; i < doors_.size(); ++i) {
00180       openDoor(i);
00181     }
00182   }
00183 
00184   bool DoorHandler::closeDoor(const std::string& door) {
00185     size_t idx = bwi_planning_common::resolveDoor(door, doors_);
00186     if (idx == bwi_planning_common::NO_DOOR_IDX) {
00187       return false;
00188     }
00189     return closeDoor(idx); 
00190   }
00191 
00192   bool DoorHandler::closeDoor(int index) {
00193     if (index >= doors_.size()) {
00194       return false;
00195     }
00196     index = door_to_true_door_map_[index];
00197     if (!door_open_status_[index]) 
00198       return true;
00199     ROS_INFO_STREAM("Closing door " << index);
00200     std::string prefix = "auto_door_";
00201     std::string model_name = prefix +
00202       boost::lexical_cast<std::string>(index);
00203     geometry_msgs::Pose pose = getDoorLocation(index);
00204     bool success = teleportEntity(model_name, pose);
00205     door_open_status_[index] = false;
00206     return success;
00207   }
00208 
00209   void DoorHandler::closeAllDoors() {
00210     ROS_INFO_STREAM("Closing all doors");
00211     for (unsigned i = 0; i < doors_.size(); ++i) {
00212       closeDoor(i);
00213     }
00214   }
00215 
00216 
00217   bool DoorHandler::isDoorOpen(const std::string& door) {
00218     size_t idx = bwi_planning_common::resolveDoor(door, doors_);
00219     if (idx == bwi_planning_common::NO_DOOR_IDX) {
00220       return false;
00221     }
00222     return isDoorOpen(idx); 
00223   }
00224 
00225   bool DoorHandler::isDoorOpen(int index) {
00226     if (index >= doors_.size()) {
00227       return false;
00228     }
00229     index = door_to_true_door_map_[index];
00230     return door_open_status_[index];
00231   }
00232 
00233   void DoorHandler::closeAllDoorsFarAwayFromPoint(
00234       const geometry_msgs::Pose& point, float distance) {
00235     for (unsigned i = 0; i < doors_.size(); ++i) {
00236       if (door_to_true_door_map_[i] != i) {
00237         // This isn't a true door. Don't worry about it.
00238         continue;
00239       }
00240       if (!door_open_status_[i]) {
00241         continue;
00242       }
00243       bool is_door_near = checkClosePoses(point, getDoorLocation(i), distance, false);
00244       if (!is_door_near) {
00245         closeDoor(i);
00246       }
00247     }
00248   }
00249 
00250   bool DoorHandler::checkClosePoses(const geometry_msgs::Pose& p1, 
00251                                     const geometry_msgs::Pose& p2, 
00252                                     float threshold, 
00253                                     bool check_yaw) {
00254     float dist_diff = sqrtf(pow((p1.position.x - p2.position.x), 2) + pow((p1.position.y - p2.position.y), 2));
00255     if (dist_diff > threshold) {
00256       return false;
00257     }
00258     double yaw1 = tf::getYaw(p1.orientation);
00259     double yaw2 = tf::getYaw(p2.orientation);
00260     if (check_yaw && fabs(yaw1 - yaw2) > 0.1) {
00261       return false;
00262     }
00263     return true;
00264   }
00265 
00266   bool DoorHandler::teleportEntity(const std::string& entity,
00267       const geometry_msgs::Pose& pose) {
00268 
00269     int count = 0;
00270     int attempts = 5;
00271     bool location_verified = false;
00272     while (count < attempts and !location_verified) {
00273       gazebo_msgs::GetModelState get_srv;
00274       get_srv.request.model_name = entity;
00275       get_gazebo_model_client_.call(get_srv);
00276       location_verified = checkClosePoses(get_srv.response.pose, pose);
00277       if (!location_verified) {
00278         gazebo_msgs::SetModelState set_srv;
00279         set_srv.request.model_state.model_name = entity;
00280         set_srv.request.model_state.pose = pose;
00281         set_gazebo_model_client_.call(set_srv);
00282         if (!set_srv.response.success) {
00283           ROS_WARN_STREAM("SetModelState service call failed for " << entity
00284               << " to " << pose);
00285         }
00286       }
00287       ++count;
00288     }
00289     if (!location_verified) {
00290       ROS_ERROR_STREAM("Unable to teleport " << entity << " to " << pose
00291           << " despite " << attempts << " attempts.");
00292       return false;
00293     }
00294     return true;
00295   }
00296 
00297   void DoorHandler::spawnObject(bool is_door, int index) {
00298 
00299     gazebo_msgs::SpawnModel spawn;
00300     std::string prefix;
00301     if (is_door) {
00302       prefix = "auto_door_";
00303       spawn.request.model_xml = boost::regex_replace(door_urdf_, 
00304           boost::regex("@WIDTH@"),
00305           boost::lexical_cast<std::string>(getDoorWidth(index)));
00306       spawn.request.initial_pose = getDoorLocation(index);
00307     } else {
00308       prefix = "auto_obs_";
00309       index = num_obstacles_;
00310       spawn.request.model_xml = obstacle_urdf_;
00311       spawn.request.initial_pose = getDefaultLocation(false, index);
00312     }
00313 
00314     spawn.request.model_name = prefix +
00315       boost::lexical_cast<std::string>(index);
00316 
00317     if (spawn_model_client_.call(spawn)) {
00318       if (spawn.response.success) {
00319         ++num_obstacles_;
00320         return;
00321       }
00322       ROS_WARN_STREAM("Received error message while spawning object: " <<
00323           spawn.response.status_message);
00324     }
00325 
00326     ROS_ERROR_STREAM("Unable to spawn: " << spawn.request.model_name);
00327   }      
00328 
00329 }


segbot_simulation_apps
Author(s): Piyush Khandelwal
autogenerated on Thu Aug 27 2015 15:11:04