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
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
00070 int parent_door = i;
00071 for (unsigned j = 0; j < i; ++j) {
00072 if (door_to_true_door_map_[j] != -1) {
00073
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
00086 spawnObject(true, i);
00087 door_open_status_[i] = false;
00088 }
00089 }
00090
00091
00092
00093 num_obstacles_ = 0;
00094
00095
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
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
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 }