robot.py
Go to the documentation of this file.
00001 '''Robot class that provides an interface to arm and head (maybe base later)'''
00002 
00003 # ######################################################################
00004 # Imports
00005 # ######################################################################
00006 
00007 # Core ROS imports come first.
00008 import rospy
00009 import roslib
00010 
00011 # System builtins
00012 import os
00013 
00014 # ROS builtins
00015 from sound_play.libsoundplay import SoundClient
00016 from std_srvs.srv import Empty
00017 from actionlib import SimpleActionClient
00018 from actionlib_msgs.msg import GoalStatus
00019 
00020 # Local
00021 from fetch_pbd_interaction.srv import MoveArm, GetGripperState, \
00022                                       SetGripperState, GetArmMovement, \
00023                                       GetEEPose, GetJointStates, GetGazeGoal, \
00024                                       GetNearestObject, MoveArmTraj
00025 from fetch_social_gaze.msg import GazeGoal, GazeAction
00026 from fetch_pbd_interaction.msg import ArmState, Landmark
00027 from fetch_arm_control.msg import GripperState
00028 
00029 # ######################################################################
00030 # Module level constants
00031 # ######################################################################
00032 
00033 # String for base link name
00034 BASE_LINK = 'base_link'
00035 
00036 PKG = 'fetch_pbd_interaction'
00037 
00038 # Directory sounds are in, within the package.
00039 SOUNDS_DIR = os.path.join(roslib.packages.get_pkg_dir(PKG), 'sounds', '')
00040 
00041 # Common postfix for sound files.
00042 SOUND_FILEFORMAT = '.wav'
00043 
00044 # ######################################################################
00045 # Classes
00046 # ######################################################################
00047 
00048 class Robot:
00049     '''Robot class that provides an interface to arm
00050     and head (maybe base later)'''
00051 
00052     def __init__(self, tf_listener, play_sound=True, social_gaze=True):
00053         '''
00054         Args:
00055             tf_listener (TransformListener)
00056         '''
00057         self._social_gaze = social_gaze
00058         self._play_sound = play_sound
00059         self._tf_listener = tf_listener
00060 
00061         # arm services
00062         self.move_arm_to_joints_plan_srv = rospy.ServiceProxy(
00063                                         '/fetch_pbd/move_arm_to_joints_plan', 
00064                                         MoveArm)
00065         rospy.wait_for_service('/fetch_pbd/move_arm_to_joints_plan')
00066 
00067         self.move_arm_to_joints_srv = rospy.ServiceProxy(
00068                                         '/fetch_pbd/move_arm_to_joints', 
00069                                         MoveArmTraj)
00070         rospy.wait_for_service('/fetch_pbd/move_arm_to_joints')
00071 
00072         self.move_arm_to_pose_srv = rospy.ServiceProxy(
00073                                         '/fetch_pbd/move_arm_to_pose', 
00074                                         MoveArm)
00075         rospy.wait_for_service('/fetch_pbd/move_arm_to_pose')
00076 
00077         self.start_move_arm_to_pose_srv = rospy.ServiceProxy(
00078                                             '/fetch_pbd/start_move_arm_to_pose', 
00079                                             MoveArm)
00080         rospy.wait_for_service('/fetch_pbd/start_move_arm_to_pose')
00081 
00082         self.is_reachable_srv = rospy.ServiceProxy('/fetch_pbd/is_reachable', MoveArm)
00083         rospy.wait_for_service('/fetch_pbd/is_reachable')
00084 
00085         self.is_arm_moving_srv = rospy.ServiceProxy(
00086                                     '/fetch_pbd/is_arm_moving', GetArmMovement)
00087         rospy.wait_for_service('/fetch_pbd/is_arm_moving')
00088 
00089         self.relax_arm_srv = rospy.ServiceProxy('/fetch_pbd/relax_arm', Empty)
00090         rospy.wait_for_service('/fetch_pbd/relax_arm')
00091 
00092         self.reset_arm_movement_history_srv = rospy.ServiceProxy(
00093                                         '/fetch_pbd/reset_arm_movement_history', 
00094                                         Empty)
00095         rospy.wait_for_service('/fetch_pbd/reset_arm_movement_history')
00096 
00097         self.get_gripper_state_srv = rospy.ServiceProxy(
00098                                         '/fetch_pbd/get_gripper_state', 
00099                                         GetGripperState)
00100         rospy.wait_for_service('/fetch_pbd/get_gripper_state')
00101 
00102         self.get_joint_states_srv = rospy.ServiceProxy(
00103                                         '/fetch_pbd/get_joint_states', 
00104                                         GetJointStates)
00105         rospy.wait_for_service('/fetch_pbd/get_joint_states')
00106 
00107         self.get_ee_pose_srv = rospy.ServiceProxy('/fetch_pbd/get_ee_pose', 
00108                                                     GetEEPose)
00109         rospy.wait_for_service('/fetch_pbd/get_ee_pose')
00110 
00111         self.set_gripper_state_srv = rospy.ServiceProxy(
00112                                         '/fetch_pbd/set_gripper_state', 
00113                                         SetGripperState)
00114         rospy.wait_for_service('/fetch_pbd/set_gripper_state')
00115 
00116         rospy.loginfo("Got all arm services")
00117 
00118         # head services
00119 
00120         self.gaze_client = SimpleActionClient('/fetch_pbd/gaze_action', 
00121                                                 GazeAction)
00122 
00123         self.gaze_client.wait_for_server(rospy.Duration(5))
00124 
00125         self.current_gaze_goal_srv = rospy.ServiceProxy(
00126                                         '/fetch_pbd/get_current_gaze_goal', 
00127                                         GetGazeGoal)
00128         rospy.wait_for_service('/fetch_pbd/get_current_gaze_goal')
00129 
00130         rospy.loginfo("Got all head services")
00131 
00132         # world services
00133 
00134         self._get_nearest_object_srv = rospy.ServiceProxy(
00135                                         '/fetch_pbd/get_nearest_object', 
00136                                         GetNearestObject)
00137         rospy.wait_for_service('/fetch_pbd/get_nearest_object')
00138 
00139         rospy.loginfo("Got all world services")
00140 
00141 
00142         # sound stuff
00143         self._sound_client = SoundClient()
00144 
00145     # arm stuff
00146 
00147     def move_arm_to_pose(self, arm_state):
00148         '''Move robot's arm to pose
00149 
00150         Args:
00151             arm_state (ArmState) : contains pose info
00152         Return:
00153             bool : success
00154         '''
00155         try:
00156             result = self.move_arm_to_pose_srv(arm_state).success
00157         except Exception, e:
00158             result = False
00159         return result
00160 
00161     def start_move_arm_to_pose(self, arm_state):
00162         '''Start thread to move robot's arm to pose
00163 
00164         Args:
00165             arm_state (ArmState) : contains pose info
00166         Return:
00167             bool : success
00168         '''
00169         # TODO(sarah): Is this really necessary? Investigate.
00170         try:
00171             result = self.start_move_arm_to_pose_srv(arm_state).success
00172         except Exception, e:
00173             result = False
00174         return result
00175 
00176     def move_arm_to_joints_plan(self, arm_state):
00177         '''Move robot's arm to joints positions from arm_state
00178         using Moveit to plan
00179 
00180         Args:
00181             arm_state (ArmState) : contains joint position info
00182         Return:
00183             bool : success
00184         '''
00185         try:
00186             result = self.move_arm_to_joints_plan_srv(arm_state).success
00187         except Exception, e:
00188             result = False
00189         return result
00190     def move_arm_to_joints(self, arm_states, times):
00191         '''Move robot's arm to joints positions from arm_state
00192         without planning, just joint interpolation
00193 
00194         Args:
00195             arm_states ([ArmState]) : contains joint position info
00196         Return:
00197             bool : success
00198         '''
00199         try:
00200             result = self.move_arm_to_joints_srv(arm_states, times).success
00201         except Exception, e:
00202             result = False
00203         return result
00204 
00205     def can_reach(self, arm_state):
00206         '''Returns whether arm can reach pose
00207 
00208         Args:
00209             arm_state (ArmState) : contains pose info
00210         Return:
00211             bool : success
00212         '''
00213         try:
00214             result = self.is_reachable_srv(arm_state).success
00215         except Exception, e:
00216             result = False
00217         return result
00218 
00219     def reset_arm_movement_history(self):
00220         '''Resets movement history of arm'''
00221         try:
00222             self.reset_arm_movement_history_srv()
00223         except Exception, e:
00224             pass
00225         return
00226 
00227     def get_gripper_state(self):
00228         '''Returns state of gripper
00229 
00230         Returns:
00231             GripperState.OPEN|GripperState.CLOSED
00232         '''
00233         try:
00234             result = self.get_gripper_state_srv().gripper_state
00235         except Exception, e:
00236             # defaults to closed, but maybe not a good idea
00237             result = GripperState.CLOSED
00238         return result
00239 
00240     def set_gripper_state(self, gripper_state):
00241         '''Sets state of gripper. Assumed to succeed
00242 
00243         Args:
00244             gripper_state (GripperState.OPEN|GripperState.CLOSED)
00245         '''
00246         try:
00247             self.set_gripper_state_srv(gripper_state)
00248         except Exception, e:
00249             pass
00250         return
00251 
00252     def get_arm_state(self):
00253         '''Returns current state of arm
00254 
00255         Returns:
00256             ArmState
00257         '''
00258         abs_ee_pose = self.get_ee_pose_srv().ee_pose  # (PoseStamped)
00259         joint_pose = self.get_joint_states_srv().joints  # ([float64])
00260 
00261         state = None
00262         rel_ee_pose = None
00263         try:
00264             resp = self._get_nearest_object_srv(
00265                 abs_ee_pose)
00266             has_nearest = resp.has_nearest
00267         except Exception, e:
00268             rospy.logwarn(str(e))
00269             has_nearest = False
00270 
00271         if not has_nearest:
00272             # Arm state is absolute (relative to robot's base_link).
00273             state = ArmState(
00274                 ArmState.ROBOT_BASE,  # ref_frame (uint8)
00275                 abs_ee_pose,  # ee_pose (PoseStamped)
00276                 joint_pose,  # joint_pose ([float64])
00277                 [], # velocities
00278                 Landmark()  # ref_frame_landmark (Landmark)
00279             )
00280         else:
00281             nearest_obj = resp.nearest_object
00282             # Arm state is relative (to some object in the world).
00283             # rospy.loginfo("Relative to: {}".format(nearest_obj.name))
00284 
00285             rel_ee_pose = self._tf_listener.transformPose(
00286                             nearest_obj.name, abs_ee_pose)
00287 
00288             state = ArmState(
00289                 ArmState.OBJECT,  # ref_frame (uint8)
00290                 rel_ee_pose,  # ee_pose (PoseStamped)
00291                 joint_pose,  # joint_pose [float64]
00292                 [], # velocities
00293                 nearest_obj  # ref_frameLandmark (Landmark)
00294             )
00295 
00296         return state
00297 
00298     def relax_arm(self):
00299         '''Make sure gravity compensation controller is on and other
00300         controllers are off
00301         '''
00302         try:
00303             self.relax_arm_srv()
00304         except Exception, e:
00305             pass
00306         return
00307 
00308     def is_arm_moving(self):
00309         '''Check if arm is currently moving
00310 
00311         Returns:
00312             bool : True if arm is moving, else False
00313         '''
00314         try:
00315             result = self.is_arm_moving_srv().moving
00316         except Exception, e:
00317             result = False
00318         return result
00319 
00320     # Head stuff
00321 
00322     def shake_head(self, num=5):
00323         '''Shakes robot's head
00324 
00325         Args:
00326             num (int) : number of times to perform action
00327         '''
00328         rospy.loginfo("Head shake requested")
00329         if self._social_gaze:
00330             try:
00331                 goal = GazeGoal()
00332                 goal.action = GazeGoal.SHAKE
00333                 goal.repeat = num
00334                 current_goal = self.current_gaze_goal_srv().gaze_goal
00335                 if goal.action != current_goal:
00336                     self.gaze_client.send_goal(goal)
00337                     self.gaze_client.wait_for_result()
00338                     rospy.loginfo("Gaze result: {}".format(self.gaze_client.get_result()))
00339                 else:
00340                     rospy.loginfo("Gaze goal is same as previous")
00341             except Exception, e:
00342                 rospy.logwarn("Fetch social gaze exception: {}".format(str(e)))
00343 
00344     def nod_head(self, num=5):
00345         '''Nods robot's head
00346 
00347         Args:
00348             num (int) : number of times to perform action
00349         '''
00350         rospy.loginfo("Head nod requested")
00351         if self._social_gaze:
00352             try:
00353                 goal = GazeGoal()
00354                 goal.action = GazeGoal.NOD
00355                 goal.repeat = num
00356                 current_goal = self.current_gaze_goal_srv().gaze_goal
00357                 if goal.action != current_goal:
00358                     self.gaze_client.send_goal(goal)
00359                     self.gaze_client.wait_for_result()
00360                     rospy.loginfo("Gaze result: {}".format(self.gaze_client.get_result()))
00361                 else:
00362                     rospy.loginfo("Gaze goal is same as previous")
00363             except Exception, e:
00364                 rospy.logwarn("Fetch social gaze exception: {}".format(str(e)))
00365 
00366     def look_at_point(self, point):
00367         '''Points robot's head at point
00368 
00369         Args:
00370             point (Point)
00371         '''
00372         if self._social_gaze:
00373             try:
00374                 goal = GazeGoal()
00375                 goal.action = GazeGoal.LOOK_AT_POINT
00376                 goal.point = point
00377                 current_goal = self.current_gaze_goal_srv().gaze_goal
00378                 if goal.action != current_goal:
00379                     self.gaze_client.send_goal(goal)
00380             except Exception, e:
00381                 pass
00382 
00383     def look_at_ee(self, follow=True):
00384         '''Makes head look at (or follow) end effector position
00385 
00386         Args:
00387             follow (bool, optional) : If True, follow end effector,
00388                                       else, just glance at end effector
00389         '''
00390         # rospy.loginfo("Look at ee")
00391         if self._social_gaze:
00392             try:
00393                 goal = GazeGoal()
00394                 if follow:
00395                     goal.action = GazeGoal.FOLLOW_EE
00396                 else:
00397                     goal.action = GazeGoal.GLANCE_EE
00398                 current_goal = self.current_gaze_goal_srv().gaze_goal
00399                 if goal.action != current_goal:
00400                     self.gaze_client.send_goal(goal)
00401             except Exception, e:
00402                 pass
00403 
00404     def look_forward(self):
00405         '''Point head forward'''
00406         if self._social_gaze:
00407             try:
00408                 goal = GazeGoal()
00409                 goal.action = GazeGoal.LOOK_FORWARD
00410                 current_goal = self.current_gaze_goal_srv().gaze_goal
00411                 if goal.action != current_goal:
00412                     self.gaze_client.send_goal(goal)
00413             except Exception, e:
00414                 pass
00415 
00416     def look_down(self):
00417         '''Point head down at table'''
00418         # TODO(sarah): maybe actually scan for table instead of
00419         # looking at static point
00420         try:
00421             rospy.loginfo("Requesting to look down")
00422             goal = GazeGoal()
00423             goal.action = GazeGoal.LOOK_DOWN
00424             current_goal = self.current_gaze_goal_srv().gaze_goal
00425             if goal.action != current_goal:
00426                 self.gaze_client.send_goal(goal)
00427             while (self.gaze_client.get_state() == GoalStatus.PENDING or
00428                    self.gaze_client.get_state() == GoalStatus.ACTIVE):
00429                 rospy.sleep(0.2)
00430             rospy.sleep(0.5)
00431         except Exception, e:
00432             rospy.logwarn("Gaze error: {}".format(e))
00433 
00434     # Sound stuff
00435 
00436     def play_sound(self, requested_sound):
00437         '''Play sound that is requested
00438 
00439         Args:
00440             requested_sound (RobotSound.ERROR|etc...) : see RobotSound.msg
00441         '''
00442         try:
00443             if self._play_sound:
00444                 self._sound_client.playWave(
00445                     os.path.join(SOUNDS_DIR, requested_sound + SOUND_FILEFORMAT))
00446         except Exception, e:
00447             rospy.loginfo(e)


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