00001
00013
00014
00015 #include <ros/ros.h>
00016 #include <tf/transform_listener.h>
00017 #include <std_msgs/String.h>
00018 #include <std_msgs/Bool.h>
00019 #include <geometry_msgs/PoseStamped.h>
00020 #include <actionlib/client/simple_action_client.h>
00021 #include <actionlib_msgs/GoalStatus.h>
00022 #include <move_base_msgs/MoveBaseAction.h>
00023 #include <stdio.h>
00024 #include <string>
00025 #include <sstream>
00026
00027 #include "video_player/PlayVideoSrv.h"
00028
00029
00030 ros::Time last_button_msg_time;
00031 int current_goal = 0;
00032
00033
00034 void createPoseFromParams(std::string param_name, geometry_msgs::PoseStamped* pose);
00035 void buttonCb(std_msgs::Bool msg);
00036 bool last_button_state = false;
00037
00038
00039 enum state {
00040 START, RETURN_START, WAIT_PERSON, APPROACH_PERSON, ASK_PERSON, WAIT_BUTTON_TOUR, APPROACH_PRESENTATION, PRESENT, ASK_REPETITION, WAIT_BUTTON_REPETITION, TALK_BYE
00041 };
00042
00043 int main(int argc, char** argv) {
00044
00045 ros::init(argc, argv, "state_machine");
00046 ros::NodeHandle nh;
00047 ros::Rate loop_rate(10);
00048
00049
00050 ros::Publisher speech_pub = nh.advertise<std_msgs::String>("/speech", 1);
00051
00052
00053 ros::Subscriber button_sub = nh.subscribe<std_msgs::Bool>("/pushed", 1, buttonCb);
00054
00055
00056 actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> client("move_base", true);
00057
00058
00059 ros::ServiceClient srv_client = nh.serviceClient<video_player::PlayVideoSrv>("/wheeled_robin/application/play_video");
00060 video_player::PlayVideoSrv srv;
00061
00062
00063 state st = START;
00064
00065
00066 tf::TransformListener listener;
00067 tf::StampedTransform transform;
00068
00069
00070 double base_range;
00071 ros::param::get("~base_range", base_range);
00072 base_range = base_range*base_range;
00073 std::string person_frame;
00074 ros::param::get("~person_frame", person_frame);
00075
00076 std::string person_threshold_frame;
00077 ros::param::get("~person_threshold_frame", person_threshold_frame);
00078
00079 double button_duration;
00080 ros::param::get("~button_duration", button_duration);
00081 std::string goal_basename;
00082 ros::param::get("~goal_basename", goal_basename);
00083 std::string video_path;
00084 ros::param::get("~video_path", video_path);
00085
00086
00087 ros::Time ask_time;
00088 last_button_msg_time = ros::Time(0);
00089
00090 move_base_msgs::MoveBaseGoal goal;
00091 goal.target_pose.header.frame_id = "map";
00092
00093
00094 ros::Duration(10).sleep();
00095
00096 while(ros::ok()) {
00097 switch(st) {
00098 case START: {
00099 createPoseFromParams("start", &(goal.target_pose));
00100 client.sendGoal(goal);
00101 st = RETURN_START;
00102 ROS_INFO("Switching to state %d", st);
00103 break;
00104 }
00105 case RETURN_START: {
00106 if (client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
00107 st = WAIT_PERSON;
00108 ROS_INFO("Reached start position");
00109 ROS_INFO("Switching to state %d", st);
00110 }
00111 current_goal = 0;
00112 break;
00113 }
00114 case WAIT_PERSON: {
00115 #ifdef DEBUG_STATES
00116 createPoseFromParams("base", &(goal.target_pose));
00117 client.sendGoal(goal);
00118 st = APPROACH_PERSON;
00119 break;
00120 #endif
00121
00122
00123 try {
00124 listener.lookupTransform(person_threshold_frame, person_frame, ros::Time(0), transform);
00125 } catch (tf::TransformException ex) {
00126 ROS_ERROR("%s", ex.what());
00127 break;
00128 }
00129 tf::Vector3 distance = transform.getOrigin();
00130 double person_range = distance.length2();
00131
00132 ROS_INFO("person_range = %f", person_range);
00133 ROS_INFO("base_range = %f", base_range);
00134
00135
00136 if(person_range <= base_range) {
00137 createPoseFromParams("base", &(goal.target_pose));
00138 client.sendGoal(goal);
00139 ROS_INFO("Person within range of base detected");
00140 st = APPROACH_PERSON;
00141 }
00142 break;
00143 }
00144 case APPROACH_PERSON: {
00145 if (client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
00146 st = ASK_PERSON;
00147 ROS_INFO("Reached person");
00148 ROS_INFO("Switching to state %d", st);
00149 }
00150 break;
00151 }
00152 case ASK_PERSON: {
00153 std_msgs::String ask_tour;
00154 ask_tour.data = "Please touch me if you would like to take a tour.";
00155 speech_pub.publish(ask_tour);
00156 ask_time = ros::Time::now();
00157 st = WAIT_BUTTON_TOUR;
00158 ROS_INFO("Switching to state %d", st);
00159 break;
00160 }
00161 case WAIT_BUTTON_TOUR: {
00162 if(ros::Time::now() - ask_time > ros::Duration(10.0)) {
00163 std_msgs::String say_nothanks;
00164 say_nothanks.data = "Thanks for wasting my time. Good bye.";
00165 speech_pub.publish(say_nothanks);
00166 createPoseFromParams("start", &(goal.target_pose));
00167 client.sendGoal(goal);
00168 st = RETURN_START;
00169 ROS_INFO("Switching to state %d", st);
00170 ROS_INFO("No tour requested.");
00171 } else {
00172 if(last_button_msg_time > ask_time && last_button_state) {
00173 std::stringstream ss;
00174 ss << goal_basename;
00175 ss << current_goal;
00176 ROS_INFO("Lookup goal: %s", ss.str().c_str());
00177 createPoseFromParams(ss.str().c_str(), &(goal.target_pose));
00178 client.sendGoal(goal);
00179 ROS_INFO("Tour requested");
00180 st = APPROACH_PRESENTATION;
00181 ROS_INFO("Switching to state %d", st);
00182 }
00183 }
00184 break;
00185 }
00186 case APPROACH_PRESENTATION: {
00187 if (client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED) {
00188 st = PRESENT;
00189 ROS_INFO("Switching to state %d", st);
00190 }
00191 break;
00192 case PRESENT:
00193 std::stringstream ss;
00194 ss << "/goals/";
00195 ss << goal_basename;
00196 ss << current_goal;
00197 ss << "/folder";
00198 ros::param::get(ss.str().c_str(), srv.request.videoPath);
00199 srv.request.videoPath = video_path + srv.request.videoPath;
00200 #ifdef DEBUG_STATES
00201 st = ASK_REPETITION;
00202 ROS_INFO("Switching to state %d", st);
00203 break;
00204 #endif
00205 if (srv_client.call(srv)){
00206 ROS_INFO("Presentation successful");
00207 } else {
00208 ROS_ERROR("Presentation failed");
00209 }
00210 st = ASK_REPETITION;
00211 ROS_INFO("Switching to state %d", st);
00212 break;
00213 }
00214 case ASK_REPETITION: {
00215 std_msgs::String ask_pres;
00216 ask_pres.data = "Please touch me if you would like to see the presentation again.";
00217 speech_pub.publish(ask_pres);
00218 ask_time = ros::Time::now();
00219 st = WAIT_BUTTON_REPETITION;
00220 ROS_INFO("Switching to state %d", st);
00221 break;
00222 }
00223 case WAIT_BUTTON_REPETITION: {
00224 if(ros::Time::now() - ask_time <= ros::Duration(button_duration)) {
00225 if(last_button_msg_time > ask_time && last_button_state) {
00226 st = PRESENT;
00227 ROS_INFO("Button pressed");
00228 ROS_INFO("Switching to state %d", st);
00229 }
00230 } else {
00231 current_goal++;
00232 std::stringstream ss;
00233 ss << goal_basename;
00234 ss << current_goal;
00235 ROS_INFO("Next goal is: %s", ss.str().c_str());
00236 std::stringstream check;
00237 check << "/goals/";
00238 check << ss.str();
00239 check << "/x";
00240 if(ros::param::has(check.str().c_str())) {
00241 createPoseFromParams(ss.str().c_str(), &(goal.target_pose));
00242 client.sendGoal(goal);
00243 st = APPROACH_PRESENTATION;
00244 ROS_INFO("Switching to state %d", st);
00245 std_msgs::String say_continue;
00246 say_continue.data = "Okay, let us continue with the next stop.";
00247 speech_pub.publish(say_continue);
00248 } else {
00249 st = TALK_BYE;
00250 ROS_INFO("Switching to state %d", st);
00251 }
00252 }
00253 break;
00254 }
00255 case TALK_BYE: {
00256 std_msgs::String say_bye;
00257 say_bye.data = "I hope you enjoyed the tour. Thanks for visiting us. Please follow me back to the start.";
00258 speech_pub.publish(say_bye);
00259 createPoseFromParams("start", &(goal.target_pose));
00260 client.sendGoal(goal);
00261 st = RETURN_START;
00262 ROS_INFO("Switching to state %d", st);
00263 break;
00264 }
00265 default:
00266 ;
00267 }
00268
00269 ros::spinOnce();
00270 loop_rate.sleep();
00271 }
00272
00273 return 0;
00274 }
00275
00286 void createPoseFromParams(std::string param_name, geometry_msgs::PoseStamped* pose) {
00287 pose->header.stamp = ros::Time::now();
00288 ros::param::get("/goals/"+param_name+"/x", pose->pose.position.x);
00289 ros::param::get("/goals/"+param_name+"/y", pose->pose.position.y);
00290 ros::param::get("/goals/"+param_name+"/z", pose->pose.position.z);
00291 ros::param::get("/goals/"+param_name+"/q1", pose->pose.orientation.x);
00292 ros::param::get("/goals/"+param_name+"/q2", pose->pose.orientation.y);
00293 ros::param::get("/goals/"+param_name+"/q3", pose->pose.orientation.z);
00294 ros::param::get("/goals/"+param_name+"/q4", pose->pose.orientation.w);
00295 }
00296
00306 void buttonCb(std_msgs::Bool msg) {
00307 last_button_msg_time = ros::Time::now();
00308 last_button_state = msg.data;
00309
00310 }