action_executor.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 import actionlib
00004 import rospy
00005 import threading
00006 import time
00007 import yaml
00008 
00009 from bwi_planning_common.srv import PlannerInterface
00010 from bwi_planning_common.msg import PlannerAtom
00011 from bwi_tools import WallRate
00012 from geometry_msgs.msg import PoseWithCovarianceStamped
00013 from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
00014 from segbot_gui.srv import QuestionDialog, QuestionDialogRequest
00015 from segbot_simulation_apps.srv import DoorHandlerInterface
00016 from sound_play.msg import SoundRequest
00017 
00018 from .atom import Atom
00019 
00020 def point_in_polygon(point, polygon):
00021     nvert = len(polygon)
00022     c = False
00023     j = nvert - 1
00024     for i in range(nvert):
00025         if (((polygon[i][1] >= point[1]) != (polygon[j][1] >= point[1])) and
00026             (point[0] <= ((polygon[j][0] - polygon[i][0]) * 
00027                           (point[1] - polygon[i][1]) / 
00028                           (polygon[j][1] - polygon[i][1])) + polygon[i][0])):
00029             c = not c
00030         j = i
00031     return c
00032 
00033 class ActionExecutor(object):
00034 
00035     def __init__(self, dry_run=False, initial_file=None, atom_class=Atom):
00036 
00037         self.dry_run = dry_run
00038         if self.dry_run:
00039             rospy.loginfo("This is a dry run. The expected next state will " +
00040                           "be used to generate observations.")
00041         self.auto_open_door = rospy.get_param("~auto_open_door", False)
00042         self.initial_file = initial_file
00043 
00044         # Atificially slow the robot down in the specified areas
00045         self.artificial_delays = None
00046         self.artificial_delay_file = \
00047                 rospy.get_param("~artificial_delay_file", None)
00048         if self.artificial_delay_file:
00049             rospy.loginfo("Using artificial delays read from " + 
00050                           self.artificial_delay_file)
00051             adf = open(self.artificial_delay_file)
00052             self.artificial_delays = yaml.load(adf)
00053             adf.close()
00054             self.pose_subscriber = rospy.Subscriber("amcl_pose", 
00055                                                     PoseWithCovarianceStamped, 
00056                                                     self.pose_handler)
00057             self.move_base_client = actionlib.SimpleActionClient(
00058                 'move_base', MoveBaseAction)
00059             self.move_base_client.wait_for_server()
00060 
00061         # segbot gui
00062         rospy.loginfo("Waiting for GUI to come up...")
00063         rospy.wait_for_service('question_dialog')
00064         self._gui = rospy.ServiceProxy('question_dialog', QuestionDialog)
00065         rospy.loginfo("  Found GUI")
00066         self.use_speech = rospy.get_param("~use_speech", False)
00067 
00068         if self.use_speech:
00069             rospy.loginfo("  Will Speak")
00070             self.sound_publisher = rospy.Publisher('robotsound', SoundRequest)
00071 
00072         if not self.dry_run: 
00073 
00074             # logical task executor
00075             rospy.wait_for_service('execute_logical_goal')
00076             self.nav_executor = rospy.ServiceProxy('execute_logical_goal', 
00077                                              PlannerInterface)
00078 
00079             # simulation - automatic door opening
00080             if self.auto_open_door:
00081                 self.update_doors = rospy.ServiceProxy('update_doors', 
00082                                                  DoorHandlerInterface)
00083         self.atom_class = atom_class
00084 
00085     def gui(self, displayType, text, choices, timeout):
00086         if self.use_speech:
00087             req = SoundRequest()
00088             req.sound = SoundRequest.SAY
00089             req.command = SoundRequest.PLAY_ONCE
00090             req.arg = text
00091             self.sound_publisher.publish(req)
00092         return self._gui(displayType, text, choices, timeout)
00093 
00094     def clear_gui(self):
00095         self._gui(QuestionDialogRequest.DISPLAY, "", [], 0.0) 
00096 
00097     def pose_handler(self, msg):
00098         self.position_frame_id = msg.header.frame_id
00099         self.pose = msg.pose.pose
00100         self.position = msg.pose.pose.position
00101 
00102     def stop_robot(self):
00103         goal = MoveBaseGoal()
00104         goal.target_pose.header.stamp = rospy.get_rostime()
00105         goal.target_pose.header.frame_id = self.position_frame_id
00106         goal.target_pose.pose = self.pose
00107         self.move_base_client.send_goal(goal)
00108         self.move_base_client.wait_for_result()
00109 
00110     def artificial_delay_handler(self):
00111         self.expect_artificial_delays = True
00112         delays_encountered = []
00113         r = rospy.Rate(1)
00114         while self.expect_artificial_delays:
00115             for i,delay in enumerate(self.artificial_delays):
00116                 if i in delays_encountered:
00117                     continue
00118                 if point_in_polygon([self.position.x, self.position.y],
00119                                     delay['location']):
00120                     print "in delay region"
00121                     delays_encountered.append(i)
00122                     self.artificial_delay_time = delay['time']
00123                     self.stopping_for_artificial_delay = True
00124                     self.stop_robot()
00125             r.sleep()
00126 
00127     def sense_initial_state(self):
00128 
00129         if self.dry_run:
00130             # Assume initial file supplied by user has initial state
00131             return
00132 
00133         if self.auto_open_door:
00134             self.update_doors("", False, True) #Close all doors
00135 
00136         result = self.nav_executor(PlannerAtom("noop", []))
00137         
00138         initial_file = open(self.initial_file,"w")
00139         display_message = "Initial state: "
00140         for fluent in result.observations:
00141             atom = self.atom_class(fluent.name, ",".join(fluent.value), time=0)
00142             initial_file.write(str(atom) + ".\n")
00143             display_message += str(atom) + " "
00144         initial_file.close()
00145         rospy.loginfo(display_message)
00146         rospy.loginfo("Sensed initial state stored in: " + self.initial_file)
00147 
00148     def execute_action(self, action, next_state, next_step):
00149 
00150         rospy.loginfo("Executing action: " + str(action))
00151 
00152         if self.dry_run and action.name != "askploc" and action.name != "greet":
00153             time.sleep(1)
00154             rospy.loginfo("  Observations: " + str(next_state))
00155             return True, next_state
00156 
00157         success = False
00158         if (action.name == "approach" or action.name == "gothrough" or
00159            action.name == "goto"):
00160 
00161             self.stopping_for_artificial_delay = False
00162             if self.artificial_delays:
00163                 self.artificial_delay_thread = \
00164                         threading.Thread(target=self.artificial_delay_handler)
00165                 self.artificial_delay_thread.start()
00166 
00167             while True:
00168                 response = self.nav_executor(PlannerAtom(action.name, 
00169                                                          [str(action.value)]))
00170                 if response.success or not self.stopping_for_artificial_delay:
00171                     break
00172                 rospy.sleep(self.artificial_delay_time)
00173                 self.stopping_for_artificial_delay = False
00174 
00175             if self.artificial_delays:
00176                 self.expect_artificial_delays = False
00177                 self.artificial_delay_thread.join()
00178 
00179             if self.auto_open_door:
00180                 # close the door now that it was automatically opened
00181                 self.update_doors(str(action.value), False, False)
00182                 
00183             success = response.success 
00184             result = response.observations
00185 
00186         # opendoor, askploc, greet
00187         if action.name == "opendoor":
00188             if self.auto_open_door:
00189                 self.update_doors(str(action.value), True, False)
00190             else:
00191                 self.gui(QuestionDialogRequest.DISPLAY,
00192                          "Can you open door " + str(action.value) + "?",
00193                          [], 0.0)
00194             rate = WallRate(0.5)
00195             door_opened = False
00196             for i in range(60):
00197                 response = self.nav_executor(PlannerAtom("sensedoor", 
00198                                               [str(action.value)]))
00199                 result = response.observations
00200                 for fluent in result:
00201                     if (fluent.name == "open" and 
00202                         fluent.value[0] == str(action.value)):
00203                         if not self.auto_open_door:
00204                             self.gui(QuestionDialogRequest.DISPLAY,
00205                                      "Thanks!!", [], 0.0)
00206                         door_opened = True
00207                         break
00208                 if door_opened:
00209                     break
00210                 rate.sleep()
00211             if door_opened:
00212                 success = True
00213 
00214         if action.name == "askploc":
00215             response = self.gui(QuestionDialogRequest.TEXT_QUESTION, 
00216                            "Can you tell me where " + str(action.value) + 
00217                                 " is?",
00218                            [], 30.0)
00219             if response.index == QuestionDialogRequest.TEXT_RESPONSE:
00220                 result = [PlannerAtom("inside",
00221                                       [str(action.value), response.text])] 
00222                 success = True
00223             else:
00224                 # The request timed out, so send back no observations
00225                 result = []
00226 
00227         if action.name == "greet":
00228             self.gui(QuestionDialogRequest.DISPLAY,
00229                      "Hello " + str(action.value) + "!!",
00230                      [], 0.0)
00231             time.sleep(2.0)
00232             result =  [PlannerAtom("visiting",[str(action.value)])]
00233             success = True
00234 
00235         observations = []
00236         for fluent in result:
00237             observations.append(self.atom_class(fluent.name, 
00238                                                 ",".join(fluent.value),
00239                                                 time=next_step))
00240         rospy.loginfo("  Observations: " + str(observations))
00241         self.clear_gui()
00242         return success, observations
00243 
00244 


bwi_planning
Author(s): Piyush Khandelwal , Fangkai Yang
autogenerated on Wed Aug 26 2015 10:54:52