00001
00038 #include <actionlib/client/simple_action_client.h>
00039 #include <actionlib/client/terminal_state.h>
00040 #include <message_filters/subscriber.h>
00041 #include <move_base_msgs/MoveBaseAction.h>
00042 #include <nav_msgs/Odometry.h>
00043 #include <ros/ros.h>
00044 #include <tf/message_filter.h>
00045 #include <tf/transform_datatypes.h>
00046 #include <tf/transform_listener.h>
00047
00048 #include <bwi_planning_common/PlannerAtom.h>
00049 #include <bwi_planning_common/PlannerInterface.h>
00050 #include <segbot_logical_translator/segbot_logical_translator.h>
00051
00052 using bwi_planning_common::PlannerAtom;
00053 using bwi_planning_common::NO_DOOR_IDX;
00054
00055 class SegbotLogicalNavigator :
00056 public segbot_logical_translator::SegbotLogicalTranslator {
00057
00058 public:
00059
00060 SegbotLogicalNavigator();
00061 bool execute(bwi_planning_common::PlannerInterface::Request &req,
00062 bwi_planning_common::PlannerInterface::Response &res);
00063
00064 protected:
00065
00066 void senseState(std::vector<PlannerAtom>& observations,
00067 size_t door_idx = NO_DOOR_IDX);
00068 bool approachDoor(const std::string& door_name,
00069 std::vector<PlannerAtom>& observations,
00070 std::string& error_message, bool gothrough = false);
00071 bool senseDoor(const std::string& door_name,
00072 std::vector<PlannerAtom>& observations,
00073 std::string& error_message);
00074
00075 bool approachObject(const std::string& object_name,
00076 std::vector<PlannerAtom>& observations,
00077 std::string& error_message);
00078
00079 bool executeNavigationGoal( const geometry_msgs::PoseStamped& pose);
00080 void odometryHandler( const nav_msgs::Odometry::ConstPtr& odom);
00081
00082 float robot_x_;
00083 float robot_y_;
00084 float robot_yaw_;
00085
00086 double door_proximity_distance_;
00087
00088 ros::ServiceServer service_;
00089 boost::shared_ptr<
00090 actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> >
00091 robot_controller_;
00092
00093 boost::shared_ptr<tf::TransformListener> tf_;
00094 boost::shared_ptr<tf::MessageFilter<nav_msgs::Odometry> > tf_filter_;
00095 boost::shared_ptr<message_filters::Subscriber<nav_msgs::Odometry> >
00096 odom_subscriber_;
00097
00098 };
00099
00100 SegbotLogicalNavigator::SegbotLogicalNavigator()
00101 : robot_x_(0), robot_y_(0), robot_yaw_(0) {
00102
00103 ROS_INFO("SegbotLogicalNavigator: Advertising services!");
00104
00105 ros::param::param("~door_proximity_distance", door_proximity_distance_, 1.5);
00106
00107 service_ = nh_->advertiseService("execute_logical_goal",
00108 &SegbotLogicalNavigator::execute, this);
00109
00110 robot_controller_.reset(
00111 new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>(
00112 "move_base", true));
00113 robot_controller_->waitForServer();
00114
00115 tf_.reset(new tf::TransformListener);
00116 odom_subscriber_.reset(new message_filters::Subscriber<nav_msgs::Odometry>);
00117 odom_subscriber_->subscribe(*nh_, "odom", 5);
00118 tf_filter_.reset(new tf::MessageFilter<nav_msgs::Odometry>(
00119 *odom_subscriber_, *tf_, global_frame_id_, 5));
00120 tf_filter_->registerCallback(
00121 boost::bind(&SegbotLogicalNavigator::odometryHandler, this, _1));
00122
00123 }
00124
00125 void SegbotLogicalNavigator::senseState(
00126 std::vector<PlannerAtom>& observations, size_t door_idx) {
00127
00128 PlannerAtom at;
00129 at.name = "at";
00130 size_t location_idx = getLocationIdx(bwi::Point2f(robot_x_, robot_y_));
00131 at.value.push_back(getLocationString(location_idx));
00132 observations.push_back(at);
00133
00134 size_t num_doors = getNumDoors();
00135 bwi::Point2f robot_loc(robot_x_, robot_y_);
00136 bool first_facing = false;
00137 bool first_beside = false;
00138 size_t facing_idx = NO_DOOR_IDX;
00139
00140 for (size_t door = 0; door < num_doors; ++door) {
00141 if (door_idx != NO_DOOR_IDX && door != door_idx) {
00142 continue;
00143 }
00144 bool facing_door = !first_facing &&
00145 isRobotFacingDoor(robot_loc, robot_yaw_, door_proximity_distance_, door);
00146 bool beside_door = !first_beside &&
00147 isRobotBesideDoor(robot_loc, robot_yaw_, door_proximity_distance_, door);
00148 if (!facing_door) {
00149 PlannerAtom n_facing;
00150 n_facing.name = "-facing";
00151 n_facing.value.push_back(getDoorString(door));
00152 observations.push_back(n_facing);
00153 } else {
00154 PlannerAtom facing;
00155 facing.name = "facing";
00156 facing.value.push_back(getDoorString(door));
00157 observations.push_back(facing);
00158 first_facing = true;
00159 facing_idx = door_idx;
00160 }
00161 if (!beside_door) {
00162 PlannerAtom n_beside;
00163 n_beside.name = "-beside";
00164 n_beside.value.push_back(getDoorString(door));
00165 observations.push_back(n_beside);
00166 } else {
00167 PlannerAtom beside;
00168 beside.name = "beside";
00169 beside.value.push_back(getDoorString(door));
00170 observations.push_back(beside);
00171 first_beside = true;
00172 }
00173 }
00174
00175
00176 if (facing_idx != NO_DOOR_IDX) {
00177 PlannerAtom door_open;
00178 door_open.value.push_back(getDoorString(facing_idx));
00179 if (isDoorOpen(facing_idx)) {
00180 door_open.name = "open";
00181 observations.push_back(door_open);
00182 } else {
00183 door_open.name = "-open";
00184 observations.push_back(door_open);
00185 }
00186 }
00187 }
00188
00189 bool SegbotLogicalNavigator::executeNavigationGoal(
00190 const geometry_msgs::PoseStamped& pose) {
00191 move_base_msgs::MoveBaseGoal goal;
00192 goal.target_pose = pose;
00193 robot_controller_->sendGoal(goal);
00194 robot_controller_->waitForResult();
00195 actionlib::SimpleClientGoalState state = robot_controller_->getState();
00196 return state == actionlib::SimpleClientGoalState::SUCCEEDED;
00197 }
00198
00199 void SegbotLogicalNavigator::odometryHandler(
00200 const nav_msgs::Odometry::ConstPtr& odom) {
00201 geometry_msgs::PoseStamped pose_in, pose_out;
00202 pose_in.header = odom->header;
00203 pose_in.pose = odom->pose.pose;
00204 tf_->transformPose(global_frame_id_, pose_in, pose_out);
00205 robot_x_ = pose_out.pose.position.x;
00206 robot_y_ = pose_out.pose.position.y;
00207 robot_yaw_ = tf::getYaw(pose_out.pose.orientation);
00208 }
00209
00210 bool SegbotLogicalNavigator::approachDoor(const std::string& door_name,
00211 std::vector<PlannerAtom>& observations,
00212 std::string& error_message, bool gothrough) {
00213 error_message = "";
00214
00215 size_t door_idx = getDoorIdx(door_name);
00216 if (door_idx == NO_DOOR_IDX) {
00217
00218 error_message = "Could not resolve argument: " + door_name;
00219 return false;
00220 } else {
00221
00222 bwi::Point2f approach_pt;
00223 float approach_yaw = 0;
00224 bool door_approachable = false;
00225
00226 if (!gothrough) {
00227 door_approachable = getApproachPoint(door_idx,
00228 bwi::Point2f(robot_x_, robot_y_), approach_pt, approach_yaw);
00229 } else {
00230 door_approachable = getThroughDoorPoint(door_idx,
00231 bwi::Point2f(robot_x_, robot_y_), approach_pt, approach_yaw);
00232 }
00233
00234 if (door_approachable) {
00235 geometry_msgs::PoseStamped pose;
00236 pose.header.stamp = ros::Time::now();
00237 pose.header.frame_id = global_frame_id_;
00238 pose.pose.position.x = approach_pt.x;
00239 pose.pose.position.y = approach_pt.y;
00240 tf::quaternionTFToMsg(
00241 tf::createQuaternionFromYaw(approach_yaw), pose.pose.orientation);
00242 bool success = executeNavigationGoal(pose);
00243
00244
00245 senseState(observations, door_idx);
00246
00247 return success;
00248 } else {
00249
00250 error_message = "Cannot interact with " + door_name + " from here.";
00251 return false;
00252 }
00253 }
00254 }
00255
00256 bool SegbotLogicalNavigator::approachObject(const std::string& object_name,
00257 std::vector<PlannerAtom>& observations,
00258 std::string& error_message) {
00259
00260 error_message = "";
00261 observations.clear();
00262
00263 if (object_approach_map_.find(object_name) != object_approach_map_.end()) {
00264 geometry_msgs::PoseStamped pose;
00265 pose.header.stamp = ros::Time::now();
00266 pose.header.frame_id = global_frame_id_;
00267 pose.pose = object_approach_map_[object_name];
00268 bool success = executeNavigationGoal(pose);
00269
00270
00271 senseState(observations, NO_DOOR_IDX);
00272 PlannerAtom closeto;
00273 closeto.name = "closeto";
00274 closeto.value.push_back(object_name);
00275 if (!success) {
00276 closeto.name = "-closeto";
00277 }
00278 observations.push_back(closeto);
00279 }
00280
00281 error_message = object_name + " does not exist.";
00282 return false;
00283 }
00284
00285 bool SegbotLogicalNavigator::senseDoor(const std::string& door_name,
00286 std::vector<PlannerAtom>& observations,
00287 std::string& error_message) {
00288 error_message = "";
00289 size_t door_idx =
00290 bwi_planning_common::resolveDoor(door_name, doors_);
00291 if (door_idx == bwi_planning_common::NO_DOOR_IDX) {
00292 error_message = "Door " + door_name + " does not exist!";
00293 return false;
00294 }
00295 bool door_open = isDoorOpen(door_idx);
00296 PlannerAtom open;
00297 open.name = "open";
00298 if (!door_open) {
00299 open.name = "-" + open.name;
00300 }
00301 open.value.push_back(door_name);
00302 observations.push_back(open);
00303 return true;
00304 }
00305
00306 bool SegbotLogicalNavigator::execute(
00307 bwi_planning_common::PlannerInterface::Request &req,
00308 bwi_planning_common::PlannerInterface::Response &res) {
00309
00310 res.observations.clear();
00311
00312 if (req.command.name == "approach") {
00313 res.success = approachDoor(req.command.value[0], res.observations,
00314 res.status, false);
00315 } else if (req.command.name == "gothrough") {
00316 res.success = approachDoor(req.command.value[0], res.observations,
00317 res.status, true);
00318 } else if (req.command.name == "sensedoor") {
00319 res.success = senseDoor(req.command.value[0], res.observations,
00320 res.status);
00321 } else if (req.command.name == "goto") {
00322 res.success = approachObject(req.command.value[0], res.observations,
00323 res.status);
00324 } else {
00325 res.success = true;
00326 res.status = "";
00327 senseState(res.observations);
00328 }
00329
00330 return true;
00331 }
00332
00333 int main(int argc, char *argv[]) {
00334
00335 ros::init(argc, argv, "segbot_logical_translator");
00336 ros::NodeHandle nh;
00337
00338 ROS_INFO("SegbotLogicalNavigator: Starting up node...");
00339 SegbotLogicalNavigator handler;
00340 ros::MultiThreadedSpinner spinner(2);
00341 spinner.spin();
00342 ROS_INFO("SegbotLogicalNavigator: Stopping node.");
00343
00344 return 0;
00345 }