00001 #include "SimulatedChangeFloor.h" 00002 00003 #include <boost/foreach.hpp> 00004 00005 #include "ActionFactory.h" 00006 #include "../StaticFacts.h" 00007 00008 #include "bwi_kr_execution/UpdateFluents.h" 00009 #include "ros/console.h" 00010 #include "ros/ros.h" 00011 00012 #include <actionlib/client/simple_action_client.h> 00013 #include <bwi_msgs/DoorHandlerInterface.h> 00014 #include <bwi_msgs/LogicalNavigationAction.h> 00015 #include <bwi_msgs/ResolveChangeFloor.h> 00016 #include <bwi_msgs/RobotTeleporterInterface.h> 00017 00018 namespace bwi_krexec { 00019 00020 SimulatedChangeFloor::SimulatedChangeFloor() : 00021 robot_teleported(false), 00022 done(false), 00023 failed(false) {} 00024 00025 void SimulatedChangeFloor::run() { 00026 00027 if (!done) { 00028 00029 // Get the doors for this elevator. 00030 std::string facing_door; 00031 std::list<actasp::AspAtom> static_facts = StaticFacts::staticFacts(); 00032 BOOST_FOREACH(const actasp::AspAtom fact, static_facts) { 00033 if (fact.getName() == "hasdoor") { 00034 std::vector<std::string> params = fact.getParameters(); 00035 if (params[0] == dest_room) { 00036 // NOTE: This makes the assumption that an elevator room only has a single door, which is true for GDC. 00037 facing_door = params[1]; 00038 break; 00039 } 00040 } 00041 } 00042 00043 if (facing_door.empty()) { 00044 ROS_ERROR_STREAM("Unable to retrieve door we're facing for destination " << dest_room << ". Cannot complete action!"); 00045 failed = true; 00046 done = true; 00047 } else { 00048 00049 if (!robot_teleported) { 00050 00051 // Resolve the location to which the robot needs to be teleported to. 00052 ros::NodeHandle n; 00053 ros::ServiceClient change_floor_resolution_client = 00054 n.serviceClient<bwi_msgs::ResolveChangeFloor>("resolve_change_floor"); 00055 change_floor_resolution_client.waitForExistence(); 00056 00057 bwi_msgs::ResolveChangeFloor rcf; 00058 rcf.request.new_room = dest_room; 00059 rcf.request.facing_door = facing_door; 00060 if (change_floor_resolution_client.call(rcf) && rcf.response.success) { 00061 00062 // Teleport robot to resolved location. 00063 ros::ServiceClient robot_teleporter_client = 00064 n.serviceClient<bwi_msgs::RobotTeleporterInterface>("teleport_robot"); 00065 robot_teleporter_client.waitForExistence(); 00066 00067 bwi_msgs::RobotTeleporterInterface rti; 00068 rti.request.pose = rcf.response.pose.pose.pose; 00069 00070 if (robot_teleporter_client.call(rti) && rti.response.success) { 00071 robot_teleported = true; 00072 robot_teleportation_start_time = ros::Time::now(); 00073 } else { 00074 ROS_ERROR_STREAM("Failed robot teleportation to pose " << rti.request.pose); 00075 failed = true; 00076 done = true; 00077 } 00078 } else { 00079 ROS_ERROR_STREAM("Change floor resolution failed for room " << dest_room << " and door " << facing_door); 00080 failed = true; 00081 done = true; 00082 } 00083 00084 } else { 00085 00086 if (ros::Time::now() - robot_teleportation_start_time > ros::Duration(10.0f)) { 00087 00088 // Open Elevator door. 00089 ros::NodeHandle n; 00090 ros::ServiceClient door_client = n.serviceClient<bwi_msgs::DoorHandlerInterface> ("/update_doors"); 00091 door_client.waitForExistence(); 00092 00093 bwi_msgs::DoorHandlerInterface dhi; 00094 00095 dhi.request.all_doors = false; 00096 dhi.request.door = facing_door; 00097 dhi.request.open = true; 00098 dhi.request.open_timeout = 30.0f; 00099 00100 door_client.call(dhi); 00101 00102 // Attempt to change the robot's location to this floor and location. 00103 boost::shared_ptr<actionlib::SimpleActionClient<bwi_msgs::LogicalNavigationAction> > lnac; 00104 lnac.reset(new actionlib::SimpleActionClient<bwi_msgs::LogicalNavigationAction>("execute_logical_goal", 00105 true)); 00106 lnac->waitForServer(); 00107 bwi_msgs::LogicalNavigationGoal goal; 00108 goal.command.name = "changefloor"; 00109 goal.command.value.push_back(dest_room); 00110 goal.command.value.push_back(facing_door); 00111 lnac->sendGoal(goal); 00112 lnac->waitForResult(); 00113 00114 // Update knowledge base to reflect change in position. 00115 ros::ServiceClient krClient = n.serviceClient<bwi_kr_execution::UpdateFluents> ( "update_fluents" ); 00116 krClient.waitForExistence(); 00117 bwi_kr_execution::UpdateFluents uf; 00118 00119 bwi_kr_execution::AspFluent open_door; 00120 open_door.name = "open"; 00121 open_door.variables.push_back(facing_door); 00122 00123 bwi_kr_execution::AspFluent face_door; 00124 face_door.name = "facing"; 00125 face_door.variables.push_back(facing_door); 00126 00127 bwi_kr_execution::AspFluent beside_door; 00128 beside_door.name = "beside"; 00129 beside_door.variables.push_back(facing_door); 00130 00131 bwi_kr_execution::AspFluent at_loc; 00132 at_loc.name = "at"; 00133 at_loc.variables.push_back(dest_room); 00134 00135 uf.request.fluents.push_back(open_door); 00136 uf.request.fluents.push_back(face_door); 00137 uf.request.fluents.push_back(beside_door); 00138 uf.request.fluents.push_back(at_loc); 00139 krClient.call(uf); 00140 00141 done = true; 00142 } 00143 } 00144 } 00145 } 00146 00147 } 00148 00149 bool SimulatedChangeFloor::hasFinished() const { 00150 return done; 00151 } 00152 00153 bool SimulatedChangeFloor::hasFailed() const { 00154 return failed; 00155 } 00156 00157 actasp::Action *SimulatedChangeFloor::cloneAndInit(const actasp::AspFluent & fluent) const { 00158 SimulatedChangeFloor *other = new SimulatedChangeFloor(); 00159 other->dest_room = fluent.getParameters().at(0); 00160 return other; 00161 } 00162 00163 std::vector<std::string> SimulatedChangeFloor::getParameters() const { 00164 return std::vector<std::string>(1, dest_room); 00165 } 00166 00167 //if you want the action to be available only in simulation, or only 00168 //on the robot, use the constructor that also takes a boolean. 00169 ActionFactory simulatedChangeFloor(new SimulatedChangeFloor(), true); 00170 00171 }