segbot_logical_navigator.cpp
Go to the documentation of this file.
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   // If we are facing a door, also sense whether it is open
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     // Interface failure
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       // Publish the observable fluents
00245       senseState(observations, door_idx);
00246 
00247       return success;
00248     } else {
00249       // Planning failure
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     // Publish the observable fluents
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 }


segbot_logical_translator
Author(s): Piyush Khandelwal
autogenerated on Mon Oct 6 2014 07:30:24