session.py
Go to the documentation of this file.
00001 '''Everything related to the state of actions and primitives
00002 in the current session
00003 '''
00004 
00005 # ######################################################################
00006 # Imports
00007 # ######################################################################
00008 
00009 # Core ROS imports come first.
00010 import rospy
00011 
00012 # System builtins
00013 import datetime
00014 import threading
00015 import couchdb
00016 import json
00017 
00018 # ROS builtins
00019 from tf import TransformBroadcaster
00020 from std_srvs.srv import Empty as EmptySrv
00021 from std_msgs.msg import Empty as EmptyMsg
00022 from std_msgs.msg import String
00023 from rail_manipulation_msgs.srv import SuggestGrasps
00024 from geometry_msgs.msg import PoseStamped
00025 
00026 # Local
00027 from fetch_pbd_interaction.action import Action
00028 from fetch_pbd_interaction.arm_target import ArmTarget
00029 from fetch_pbd_interaction.arm_trajectory  import ArmTrajectory
00030 from fetch_pbd_interaction.grasp  import Grasp
00031 from fetch_pbd_interaction.msg import SessionState, ExecutionStatus, \
00032                                         Landmark
00033 from fetch_pbd_interaction.srv import GetSessionState, \
00034                                      GetSessionStateResponse, \
00035                                      GetObjectList
00036 
00037 # ######################################################################
00038 # Classes
00039 # ######################################################################
00040 
00041 class Session:
00042     '''Everything related to the state of actions and primitives
00043     in the current session
00044     '''
00045 
00046     def __init__(self, robot, _tf_listener, im_server, 
00047                 from_file=None, to_file=None, 
00048                 grasp_suggestion_service_name=None,
00049                 grasp_feedback_topic=None,
00050                 external_ee_link=None):
00051         '''
00052         Args:
00053             robot (Robot) : interface to lower level robot functionality
00054             tf_listener (TransformListener)
00055             im_server (InteractiveMarkerSerever)
00056         '''
00057         self._lock = threading.Lock()
00058         self._from_file = from_file
00059         self._to_file = to_file
00060         self._grasp_suggestion_service = grasp_suggestion_service_name
00061         self._grasp_feedback_topic = grasp_feedback_topic
00062         self._external_ee_link = external_ee_link
00063         
00064         self._json = {}
00065         self._robot = robot
00066         self._tf_listener = _tf_listener
00067         self._tf_broadcaster = TransformBroadcaster()
00068 
00069         self._im_server = im_server
00070 
00071         self._couch = couchdb.Server()
00072         try:
00073             self._db = self._couch['fetch_pbd']
00074         except:
00075             self._db = self._couch.create('fetch_pbd')
00076 
00077         # Dict (keys = ids, values = actions)
00078         self._actions = {}
00079         # Sorted list of action ids
00080         self._action_ids = []
00081         self._current_action_id = None
00082         # -1 means None selected, used because SessionState.msg uses int8
00083         self._selected_primitive = -1
00084         self._current_arm_trajectory = None
00085         self._marker_visibility = []
00086         self._head_busy = False
00087 
00088         self._actions_disabled = []
00089 
00090         # Publishers & Services
00091         self._state_publisher = rospy.Publisher('/fetch_pbd/session_state',
00092                                                 SessionState,
00093                                                 queue_size=10)
00094         self._status_publisher = rospy.Publisher('/fetch_pbd/fetch_pbd_status',
00095                                                 String,
00096                                                 queue_size=10)
00097         rospy.Service('/fetch_pbd/get_session_state', GetSessionState,
00098                       self._get_session_state_cb)
00099         
00100         self._get_object_list_srv = rospy.ServiceProxy(
00101                                                 '/fetch_pbd/get_object_list',
00102                                                 GetObjectList)
00103         self._update_world_srv = rospy.ServiceProxy('/fetch_pbd/update_world',
00104                                                     GetObjectList)
00105         rospy.wait_for_service('/fetch_pbd/update_world')
00106         rospy.loginfo("Got update_world service.")
00107 
00108 
00109         self._clear_world_objects_srv = \
00110                         rospy.ServiceProxy('/fetch_pbd/clear_world_objects', 
00111                                             EmptySrv)
00112         rospy.wait_for_service('/fetch_pbd/clear_world_objects')
00113         rospy.loginfo("Got clear_world_objects service.")
00114 
00115         self._load_session_state()
00116         rospy.loginfo("Session state loaded.")
00117 
00118         # Send initial broadcast of experiment state.
00119         self._update_session_state()
00120 
00121     # ##################################################################
00122     # Instance methods: Public (API)
00123     # ##################################################################
00124 
00125     def head_busy(self):
00126         '''Returns true if head is busy
00127         
00128         Returns:
00129             bool
00130         '''
00131         if self.n_actions() < 1 or self._current_action_id is None:
00132             return False or self._head_busy
00133         action = self._actions[self._current_action_id]
00134         return action.head_busy() or self._head_busy
00135 
00136     def select_action_primitive(self, primitive_id):
00137         ''' Makes the interactive marker for the indicated action primitive
00138         selected by showing the 6D controls.
00139 
00140         Args:
00141             primitive_id (int): ID of the primitive to select.
00142         '''
00143         # If already selected, un-select, else select
00144         rospy.loginfo("new: {}, selected: {}".format(primitive_id, 
00145                         self._selected_primitive))
00146         if primitive_id == self._selected_primitive:
00147             is_selected = False
00148         else:
00149             is_selected = True
00150         self._actions[self._current_action_id].select_primitive(primitive_id, 
00151                                                                 is_selected)
00152 
00153     def new_action(self, name=None):
00154         '''Creates new action.'''
00155         self._clear_world_objects_srv()
00156         if self.n_actions() > 0:
00157             if not self._current_action_id is None:
00158                 self.get_current_action().reset_viz()
00159             self._current_action_id = self.n_actions()
00160         else:
00161             self._current_action_id = 0
00162 
00163         # action_id = self._db.insert_new(name)
00164         action = Action(self._robot,
00165                         self._tf_listener,
00166                         self._im_server,
00167                         self._selected_primitive_cb,
00168                         self._action_change_cb,
00169                         self._current_action_id,
00170                         self._grasp_suggestion_service,
00171                         self._grasp_feedback_topic,
00172                         self._external_ee_link)
00173         if not name is None:
00174             action.set_name(name)
00175         else:
00176             time_str = datetime.datetime.now().strftime('%c')
00177             action.set_name("Untitled action {}".format(time_str))
00178 
00179         self._actions.update({
00180             self._current_action_id: action
00181         })
00182         self._actions_disabled.append(False)
00183         self._action_ids.append(self._current_action_id)
00184         self._marker_visibility = [True] * self.n_primitives()
00185         self._update_session_state()
00186 
00187     def n_actions(self):
00188         '''Returns the number of actions programmed so far.
00189 
00190         Returns:
00191             int
00192         '''
00193         return len(self._actions)
00194 
00195     def get_current_action(self):
00196         '''Returns the current action.
00197 
00198         Returns:
00199             Action
00200         '''
00201         if self.n_actions() > 0 and not self._current_action_id is None:
00202             action = self._actions[self._current_action_id]
00203             return action
00204         else:
00205             return None
00206 
00207     def clear_current_action(self):
00208         '''Removes all primitives in the current action.'''
00209         if self.n_actions() > 0:
00210             current_action = self._actions[self._current_action_id]
00211             current_action.clear()
00212         else:
00213             rospy.logwarn("Can't clear action: No actions created yet.")
00214         self._update_session_state()
00215 
00216     def update_arm_trajectory(self):
00217         '''Saves current arm state into continuous trajectory.'''
00218         if self._current_arm_trajectory is not None:
00219             arm_state = self._robot.get_arm_state()
00220             gripper_state = self._robot.get_gripper_state()
00221             self._current_arm_trajectory.add_step(arm_state,
00222                                                        gripper_state)
00223 
00224     def start_recording_arm_trajectory(self):
00225         '''Creates ArmTrajectory primitive that will be updated
00226         by update_arm_trajectory
00227         '''
00228         current_action = self._actions[self._current_action_id]
00229         primitive_number = current_action.n_primitives()
00230         self._current_arm_trajectory = ArmTrajectory(self._robot,
00231                     self._tf_listener, self._im_server, primitive_number)
00232 
00233     def stop_recording_arm_trajectory(self):
00234         '''Finalises ArmTrajectory primitive.
00235         Updates the references frames and saves it to the db.
00236         '''
00237         if self.n_actions() > 0:
00238             current_action = self._actions[self._current_action_id]
00239             current_action.add_primitive(self._current_arm_trajectory, False)
00240             self.publish_primitive_tf()
00241             current_action.make_primitive_marker(-1)
00242         else:
00243             rospy.logwarn("Can't add primitive: No actions created yet.")
00244         self._update_session_state()
00245         self._current_arm_trajectory = None
00246 
00247     def add_arm_target_to_action(self):
00248         '''Add a new ArmTarget primitive to the current action.'''
00249 
00250         if self.n_actions() > 0:
00251             arm_state = self._robot.get_arm_state()
00252             gripper_state = self._robot.get_gripper_state()
00253             rospy.loginfo("gripper_state: {}".format(gripper_state))
00254             current_action = self._actions[self._current_action_id]
00255             primitive_number = current_action.n_primitives()
00256             arm_target = ArmTarget(self._robot, self._tf_listener,
00257                                    self._im_server, arm_state,
00258                                    gripper_state, primitive_number)
00259 
00260             current_action.add_primitive(arm_target)
00261         else:
00262             rospy.logwarn("Can't add primitive: No actions created yet.")
00263         self._update_session_state()
00264 
00265     def add_grasp_to_action(self, landmark):
00266         '''Add a grasp primitive to the current action.
00267 
00268         Args:
00269             landmark (Landmark)
00270         '''
00271         if self.n_actions() > 0:
00272             current_action = self._actions[self._current_action_id]
00273             primitive_number = current_action.n_primitives()
00274             grasp = Grasp(self._robot, self._tf_listener, 
00275                               self._im_server, 
00276                               self._grasp_suggestion_service,
00277                               self._grasp_feedback_topic,
00278                               self._external_ee_link, 
00279                               landmark,
00280                               primitive_number)
00281             current_action.add_primitive(grasp)            
00282         else:
00283             rospy.logwarn("Can't add grasp: No actions created yet.")
00284         self._update_session_state()
00285 
00286     def delete_last_primitive(self):
00287         '''Removes the last primitive of the action.'''
00288         if self.n_actions() > 0:
00289             current_action = self._actions[self._current_action_id]
00290             current_action.delete_last_primitive()
00291         else:
00292             rospy.logwarn("Can't delete last primitive:" +
00293                           " No actions created yet.")
00294         self._update_session_state()
00295 
00296     def switch_to_action_by_index(self, index):
00297         '''Switches to action with index
00298 
00299         Args:
00300             index (int): The action id to switch to.
00301 
00302         Returns:
00303             bool: Whether successfully switched to index action.
00304         '''
00305         self._im_server.clear()
00306         self._im_server.applyChanges()
00307         self._lock.acquire()
00308         self._selected_primitive = -1
00309 
00310         if index < 0 or index >= len(self._actions):
00311             rospy.logwarn("Index out of bounds: {}".format(index))
00312             return False
00313 
00314         if self.n_actions() > 0 and not self._current_action_id is None:
00315             self.get_current_action().reset_viz()
00316 
00317         if not index in self._actions:
00318             rospy.logwarn(
00319                 "Can't switch actions: failed to load action {}".format(
00320                     index))
00321             return False
00322         else:
00323             rospy.loginfo(
00324                 "Switching to action {}".format(
00325                     index))
00326 
00327         self._current_action_id = index
00328         self._clear_world_objects_srv()
00329         self._lock.release()
00330         try:
00331             rospy.wait_for_message('/fetch_pbd/action_loaded', EmptyMsg, timeout=1000)
00332         except Exception, e:
00333             rospy.logwarn("Timed out waiting for frontend to respond")
00334         self.get_current_action().initialize_viz()
00335         self._update_session_state()
00336         self.publish_primitive_tf()
00337         action = self._actions[self._current_action_id]
00338         for i in range(self.n_primitives()):
00339             try:
00340                 self._tf_listener.waitForTransform("base_link",
00341                              "primitive_" + str(i),
00342                              rospy.Time.now(),
00343                              rospy.Duration(5.0))
00344                 rospy.loginfo("primitive: {}".format(action.get_primitive(i)))
00345                 action.get_primitive(i).update_viz(False)
00346             except Exception, e:
00347                 rospy.loginfo("Frame primitive_" + str(i) +
00348                               " is not available.")
00349         return True
00350 
00351     def switch_to_action_by_name(self, name):
00352         '''Switches to action with name
00353 
00354             Args:
00355                 name (str): The action name to switch to.
00356 
00357             Returns:
00358                 bool: Whether successfully switched to index action.
00359         '''
00360         names = self._get_action_names()
00361         if name in names:
00362             index = names.index(name)
00363             return self.switch_to_action_by_index(index)
00364         else:
00365             return False
00366 
00367     def next_action(self):
00368         '''Switches to the next action.
00369 
00370         Returns:
00371             bool: Whether successfully switched to the next action.
00372         '''
00373         index = self._action_ids.index(self._current_action_id)
00374         if index == len(self._actions) - 1:
00375             rospy.logerr("Already on the last action.")
00376             return False
00377         action_id = self._action_ids[index + 1]
00378         return self.switch_to_action_by_index(action_id)
00379 
00380     def previous_action(self):
00381         '''Switches to the previous action.
00382 
00383         Returns:
00384             bool: Whether successfully switched to the previous action.
00385         '''
00386         index = self._action_ids.index(self._current_action_id)
00387         if index == 0:
00388             rospy.logerr("Already on the first action.")
00389             return False
00390         action_id = self._action_ids[index - 1]
00391         return self.switch_to_action_by_index(action_id)
00392 
00393     def n_primitives(self):
00394         '''Returns the number of primitives in the current action, or 0 if
00395         there is no current action.
00396 
00397         Returns:
00398             int
00399         '''
00400         if self.n_actions() > 0 and not self._current_action_id is None:
00401             return self._actions[self._current_action_id].n_primitives()
00402         else:
00403             rospy.logwarn(
00404                 "Can't get number of primitives: No actions created yet.")
00405             return 0
00406 
00407     def update_action_name(self, name):
00408         '''Update name of current action
00409 
00410         Args:
00411             name (string)
00412         '''
00413         if not self._current_action_id is None:
00414             self.get_current_action().set_name(name)
00415             self._update_session_state()
00416 
00417     def copy_action(self, action_id):
00418         '''Make a copy of action
00419 
00420         Args:
00421             action_id (int)
00422         '''
00423         self._clear_world_objects_srv()
00424 
00425         new_id = self.n_actions()
00426 
00427         map_fun = '''function(doc) {
00428                      emit(doc.id, doc);
00429                   }'''
00430 
00431         results = self._db.query(map_fun)
00432 
00433         # Load data from db into Action objects.
00434         for result in results:
00435             if int(result.value['id']) == action_id:
00436                 action = Action(self._robot, self._tf_listener, self._im_server,
00437                            self._selected_primitive_cb, self._action_change_cb,
00438                            grasp_suggestion_service=self._grasp_suggestion_service,
00439                            grasp_feedback_topic=self._grasp_feedback_topic,
00440                            external_ee_link=self._external_ee_link)
00441                 result.value['id'] = new_id
00442                 action.build_from_json(result.value)
00443                 name = action.get_name()
00444                 action.set_name("Copy of " + name)
00445                 self._actions[new_id] = action
00446                 self._action_ids.append(new_id)
00447 
00448         self._current_action_id = new_id
00449         self._update_session_state()
00450 
00451 
00452     def copy_primitive(self, primitive_number):
00453         '''Make a copy of a primitive
00454 
00455         Args:
00456             primitive (int)
00457         '''
00458         # new_id = self.n_actions()
00459 
00460         map_fun = '''function(doc) {
00461                      emit(doc.id, doc);
00462                   }'''
00463 
00464         results = self._db.query(map_fun)
00465 
00466         # Load data from db into Action objects.
00467         new_num = self.n_primitives()
00468         for result in results:
00469             if int(result.value['id']) == self._current_action_id:
00470                 for idx, primitive in enumerate(result.value['seq']):
00471                     if idx == primitive_number:
00472                         if primitive.has_key('arm_target'):
00473                             target = primitive['arm_target']
00474                             primitive_copy = ArmTarget(self._robot,
00475                                                        self._tf_listener,
00476                                                        self._im_server)
00477                             primitive_copy.build_from_json(target)
00478                             primitive_copy.set_primitive_number(new_num)
00479                             break
00480 
00481                         elif primitive.has_key('arm_trajectory'):
00482                             target = primitive['arm_trajectory']
00483                             primitive_copy = ArmTrajectory(self._robot,
00484                                                            self._tf_listener,
00485                                                            self._im_server)
00486                             primitive_copy.build_from_json(target)
00487                             primitive_copy.set_primitive_number(new_num)
00488                             break
00489                         elif primitive.has_key('grasp'):
00490                             target = primitive['grasp']
00491                             primitive_copy = Grasp(self._robot,
00492                                                self._tf_listener,
00493                                                self._im_server,
00494                                                self._grasp_suggestion_service,
00495                                                self._grasp_feedback_topic,
00496                                                self._external_ee_link)
00497                             primitive_copy.build_from_json(target)
00498                             primitive_copy.set_primitive_number(new_num)
00499                             break
00500 
00501         self._actions[self._current_action_id].add_primitive(primitive_copy)
00502 
00503         self._actions[self._current_action_id].update_viz()
00504 
00505         self._update_session_state()
00506 
00507     def delete_action_current_action(self):
00508         '''Delete current action'''
00509         self.delete_action(self._current_action_id)
00510 
00511     def delete_action(self, action_id):
00512         '''Deletes action by id
00513 
00514         Args:
00515             action_id (string|int)
00516         '''
00517         if self.n_actions > 0:
00518             self._lock.acquire()
00519             rospy.loginfo('Deleting action')
00520             if int(action_id) == self._current_action_id:
00521                 if len(self._action_ids) == 1:
00522                     self._current_action_id = None
00523                     self._actions = {}
00524                     self._action_ids = []
00525                     action_id_str = str(action_id)
00526                     if action_id_str in self._db:
00527                         self._db.delete(self._db[action_id_str])
00528                     self._lock.release()
00529                     self._update_session_state()
00530                     return
00531                 else:
00532                     self._current_action_id-=1
00533 
00534             action_id_str = str(action_id)
00535             # rospy.loginfo(self._actions)
00536             if action_id in self._actions:
00537                 del self._actions[int(action_id)]
00538             if action_id_str in self._db:
00539                 self._db.delete(self._db[action_id_str])
00540 
00541             # new_actions = {}
00542             for a_id in range(int(action_id) + 1, len(self._actions)):
00543                 action = self._actions[a_id]
00544                 action.decrease_id()
00545                 del self._actions[a_id]
00546                 rospy.loginfo("id: {}".format(action.get_action_id()))
00547                 self._actions[action.get_action_id()] = action
00548 
00549                 if str(a_id) in self._db:
00550                     self._db.delete(self._db[str(a_id)])
00551 
00552                 self._update_db_with_action(action)
00553 
00554             if len(self._action_ids) > 0:
00555                 self._action_ids.pop()
00556             if int(action_id) == self._current_action_id:
00557                 self._current_action_id = self._action_ids[-1]
00558             elif int(action_id) < self._current_action_id:
00559                 self._current_action_id = self._current_action_id - 1
00560             self._lock.release()
00561             self._update_session_state()
00562 
00563     def switch_primitive_order(self, old_index, new_index):
00564         '''Change the order of primitives in action
00565 
00566         Args:
00567             old_index (int)
00568             new_index (int)
00569         '''
00570         rospy.loginfo("Switching primitive order")
00571 
00572         self._lock.acquire()
00573         action = self._actions[self._current_action_id]
00574         action.switch_primitive_order(old_index, new_index)
00575         self._update_db_with_current_action()
00576         self._lock.release()
00577         self.publish_primitive_tf()
00578         action = self._actions[self._current_action_id]
00579         primitives = action.get_primitives()
00580         for primitive in primitives:
00581             primitive.show_marker()
00582         self._update_session_state()
00583 
00584     def delete_primitive(self, primitive_number):
00585         '''Delete specified primitive
00586 
00587         Args:
00588             primitive_number (int) : Number of primitive to be deleted
00589         '''
00590         # self._lock.acquire()
00591         action = self._actions[self._current_action_id]
00592         action.delete_primitive(primitive_number)
00593         # self._lock.release()
00594         # self._update_db_with_current_action()
00595 
00596     def hide_primitive_marker(self, primitive_number):
00597         '''Hide marker with primitive_number
00598 
00599         Args:
00600             primitive_number (int)
00601         '''
00602         # self._lock.acquire()
00603         # self._marker_visibility[primitive_number] = False
00604         action = self._actions[self._current_action_id]
00605         action.delete_primitive_marker(primitive_number)
00606         self._update_session_state()
00607         # self._lock.release()
00608 
00609     def show_primitive_marker(self, primitive_number):
00610         '''Show marker with primitive_number
00611 
00612         Args:
00613             primitive_number (int)
00614         '''
00615         # self._lock.acquire()
00616         # self._marker_visibility[primitive_number] = True
00617         action = self._actions[self._current_action_id]
00618         action.make_primitive_marker(primitive_number)
00619         self._update_session_state()
00620         # self._lock.release()
00621 
00622     def execute_primitive(self, primitive_number):
00623         '''Execute primitive with number
00624 
00625         Args:
00626             primitive_number (int)
00627         '''
00628         rospy.loginfo("Executing primitive")
00629 
00630         action = self._actions[self._current_action_id]
00631         primitive = action.get_primitive(primitive_number)
00632         if primitive.is_object_required():
00633             # We need an object; check if we have one.
00634             self._head_busy = True
00635             rospy.loginfo("Object required for execution")
00636             self._robot.look_down()
00637             resp = self._update_world_srv()
00638             if resp.object_list:
00639                 rospy.loginfo("Object list not empty")
00640                 # An object is required, and we got one. Execute.
00641                 self.get_current_action().update_objects()
00642                 success, msg = primitive.check_pre_condition()
00643                 if not success:
00644                     rospy.logwarn(
00645                         "\tPreconditions of primitive " + 
00646                         str(primitive.get_name()) + " are not " +
00647                         "satisfied. " + msg)
00648                     self._status_publisher.publish(
00649                         String("Preconditions of primitive " + 
00650                         str(primitive.get_name()) +
00651                         " are not satisfied. " + msg))
00652                 primitive.execute()
00653             else:
00654                 rospy.logwarn("Needs object(s) but none available")
00655                 self._status_publisher.publish(
00656                         "Primitive {}".format(primitive.get_name()) +
00657                         "requires an object but none are available")
00658             self._head_busy = False
00659         else:
00660             success, msg = primitive.check_pre_condition()
00661             if not success:
00662                 rospy.logwarn(
00663                         "\tPreconditions of primitive " + 
00664                         str(primitive.get_name()) + " are not " +
00665                         "satisfied. " + msg)
00666                 self._status_publisher.publish(
00667                     String("Preconditions of primitive " + 
00668                     str(primitive.get_name()) +
00669                     " are not satisfied. " + msg))
00670             primitive.execute()
00671         self._async_update_session_state()
00672 
00673 
00674     def record_objects(self):
00675         '''Records poses of objects
00676         '''
00677         self._robot.look_down()
00678         resp = self._update_world_srv()
00679         if resp.object_list:
00680             if self.n_actions() > 0:
00681                 self.get_current_action().update_objects()
00682             self._async_update_session_state()
00683             self._robot.look_forward()
00684             return  True
00685         else:
00686             self._async_update_session_state()
00687             self._robot.look_forward()
00688             return False
00689 
00690     def execute_current_action(self):
00691         '''Executes current action
00692 
00693         Returns:
00694             bool
00695         '''
00696         if self.n_actions() > 0 and not self._current_action_id is None:
00697             # We must have also recorded primitives (/poses/frames) in it.
00698             if self.n_primitives() > 0:
00699                 # Save curent action and retrieve it.
00700                 # self._session.save_current_action()
00701 
00702                 # Now, see if we can execute.
00703                 if self.get_current_action().is_object_required():
00704                     # We need an object; check if we have one.
00705                     rospy.loginfo("An object is required for this action")
00706                     self._robot.look_down()
00707                     resp = self._update_world_srv()
00708                     self._robot.look_forward()
00709 
00710                     # objects = resp.objects
00711                     if resp.object_list:
00712                         # An object is required, and we got one. Execute.
00713                         action = self.get_current_action()
00714                         action.update_objects()
00715                         action.start_execution()
00716                         # Wait a certain max time for execution to finish
00717                         for i in range(1000):
00718                             status = action.get_status()
00719                             if status != ExecutionStatus.EXECUTING:
00720                                 break
00721                             if i % 10 == 0:
00722                                 rospy.loginfo("Still executing")
00723                             rospy.sleep(0.1)
00724                         if status == ExecutionStatus.SUCCEEDED:
00725                             action.end_execution()
00726                             self._async_update_session_state()
00727                             return True
00728                         else:
00729                             action.end_execution()
00730                             self._async_update_session_state()
00731                             return False
00732 
00733                     else:
00734                         # An object is required, but we didn't get it.
00735                         rospy.logwarn("An object is required for" + 
00736                                         " this action but none were found")
00737                         self._async_update_session_state()
00738                         return False
00739                 else:
00740                     # No object is required: start execution now.
00741                     action = self.get_current_action()
00742                     action.start_execution()
00743 
00744                     for i in range(1000):
00745                         
00746                         status = action.get_status()
00747                         if status != ExecutionStatus.EXECUTING:
00748                             break
00749                         if i % 10 == 0:
00750                             rospy.loginfo("Still executing")
00751                         rospy.sleep(0.1)
00752                     if status == ExecutionStatus.SUCCEEDED:
00753                         action.end_execution()
00754                         self._async_update_session_state()
00755                         return True
00756                     else:
00757                         rospy.logwarn("Execution failed, with status: {}".format(status))
00758                         action.end_execution()
00759                         self._async_update_session_state()
00760                         return False
00761             else:
00762                 # No primitives / poses / frames recorded.
00763                 rospy.logwarn("No primitives recorded")
00764                 self._async_update_session_state()
00765                 return False
00766         else:
00767             # No actions.
00768             rospy.logwarn("No current action")
00769             self._async_update_session_state()
00770             return False
00771 
00772     def publish_primitive_tf(self):
00773         '''Publish tf frame for each primitive of current action'''
00774         if not self._current_action_id is None:
00775             # self._lock.acquire()
00776             action = self._actions[self._current_action_id]
00777             primitives = action.get_primitives()
00778             # self._lock.release()
00779             for primitive in primitives:
00780                 self._publish_primitive_tf(primitive)
00781 
00782     def update_primitive_pose(self, primitive_number, position, orientation):
00783         '''Update pose of primitive given by primitive_number
00784 
00785         Args:
00786             primitive_number (int)
00787             position (Point)
00788             orientation (OrientationRPY)
00789         '''
00790         action = self._actions[self._current_action_id]
00791         action.update_primitive_pose(primitive_number, position, orientation)
00792 
00793     # ##################################################################
00794     # Instance methods: Internal ("private")
00795     # ##################################################################
00796 
00797     def _get_marker_visibility(self):
00798         '''Get the visibility of the markers
00799 
00800         Returns:
00801             [bool]
00802         '''
00803         if self._current_action_id is None:
00804             return []
00805         return self._actions[self._current_action_id].get_marker_visibility()
00806 
00807     def _update_db_with_action(self, action, db_file=None):
00808         '''Adds action to db if it does not already exist.
00809         Or if it exists, delete the existing entry and replace with
00810         update version
00811 
00812         Args:
00813             action (Action)
00814         '''
00815         rospy.loginfo("Updating database")
00816         if db_file is None:
00817             db_file = self._to_file
00818         action_json = action.get_json()
00819         # rospy.loginfo("json: {}".format(json))
00820         action_id_str = str(action.get_action_id())
00821         if action_id_str in self._db:
00822 
00823             self._db.delete(self._db[action_id_str])
00824             self._db[action_id_str] = action_json
00825         else:
00826             self._db[action_id_str] = action_json
00827         if db_file:
00828             self._json[action.get_action_id()] = action_json
00829             with open(db_file, 'w') as to_file:
00830                 json.dump(self._json, to_file)
00831 
00832     def _update_db_with_current_action(self):
00833         '''Adds current action to db if it does not already exist.
00834         Or if it exists, delete the existing entry and replace with
00835         update version
00836         '''
00837         action = self.get_current_action()
00838         if not action is None:
00839             self._update_db_with_action(action)
00840 
00841 
00842     def _selected_primitive_cb(self, selected_primitive):
00843         '''Updates the selected primitive when interactive markers are
00844         clicked on.
00845 
00846         Args:
00847             selected_primitive (int): ID of the primitive selected.
00848         '''
00849         rospy.loginfo("Setting primitive to {}".format(selected_primitive))
00850         self._selected_primitive = selected_primitive
00851 
00852         self._async_update_session_state()
00853         rospy.loginfo("Done setting primitive to {}".format(selected_primitive))
00854 
00855     def _action_change_cb(self):
00856         '''Updates the db when primitive deleted.
00857         '''
00858         self.publish_primitive_tf()
00859         self._async_update_session_state()
00860         rospy.loginfo("Session state updates")
00861 
00862     def _get_session_state_cb(self, req):
00863         '''Response to the experiment state service call.
00864 
00865         Args:
00866             req (GetSessionStateRequest): Unused.
00867         Returns:
00868             GetSessionStateResponse
00869         '''
00870         return GetSessionStateResponse(self._get_session_state())
00871 
00872     def _async_update_session_state(self):
00873         '''Launches a new thread to asynchronously update experiment
00874         state.'''
00875         threading.Thread(group=None,
00876                          target=self._update_session_state,
00877                          name='session_state_publish_thread').start()
00878 
00879     def _update_session_state(self):
00880         '''Publishes a message with the latest state.'''
00881         rospy.loginfo("Session state update")
00882         if len(self._actions) > 0:
00883             self._lock.acquire()
00884             self._update_db_with_current_action()
00885             self._lock.release()
00886         state = self._get_session_state()
00887         self._state_publisher.publish(state)
00888         rospy.loginfo("Session state updated")
00889 
00890     def _get_session_state(self):
00891         '''Creates and returns a message with the latest state.
00892 
00893         Returns:
00894             SessionState
00895         '''
00896         rospy.loginfo("Getting session state")
00897         index = self._current_action_id
00898 
00899         # Should the GUI retrieve this information itself?
00900         object_list = self._get_object_list_srv().object_list
00901         positions, orientations = self._get_primitive_positions_orientations()
00902         rospy.loginfo("Got positions and orientations")
00903 
00904         return SessionState(
00905             self.n_actions(),
00906             index,
00907             self.n_primitives(),
00908             self._selected_primitive,
00909             self._get_action_names(),
00910             self._get_ref_frame_names(),
00911             self._get_primitive_names(),
00912             self._get_actions_disabled(),
00913             self._get_marker_visibility(),
00914             self._get_primitives_editable(),
00915             [],
00916             object_list,
00917             positions,
00918             orientations)
00919 
00920     def _get_action_names(self):
00921         '''Return the names of all of the actions in the session
00922 
00923         Returns:
00924             [string]
00925         '''
00926         name_list = []
00927         for key in self._actions:
00928 
00929             name_list.append(self._actions[key].get_name())
00930 
00931         return name_list
00932 
00933     def _get_ref_frame_names(self):
00934         '''Returns a list of the names of the reference frames for the
00935         primitives of the current action.
00936 
00937         Returns:
00938             [str]
00939         '''
00940         # This can be called before anything's set up.
00941         if self.n_actions() < 1 or self._current_action_id is None:
00942             return []
00943         # Once we've got an action, we can query / return things.
00944         action = self._actions[self._current_action_id]
00945         return action.get_ref_frame_names()
00946 
00947     def _get_primitive_positions_orientations(self):
00948         '''Returns positions and orientations of primitives
00949 
00950         Returns:
00951             Point[], OrientationRPY[]
00952         '''
00953         if self.n_actions() < 1 or self._current_action_id is None:
00954             return [], []
00955         # Once we've got an action, we can query / return things.
00956         action = self._actions[self._current_action_id]
00957         return action.get_primitive_positions_orientations()
00958 
00959     def _get_primitive_names(self):
00960         '''Returns a list of the names of the
00961         primitives of the current action.
00962 
00963         Returns:
00964             [str]
00965         '''
00966         # This can be called before anything's set up.
00967         if self.n_actions() < 1 or self._current_action_id is None:
00968             return []
00969         # Once we've got an action, we can query / return things.
00970         action = self._actions[self._current_action_id]
00971         return action.get_primitive_names()
00972 
00973     def _get_actions_disabled(self):
00974         '''Returns whether each action is disabled currently 
00975         (due to grasp suggestion not being available)
00976 
00977         Returns:
00978             [bool]
00979         '''
00980         if not self._actions_disabled:
00981             return [True] * self.n_actions()
00982         return self._actions_disabled
00983 
00984     def _get_primitives_editable(self):
00985         '''Returns list of whether primitive poses are editable
00986 
00987         Returns:
00988             [bool]
00989         '''
00990         if self.n_actions() < 1 or self._current_action_id is None:
00991             return []
00992         # Once we've got an action, we can query / return things.
00993         action = self._actions[self._current_action_id]
00994         return action.get_primitives_editable()
00995 
00996     def _load_session_state(self):
00997         '''Loads the experiment state from couchdb database or json file.'''
00998         # It retrieves actions from db sorted by their integer ids.
00999 
01000         map_fun = '''function(doc) {
01001                      emit(doc.id, doc);
01002                   }'''
01003 
01004         results = self._db.query(map_fun)
01005 
01006         # Load data from db into Action objects.
01007         for result in results:
01008             action = Action(self._robot, self._tf_listener, self._im_server,
01009                        self._selected_primitive_cb, self._action_change_cb, 
01010                        grasp_suggestion_service=self._grasp_suggestion_service,
01011                        grasp_feedback_topic=self._grasp_feedback_topic,
01012                        external_ee_link=self._external_ee_link)
01013             success = action.build_from_json(result.value)
01014             self._actions_disabled.append(not success)
01015             self._actions[int(result.value['id'])] = action
01016             self._action_ids.append(int(result.value['id']))
01017             self._update_db_with_action(action)
01018 
01019         if self._from_file:
01020             time_str = datetime.datetime.now().strftime('%c')
01021             for key in self._actions:
01022                 action = self._actions[key]
01023                 self._update_db_with_action(action, time_str + '.json')
01024 
01025             del self._couch['fetch_pbd']
01026             self._db = self._couch.create('fetch_pbd')
01027             self._actions = {}
01028             self._action_ids = []
01029             with open(self._from_file) as json_file:
01030                 self._json = json.load(json_file)
01031 
01032             keys = self._json.keys()
01033             keys.sort()
01034             self._actions_disabled = []
01035             for key in keys:
01036                 action = Action(self._robot, self._tf_listener, self._im_server,
01037                        self._selected_primitive_cb, self._action_change_cb,
01038                        grasp_suggestion_service=self._grasp_suggestion_service,
01039                        grasp_feedback_topic=self._grasp_feedback_topic,
01040                        external_ee_link=self._external_ee_link)
01041                 success = action.build_from_json(self._json[key])
01042                 self._actions_disabled.append(not success)
01043                 self._actions[int(self._json[key]['id'])] = action
01044                 self._action_ids.append(int(self._json[key]['id']))
01045                 self._update_db_with_action(action)
01046 
01047         if True in self._actions_disabled:
01048             self._status_publisher.publish(String("Some actions have been " +
01049                        "disabled because they require grasp suggestion."))
01050 
01051         # if len(self._actions) > 0:
01052         #     # Select the starting action as the action with the largest id
01053         #     self._current_action_id = self._action_ids[-1]
01054 
01055         #     # self._actions[self._current_action_id].initialize_viz()
01056 
01057     def _publish_primitive_tf(self, primitive, parent="base_link"):
01058         ''' Publishes a TF for primitive
01059 
01060         Args:
01061             primitive (Primitive)
01062             parent (str): The parent reference frame.
01063         '''
01064         try:
01065             marker_pose = primitive.get_absolute_marker_pose()
01066             # rospy.loginfo("Publishing primitive TF")
01067             if marker_pose:
01068                 pose = self._tf_listener.transformPose('base_link', marker_pose)
01069                 position = pose.pose.position
01070                 orientation = pose.pose.orientation
01071                 pos = (position.x, position.y, position.z)
01072                 rot = (orientation.x, orientation.y, 
01073                         orientation.z, orientation.w)
01074                 name = "primitive_" + str(primitive.get_number())
01075                 # TODO(mbforbes): Is it necessary to change the position
01076                 # and orientation into tuples to send to TF?
01077                 self._tf_broadcaster.sendTransform(
01078                     pos, rot, rospy.Time.now(), name, parent)
01079         except Exception, e:
01080             rospy.logwarn(str(e))


fetch_pbd_interaction
Author(s): Sarah Elliott
autogenerated on Thu Jun 6 2019 18:27:21