arm_trajectory.py
Go to the documentation of this file.
00001 '''Defines behaviour for ArmTrajectory primitive. This is for primitives
00002 where the arm moves to a series of poses.
00003 '''
00004 
00005 # ######################################################################
00006 # Imports
00007 # ######################################################################
00008 
00009 # Core ROS imports come first.
00010 import rospy
00011 
00012 # System builtins
00013 from collections import Counter
00014 
00015 # ROS builtins
00016 import tf
00017 from std_msgs.msg import ColorRGBA, Header
00018 from geometry_msgs.msg import Vector3, Point, Pose, Quaternion, PoseStamped
00019 from visualization_msgs.msg import Marker, InteractiveMarker
00020 from visualization_msgs.msg import InteractiveMarkerControl
00021 from visualization_msgs.msg import InteractiveMarkerFeedback
00022 from interactive_markers.menu_handler import MenuHandler
00023 
00024 # Local
00025 from fetch_pbd_interaction.primitive import Primitive
00026 from fetch_pbd_interaction.msg import ArmState, Landmark
00027 from fetch_pbd_interaction.srv import GetObjectList, \
00028                                       GetObjectFromName, GetMostSimilarObject
00029 
00030 
00031 # ######################################################################
00032 # Module level constants
00033 # ######################################################################
00034 
00035 # Marker options
00036 # --------------
00037 # Colors
00038 COLOR_TRAJ_ENDPOINT_SPHERES = ColorRGBA(1.0, 0.5, 0.0, 0.8)
00039 COLOR_TRAJ_LINE = ColorRGBA(0.8, 0.4, 0.0, 0.8)
00040 COLOR_TRAJ_ENDPOINT_SPHERES_SELECTED = ColorRGBA(0.0, 1.0, 0.0, 0.8)
00041 COLOR_TRAJ_LINE_SELECTED = ColorRGBA(0.0, 1.0, 0.0, 0.8)
00042 # COLOR_OBJ_REF_ARROW = ColorRGBA(1.0, 0.8, 0.2, 0.5)
00043 
00044 # Scales
00045 SCALE_TRAJ_LINE = Vector3(0.02, 0.0, 0.0)
00046 SCALE_OBJ_REF_ARROW = Vector3(0.02, 0.03, 0.04)
00047 
00048 # Gripper mesh related
00049 STR_MESH_GRIPPER_FOLDER = 'package://fetch_description/meshes/'
00050 STR_GRIPPER_PALM_FILE = STR_MESH_GRIPPER_FOLDER + 'gripper_link.STL'
00051 STR_L_GRIPPER_FINGER_FILE = STR_MESH_GRIPPER_FOLDER + \
00052                                 'l_gripper_finger_link.STL'
00053 STR_R_GRIPPER_FINGER_FILE = STR_MESH_GRIPPER_FOLDER + \
00054                                 'r_gripper_finger_link.STL'
00055 DEFAULT_OFFSET = 0.085
00056 
00057 # Right-click menu.
00058 MENU_OPTIONS = {
00059     'ref': 'Reference frame',
00060     'move_here': 'Move arm here',
00061     'move_current': 'Move to current arm pose',
00062     'del': 'Delete',
00063 }
00064 
00065 # Offets to maintain globally-unique IDs but with new sets of objects.
00066 # Each primitive marker has a unique ID, and this allows each to
00067 # have a matching unique id for trajectories, text, etc. Assumes we'll
00068 # have < 1k steps.
00069 ID_OFFSET_REF_ARROW = 1000
00070 ID_OFFSET_TRAJ_FIRST = 2000
00071 ID_OFFSET_TRAJ_LAST = 3000
00072 
00073 # Other
00074 TRAJ_MARKER_LIFETIME = rospy.Duration()
00075 TEXT_Z_OFFSET = 0.1
00076 INT_MARKER_SCALE = 0.2
00077 TRAJ_ENDPOINT_SCALE = 0.05
00078 
00079 # ROS topics, etc.
00080 # ----------------
00081 # Namespace for interactive marker server.
00082 TOPIC_IM_SERVER = 'programmed_actions'
00083 
00084 # We might want to refactor this even further, as it's used throughout
00085 # the code.
00086 BASE_LINK = 'base_link'
00087 FIXED_LINK = 'torso_lift_link'
00088 
00089 # ######################################################################
00090 # Classes
00091 # ######################################################################
00092 
00093 class ArmTrajectory(Primitive):
00094     '''Defines behaviour for ArmTrajectory primitive. This is for primitives
00095     where the arm moves to a series of poses.
00096     '''
00097 
00098     _offset = DEFAULT_OFFSET
00099 
00100     def __init__(self, robot, tf_listener, im_server, number=None):
00101         '''
00102         Args:
00103             robot (Robot) : interface to lower level robot functionality
00104             tf_listener (TransformListener)
00105             im_server (InteractiveMarkerSerever)
00106             number (int, optional): The number of this primitive in the
00107             action sequence
00108         '''
00109         self._name = '' # Unused currently
00110         self._robot = robot
00111         self._im_server = im_server
00112         self._start_time = rospy.Time.now()
00113         self._tf_listener = tf_listener
00114         self._is_control_visible = False
00115         self._is_selected = False
00116         self._marker_visible = False
00117         self._color_traj_line = COLOR_TRAJ_LINE
00118         self._color_traj_endpoint_spheres = COLOR_TRAJ_ENDPOINT_SPHERES
00119 
00120         # Timing is not currently used but the current implementation
00121         # for executing trajectories is very bad and I think in future
00122         # implementations this will be very useful
00123         self._timing = []
00124         self._menu_handler = MenuHandler()
00125 
00126         self._time_offset = rospy.Duration(0.1)
00127         self._arm_states = []
00128         self._gripper_states = []
00129         self._number = number
00130         self._ref_type = ArmState.FIXED_LINK
00131         self._ref_landmark = Landmark()
00132         self._sub_entries = None
00133         self._marker_click_cb = None
00134         self._marker_delete_cb = None
00135         self._pose_change_cb = None
00136         self._action_change_cb = None
00137 
00138         self._get_object_from_name_srv = rospy.ServiceProxy(
00139                                          '/fetch_pbd/get_object_from_name',
00140                                          GetObjectFromName)
00141         self._get_most_similar_obj_srv = rospy.ServiceProxy(
00142                                          '/fetch_pbd/get_most_similar_object',
00143                                          GetMostSimilarObject)
00144         self._get_object_list_srv = rospy.ServiceProxy('/fetch_pbd/get_object_list',
00145                                                        GetObjectList)
00146 
00147     # ##################################################################
00148     # Instance methods: Public (API)
00149     # ##################################################################
00150 
00151     def get_json(self):
00152         '''Returns json representation of primitive'''
00153 
00154         json = {}
00155 
00156         json['name'] = self._name
00157         json['number'] = self._number
00158         json['timing'] = self._timing
00159         json['ref_type'] = self._ref_type
00160         json['ref_landmark'] = \
00161                     ArmTrajectory._get_json_from_landmark(self._ref_landmark)
00162         json['arm_states'] = []
00163         json['gripper_states'] = []
00164 
00165         for i in range(len(self._arm_states)):
00166             arm_state = ArmTrajectory._get_json_from_arm_state(
00167                                             self._arm_states[i])
00168             gripper_state = self._gripper_states[i]
00169             json['arm_states'].append(arm_state)
00170             json['gripper_states'].append(gripper_state)
00171 
00172         return {'arm_trajectory': json}
00173 
00174     def build_from_json(self, json):
00175         '''Fills out ArmTrajectory using json from db'''
00176 
00177         self._name = json['name']
00178         self._number = json['number']
00179         self._timing = json['timing']
00180         self._ref_type = json['ref_type']
00181         self._ref_landmark = \
00182                     ArmTrajectory._get_landmark_from_json(json['ref_landmark'])
00183 
00184         for i in range(len(json['arm_states'])):
00185             arm_state = ArmTrajectory._get_arm_state_from_json(
00186                                             json['arm_states'][i])
00187             self._arm_states.append(arm_state)
00188 
00189             gripper_state = json['gripper_states'][i]
00190             self._gripper_states.append(gripper_state)
00191 
00192     def check_pre_condition(self):
00193         ''' Currently just a placeholder
00194             Meant to return conditions that need to be met before a
00195             primitive can be executed. This could be something like
00196             "There should only be one object" or something.
00197 
00198             Returns:
00199                 None
00200         '''
00201         return True, None
00202 
00203     def check_post_condition(self):
00204         ''' Currently just a placeholder
00205             Meant to return conditions that need to be met after a
00206             primitive is executed in order for execution to be a success.
00207             This could be something like "object must be 0.1m above surface"
00208 
00209             Returns:
00210                 None
00211         '''
00212         return True, None
00213 
00214     def add_marker_callbacks(self, click_cb, delete_cb, pose_change_cb,
00215                     action_change_cb):
00216         '''Adds marker to world'''
00217 
00218         # rospy.loginfo("Making marker")
00219         self._marker_click_cb = click_cb
00220         self._marker_delete_cb = delete_cb
00221         self._pose_change_cb = pose_change_cb
00222         self._action_change_cb = action_change_cb
00223         # self.update_ref_frames()
00224 
00225     def show_marker(self):
00226         '''Adds marker for primitive'''
00227         if self.update_ref_frames():
00228             try:
00229                 self._update_menu()
00230                 self._update_viz_core()
00231                 self._menu_handler.apply(self._im_server, self.get_name())
00232                 self._im_server.applyChanges()
00233             except Exception, e:
00234                 rospy.logwarn(e)
00235 
00236         self._marker_visible = True
00237         return True
00238 
00239     def hide_marker(self):
00240         '''Removes marker from the world.'''
00241 
00242         rospy.loginfo("Deleting marker for: {}".format(self.get_name()))
00243         self._im_server.erase(self.get_name())
00244         self._im_server.applyChanges()
00245         self._marker_visible = False
00246 
00247     def marker_visible(self):
00248         '''Return whether or not marker is visible
00249 
00250         Returns:
00251             bool
00252         '''
00253         return self._marker_visible
00254 
00255     def update_ref_frames(self):
00256         '''Updates and re-assigns coordinate frames when the world changes.'''
00257 
00258         if self._ref_type != ArmState.FIXED_LINK:
00259             rospy.logwarn("Trajectories can only be relative to the robot's base")
00260             return False
00261         else:
00262             return True
00263 
00264     def change_ref_frame(self, ref_type, landmark):
00265         '''Sets new reference frame for primitive
00266 
00267         Args:
00268 
00269         '''
00270         rospy.logwarn("Trajectories are always relative to the robot's base")
00271 
00272     def get_ref_frame_name(self):
00273         '''Returns the name string for the reference frame object of the
00274         primitive.
00275 
00276         Returns:
00277             str|None: Under all normal circumstances, returns the str
00278                 reference frame name. Returns None in error.
00279         '''
00280         # "Normal" step (saved pose).
00281         return FIXED_LINK
00282 
00283     def select(self, is_selected):
00284         '''Set whether primitive is selected or not
00285 
00286         Args:
00287             is_selected (bool)
00288         '''
00289         self._selected = is_selected
00290         self.set_control_visible(is_selected)
00291         if is_selected:
00292             self._color_traj_line = COLOR_TRAJ_LINE_SELECTED
00293             self._color_traj_endpoint_spheres = \
00294                 COLOR_TRAJ_ENDPOINT_SPHERES_SELECTED
00295         else:
00296             self._color_traj_line = COLOR_TRAJ_LINE
00297             self._color_traj_endpoint_spheres = COLOR_TRAJ_ENDPOINT_SPHERES
00298         self.update_viz()
00299 
00300     def is_selected(self):
00301         '''Return whether or not primitive is selected
00302 
00303         Returns
00304             bool
00305         '''
00306         return self._selected
00307 
00308     def is_control_visible(self):
00309         '''Check if the marker control is visible
00310 
00311         Returns
00312             bool
00313         '''
00314         return self._is_control_visible
00315 
00316     def set_control_visible(self, visible=True):
00317         '''Set visibility of marker controls
00318 
00319         Args:
00320             visible (bool, optional)
00321         '''
00322         self._is_control_visible = visible
00323 
00324     def update_viz(self, check_reachable=True):
00325         '''Updates visualization fully.
00326 
00327         Args:
00328             check_reachable (bool) : Unused
00329         '''
00330         if self._marker_visible:
00331             try:
00332                 self._update_menu()
00333                 self._update_viz_core()
00334                 self._menu_handler.apply(self._im_server, self.get_name())
00335                 self._im_server.applyChanges()
00336             except Exception, e:
00337                 rospy.logwarn(e)
00338 
00339     def get_primitive_number(self):
00340         '''Returns what number this primitive is in the sequence'''
00341         return self._number
00342 
00343     def set_primitive_number(self, num):
00344         '''Sets what number this primitive is in the sequence
00345 
00346         Args:
00347             num (int)
00348         '''
00349         self._number = num
00350 
00351     def is_object_required(self):
00352         '''Check if this primitive requires an object to be present
00353 
00354         Returns:
00355             bool
00356         '''
00357         return False
00358 
00359     def execute(self):
00360         '''Execute this primitive
00361 
00362         Returns
00363             bool : Success of execution
00364         '''
00365         first_arm_state = self._arm_states[0]
00366 
00367         velocities = [0.2] * len(first_arm_state.joint_pose)
00368 
00369         first_arm_state.velocities = velocities
00370         # Sleep to let arm actually reach goal?
00371         rospy.sleep(0.2)
00372         self._robot.move_arm_to_pose(first_arm_state)
00373         self._robot.move_arm_to_joints_plan(first_arm_state)
00374         # Sleep to let arm actually reach goal?
00375         rospy.sleep(0.2)
00376         all_states = self._robot.move_arm_to_joints(self._arm_states,
00377                                                   self._timing)
00378         last_arm_state = self._arm_states[-1]
00379 
00380         velocities = [0.0] * len(last_arm_state.joint_pose)
00381 
00382         last_arm_state.velocities = velocities
00383         self._robot.move_arm_to_joints_plan(last_arm_state)
00384 
00385 
00386         gripper_state = self._gripper_states[-1]
00387 
00388         self._robot.set_gripper_state(gripper_state)
00389         if all_states:
00390             return True, None
00391         else:
00392             return False, "Problem finding IK solution"
00393 
00394     def head_busy(self):
00395         '''Return true if head busy
00396 
00397         Returns:
00398             bool
00399         '''
00400         return False
00401 
00402     def is_reachable(self):
00403         '''Check if robot can physically reach all steps in trajectory'''
00404         for arm_state in self._arm_states:
00405             if not self._robot.can_reach(arm_state):
00406                 return False
00407         return True
00408 
00409     def get_relative_pose(self, use_final=True):
00410         '''Returns the absolute pose of the primitive.
00411         Args:
00412             use_final (bool, optional). Whether to
00413                 get the final pose in the trajectory. Defaults to True.
00414         Returns:
00415             PoseStamped
00416         '''
00417         index = len(self._arm_states) - 1 if use_final else 0
00418         arm_state = self._arm_states[index]
00419 
00420         return arm_state.ee_pose
00421 
00422     def get_absolute_pose(self):
00423         '''Returns the absolute pose of the primitive.
00424 
00425         Args:
00426             None
00427 
00428         Returns:
00429             PoseStamped
00430         '''
00431         index = len(self._arm_states) - 1 if use_final else 0
00432         arm_state = self._arm_states[index]
00433 
00434         try:
00435             # self._tf_listener.waitForTransform(BASE_LINK,
00436             #                  arm_state.ee_pose.header.frame_id,
00437             #                  rospy.Time.now(),
00438             #                  rospy.Duration(5.0))
00439             abs_pose = self._tf_listener.transformPose(BASE_LINK,
00440                                                    arm_state.ee_pose)
00441             return abs_pose
00442         except:
00443             frame_id = arm_state.ee_pose.header.frame_id
00444             rospy.logwarn("Frame: {} does not exist".format(frame_id))
00445             return None
00446 
00447     def get_absolute_marker_pose(self, use_final=True):
00448         '''Returns the absolute pose of the primitive marker.
00449 
00450         Args:
00451             use_final (bool, optional). For trajectories only. Whether to
00452                 get the final pose in the trajectory. Defaults to True.
00453 
00454         Returns:
00455             PoseStamped
00456         '''
00457         index = len(self._arm_states) - 1 if use_final else 0
00458         arm_state = self._arm_states[index]
00459 
00460         try:
00461             # self._tf_listener.waitForTransform(BASE_LINK,
00462             #                  arm_state.ee_pose.header.frame_id,
00463             #                  rospy.Time.now(),
00464             #                  rospy.Duration(5.0))
00465             abs_pose = self._tf_listener.transformPose(BASE_LINK,
00466                                                    arm_state.ee_pose)
00467             return ArmTrajectory._offset_pose(abs_pose)
00468         except:
00469             frame_id = arm_state.ee_pose.header.frame_id
00470             rospy.logwarn("Frame: {} does not exist".format(frame_id))
00471             return None
00472 
00473     def get_absolute_marker_position(self, use_final=True):
00474         '''Returns the absolute position of the primitive marker.
00475 
00476         Args:
00477             use_final (bool, optional). For trajectories only. Whether to
00478                 get the final position in the trajectory. Defaults to
00479                 True.
00480 
00481         Returns:
00482             Point
00483         '''
00484         abs_pose = self.get_absolute_marker_pose(use_final)
00485         if not abs_pose is None:
00486             return abs_pose.pose.position
00487         else:
00488             return None
00489 
00490     def decrease_id(self):
00491         '''Reduces the number of the primitive.'''
00492         self._number -= 1
00493         # self._update_menu()
00494 
00495     def add_step(self, arm_state, gripper_state):
00496         '''Add step to trajectory
00497 
00498         Args:
00499             arm_state (ArmState)
00500             gripper_state (GripperState.OPEN|GripperState.CLOSED)
00501         '''
00502         # Adjusts durations so that they start at 0.1s
00503         # And adds 0.1s of padding between each step
00504         if not self._timing:
00505             self._time_offset = ((rospy.Time.now() -
00506                                  self._start_time).to_sec() - 0.1)
00507             self._timing = [0.1]
00508         else:
00509             self._timing.append((rospy.Time.now() -
00510                                 self._start_time).to_sec() -
00511                                 self._time_offset)
00512         arm_state = self._convert_ref_frame(arm_state)
00513         self._arm_states.append(arm_state)
00514         self._gripper_states.append(gripper_state)
00515 
00516     def set_name(self, name):
00517         '''Sets the display name for the primitive.
00518 
00519         Args:
00520             name (str) : A human-readable unique name for the primitive.
00521         '''
00522         self._name = name
00523 
00524     def get_name(self):
00525         '''Returns the display name for the primitive.
00526 
00527         Returns:
00528             str: A human-readable unique name for the primitive.
00529         '''
00530         return self._name
00531 
00532     def get_number(self):
00533         '''Returns number of primitive
00534 
00535         Returns:
00536             int
00537         '''
00538         return self._number
00539 
00540     def set_pose(self, pose):
00541         '''CHanging pose of trajectory is currently not supported
00542 
00543         Args:
00544             pose (PoseStamped) : Unused
00545         '''
00546         rospy.logwarn("Changing pose of trajectory is not currently supported")
00547 
00548     def pose_editable(self):
00549         '''Return whether pose of primitive is editable
00550 
00551         Returns:
00552             bool : False
00553         '''
00554         return False
00555 
00556     def get_ref_type(self):
00557         '''Return reference type of primitive
00558 
00559         Returns:
00560             ArmState.ROBOT_BASE, etc
00561         '''
00562         return self._ref_type
00563 
00564     # ##################################################################
00565     # Static methods: Internal ("private")
00566     # ##################################################################
00567 
00568     @staticmethod
00569     def _get_json_from_arm_state(arm_state):
00570         '''Return json containing data of arm_state
00571 
00572         Args:
00573             arm_state (ArmState)
00574         Returns:
00575             json (dict)
00576         '''
00577         json = {}
00578         json['ref_type'] = arm_state.ref_type
00579         json['joint_pose'] = arm_state.joint_pose
00580         pose = arm_state.ee_pose
00581         json['ee_pose'] = ArmTrajectory._get_json_from_pose_stamped(pose)
00582         landmark = ArmTrajectory._get_json_from_landmark(arm_state.ref_landmark)
00583         json['ref_landmark'] = landmark
00584         return json
00585 
00586     @staticmethod
00587     def _get_json_from_pose_stamped(pose_stamped):
00588         '''Return json containing data of pose_stamped
00589 
00590         Args:
00591             pose_stamped (PoseStamped)
00592         Returns:
00593             json (dict)
00594         '''
00595         json = {}
00596         json['pose'] = ArmTrajectory._get_json_from_pose(pose_stamped.pose)
00597         json['frame_id'] = pose_stamped.header.frame_id
00598 
00599         return json
00600 
00601     @staticmethod
00602     def _get_json_from_pose(pose):
00603         '''Return json containing data of pose
00604 
00605         Args:
00606             pose (Pose)
00607         Returns:
00608             json (dict)
00609         '''
00610         json = {}
00611         json['position'] = {}
00612         json['position']['x'] = pose.position.x
00613         json['position']['y'] = pose.position.y
00614         json['position']['z'] = pose.position.z
00615 
00616         json['orientation'] = {}
00617         json['orientation']['x'] = pose.orientation.x
00618         json['orientation']['y'] = pose.orientation.y
00619         json['orientation']['z'] = pose.orientation.z
00620         json['orientation']['w'] = pose.orientation.w
00621 
00622         return json
00623 
00624     @staticmethod
00625     def _get_json_from_landmark(landmark):
00626         '''Return json containing data of landmark
00627 
00628         Args:
00629             landmark (Landmark)
00630         Returns:
00631             json (dict)
00632         '''
00633         json = {}
00634         # json['type'] = landmark.type
00635         json['name'] = landmark.name
00636         json['pose'] = ArmTrajectory._get_json_from_pose(landmark.pose)
00637         json['dimensions'] = {}
00638         json['dimensions']['x'] = landmark.dimensions.x
00639         json['dimensions']['y'] = landmark.dimensions.y
00640         json['dimensions']['z'] = landmark.dimensions.z
00641 
00642         return json
00643 
00644     @staticmethod
00645     def _get_arm_state_from_json(json):
00646         '''Return ArmState msg from json
00647 
00648         Args:
00649             json (dict)
00650         Returns:
00651             ArmState
00652         '''
00653         arm_state = ArmState()
00654         arm_state.ref_type = json['ref_type']
00655         arm_state.joint_pose = json['joint_pose']
00656         pose = ArmTrajectory._get_pose_stamped_from_json(json['ee_pose'])
00657         arm_state.ee_pose = pose
00658         landmark = ArmTrajectory._get_landmark_from_json(json['ref_landmark'])
00659         arm_state.ref_landmark = landmark
00660         return arm_state
00661 
00662     @staticmethod
00663     def _get_landmark_from_json(json):
00664         '''Return Landmark msg from json
00665 
00666         Args:
00667             json (dict)
00668         Returns:
00669             Landmark
00670         '''
00671         landmark = Landmark()
00672         # landmark.type = json['type']
00673         landmark.name = json['name']
00674 
00675         landmark_pose = ArmTrajectory._get_pose_from_json(json['pose'])
00676         landmark.pose = landmark_pose
00677 
00678         landmark_dimensions = Vector3()
00679         landmark_dimensions.x = json['dimensions']['x']
00680         landmark_dimensions.y = json['dimensions']['y']
00681         landmark_dimensions.z = json['dimensions']['z']
00682 
00683         landmark.dimensions = landmark_dimensions
00684 
00685         return landmark
00686 
00687     @staticmethod
00688     def _get_pose_stamped_from_json(json):
00689         '''Return PoseStamped msg from json
00690 
00691         Args:
00692             json (dict)
00693         Returns:
00694             PoseStamped
00695         '''
00696         pose_stamped = PoseStamped()
00697         pose = ArmTrajectory._get_pose_from_json(json['pose'])
00698         pose_stamped.pose = pose
00699         pose_stamped.header.frame_id = json['frame_id']
00700 
00701         return pose_stamped
00702 
00703     @staticmethod
00704     def _get_pose_from_json(json):
00705         '''Return Pose msg from json
00706 
00707         Args:
00708             json (dict)
00709         Returns:
00710             Pose
00711         '''
00712         pose = Pose()
00713 
00714         pose.position.x = json['position']['x']
00715         pose.position.y = json['position']['y']
00716         pose.position.z = json['position']['z']
00717 
00718         pose.orientation.x = json['orientation']['x']
00719         pose.orientation.y = json['orientation']['y']
00720         pose.orientation.z = json['orientation']['z']
00721         pose.orientation.w = json['orientation']['w']
00722 
00723         return pose
00724 
00725     @staticmethod
00726     def _offset_pose(pose, constant=1):
00727         '''Offsets the world pose for visualization.
00728 
00729         Args:
00730             pose (PoseStamped): The pose to offset.
00731             constant (int, optional): How much to scale the set offset
00732                 by (scales ArmTrajectory._offset). Defaults to 1.
00733 
00734         Returns:
00735             PoseStamped: The offset pose.
00736         '''
00737         transform = ArmTrajectory._get_matrix_from_pose(pose)
00738         offset_array = [constant * ArmTrajectory._offset, 0, 0]
00739         offset_transform = tf.transformations.translation_matrix(offset_array)
00740         hand_transform = tf.transformations.concatenate_matrices(
00741             transform, offset_transform)
00742 
00743         new_pose = PoseStamped()
00744         new_pose.header.frame_id = pose.header.frame_id
00745         new_pose.pose = ArmTrajectory._get_pose_from_transform(hand_transform)
00746         return new_pose
00747 
00748     @staticmethod
00749     def _get_matrix_from_pose(pose):
00750         '''Returns the transformation matrix for given pose.
00751 
00752         Args:
00753             pose (PoseStamped)
00754 
00755         Returns:
00756             Matrix3x3
00757         '''
00758         position, orientation = pose.pose.position, pose.pose.orientation
00759         rot_list = [orientation.x, orientation.y, orientation.z, orientation.w]
00760         transformation = tf.transformations.quaternion_matrix(rot_list)
00761         pos_list = [position.x, position.y, position.z]
00762         transformation[:3, 3] = pos_list
00763         return transformation
00764 
00765     @staticmethod
00766     def _get_pose_from_transform(transform):
00767         '''Returns pose for transformation matrix.
00768 
00769         Args:
00770             transform (Matrix3x3): (I think this is the correct type.
00771                 See ArmTrajectory as a reference for how to use.)
00772 
00773         Returns:
00774             Pose
00775         '''
00776         pos = transform[:3, 3].copy()
00777         rot = tf.transformations.quaternion_from_matrix(transform)
00778         return Pose(
00779             Point(pos[0], pos[1], pos[2]),
00780             Quaternion(rot[0], rot[1], rot[2], rot[3])
00781         )
00782 
00783     # ##################################################################
00784     # Instance methods: Internal ("private")
00785     # ##################################################################
00786 
00787     def _update_menu(self):
00788         '''Recreates the menu when something has changed.'''
00789         self._menu_handler = MenuHandler()
00790 
00791         # Insert sub entries.
00792         self._sub_entries = []
00793         # frame_entry = self._menu_handler.insert(MENU_OPTIONS['ref'])
00794         # object_list = self._get_object_list_srv().object_list
00795         # refs = [obj.name for obj in object_list]
00796         # if self._number > 0:
00797         #     refs.append(PREVIOUS_PRIMITIVE)
00798         # if len(refs) > 0:
00799         #     refs.append(BASE_LINK)
00800         # for ref in refs:
00801         #     subent = self._menu_handler.insert(
00802         #         ref, parent=frame_entry, callback=self._change_ref_cb)
00803         #     self._sub_entries += [subent]
00804 
00805         # Inset main menu entries.
00806         self._menu_handler.insert(
00807             MENU_OPTIONS['del'], callback=self._delete_primitive_cb)
00808 
00809         # Make all unchecked to start.
00810         # for subent in self._sub_entries:
00811         #     self._menu_handler.setCheckState(subent, MenuHandler.UNCHECKED)
00812 
00813         # Check if necessary.
00814         # menu_id = self._get_menu_id(self._get_menu_ref())
00815         # if not menu_id is None:
00816         #     # self.has_object = False
00817         #     self._menu_handler.setCheckState(menu_id, MenuHandler.CHECKED)
00818 
00819         # Update.
00820         # if self._update_viz_core():
00821         #     self._menu_handler.apply(self._im_server, self.get_name())
00822         #     self._im_server.applyChanges()
00823 
00824     def _convert_ref_frame(self, arm_state):
00825         '''Convert arm_state to be in a different reference frame
00826 
00827             Args:
00828                 arm_state (ArmState)
00829                 new_landmark (Landmark)
00830             Returns:
00831                 ArmState
00832         '''
00833         ee_pose = self._tf_listener.transformPose(
00834                                 FIXED_LINK,
00835                                 arm_state.ee_pose
00836                             )
00837         arm_state.ee_pose = ee_pose
00838 
00839         return arm_state
00840 
00841     def _get_marker_pose(self):
00842         '''Returns the pose of the primitive.
00843 
00844         Returns:
00845             Pose
00846         '''
00847         try:
00848             i = int(len(self._arm_states) - 1)
00849             # self._tf_listener.waitForTransform(BASE_LINK,
00850             #                      self._arm_states[i].ee_pose.header.frame_id,
00851             #                      rospy.Time(0),
00852             #                      rospy.Duration(4.0))
00853             # intermediate_pose = self._tf_listener.transformPose(
00854             #                                         BASE_LINK,
00855             #                                         self._arm_states[i].ee_pose)
00856             offset_pose = ArmTrajectory._offset_pose(self._arm_states[i].ee_pose)
00857             return self._tf_listener.transformPose(self.get_ref_frame_name(),
00858                                                     offset_pose)
00859         except:
00860             rospy.logwarn("Frame not available yet.")
00861             return None
00862 
00863     def _update_viz_core(self):
00864         '''Updates visualization after a change.'''
00865         # Create a new IM control.
00866         menu_control = InteractiveMarkerControl()
00867         menu_control.interaction_mode = InteractiveMarkerControl.BUTTON
00868         menu_control.always_visible = True
00869         frame_id = self.get_ref_frame_name()
00870         pose = None
00871         pose = self._get_marker_pose()
00872         if pose is None:
00873             return
00874 
00875         # Handle trajectories.
00876         # First, get all trajectory positions.
00877         point_list = []
00878         traj_pose = None
00879         try:
00880             self._tf_listener.waitForTransform(FIXED_LINK,
00881                              "primitive_" + str(self._number),
00882                              rospy.Time.now(),
00883                              rospy.Duration(1.0))
00884         except Exception, e:
00885             pass
00886         for j in range(len(self._timing)):
00887             traj_pose = self._get_traj_pose(j)
00888             if not traj_pose is None:
00889                 point_list.append(traj_pose.pose.position)
00890             else:
00891                 break
00892 
00893         if traj_pose is None:
00894             try:
00895                 self._tf_listener.waitForTransform(FIXED_LINK,
00896                                  "primitive_" + str(self._number),
00897                                  rospy.Time.now(),
00898                                  rospy.Duration(4.0))
00899             except Exception, e:
00900                 pass
00901             for j in range(len(self._timing)):
00902                 traj_pose = self._get_traj_pose(j)
00903                 if not traj_pose is None:
00904                     point_list.append(traj_pose.pose.position)
00905                 else:
00906                     return
00907 
00908         rospy.loginfo("last pose: {}".format(self._arm_states[0].ee_pose))
00909 
00910         last_point = self._tf_listener.transformPose(FIXED_LINK, self._get_traj_pose(0))
00911         rospy.loginfo("last point: {}".format(last_point))
00912 
00913         # Add a main maker for all points in the trajectory (sphere
00914         # list).
00915         menu_control.markers.append(
00916             Marker(
00917                 type=Marker.LINE_STRIP,
00918                 id=self._number,
00919                 lifetime=TRAJ_MARKER_LIFETIME,
00920                 scale=SCALE_TRAJ_LINE,
00921                 header=Header(frame_id=''),
00922                 color=self._color_traj_line,
00923                 points=point_list
00924             )
00925         )
00926 
00927         # Add a marker for the first step in the trajectory.
00928         menu_control.markers.append(
00929             self._make_sphere_marker(
00930                 self._number + ID_OFFSET_TRAJ_FIRST,
00931                 self._get_traj_pose(0).pose,
00932                 '',
00933                 TRAJ_ENDPOINT_SCALE
00934             )
00935         )
00936 
00937         # Add a marker for the last step in the trajectory.
00938         last_index = len(self._timing) - 1
00939         menu_control.markers.append(
00940             self._make_sphere_marker(
00941                 self._number + ID_OFFSET_TRAJ_LAST,
00942                 self._get_traj_pose(last_index).pose,
00943                 '',
00944                 TRAJ_ENDPOINT_SCALE
00945             )
00946         )
00947 
00948         # Add an arrow to the relative object, if there is one.
00949         # if not self._ref_type == ArmState.ROBOT_BASE:
00950         #     menu_control.markers.append(
00951         #         Marker(
00952         #             type=Marker.ARROW,
00953         #             id=(ID_OFFSET_REF_ARROW + self._number),
00954         #             lifetime=TRAJ_MARKER_LIFETIME,
00955         #             scale=SCALE_OBJ_REF_ARROW,
00956         #             header=Header(frame_id=frame_id),
00957         #             color=COLOR_OBJ_REF_ARROW,
00958         #             points=[pose.pose.position, Point(0, 0, 0)]
00959         #         )
00960         #     )
00961 
00962         # Make and add interactive marker.
00963         int_marker = InteractiveMarker()
00964         int_marker.name = self.get_name()
00965         int_marker.header.frame_id = frame_id
00966         int_marker.pose = pose.pose
00967         int_marker.scale = INT_MARKER_SCALE
00968         # self._add_6dof_marker(int_marker, True)
00969         int_marker.controls.append(menu_control)
00970         self._im_server.insert(
00971             int_marker, self._marker_feedback_cb)
00972         return
00973 
00974     def _add_6dof_marker(self, int_marker, is_fixed):
00975         '''Adds a 6 DoF control marker to the interactive marker.
00976 
00977         Args:
00978             int_marker (InteractiveMarker)
00979             is_fixed (bool): Looks like whether position is fixed (?).
00980                 Currently only passed as True.
00981         '''
00982         # Each entry in options is (name, orientation, is_move)
00983         options = [
00984             ('rotate_x', Quaternion(1, 0, 0, 1), False),
00985             ('move_x', Quaternion(1, 0, 0, 1), True),
00986             ('rotate_z', Quaternion(0, 1, 0, 1), False),
00987             ('move_z', Quaternion(0, 1, 0, 1), True),
00988             ('rotate_y', Quaternion(0, 0, 1, 1), False),
00989             ('move_y', Quaternion(0, 0, 1, 1), True),
00990         ]
00991         for opt in options:
00992             name, orient, is_move = opt
00993             control = self._make_6dof_control(name, orient, is_move, is_fixed)
00994             int_marker.controls.append(control)
00995 
00996     def _make_6dof_control(self, name, orientation, is_move, is_fixed):
00997         '''Creates and returns one component of the 6dof controller.
00998 
00999         Args:
01000             name (str): Name for hte control
01001             orientation (Quaternion): How the control should be
01002                 oriented.
01003             is_move (bool): Looks like whether the marker moves the
01004                 object (?). Currently passed as True for moving markers,
01005                 False for rotating ones.
01006             is_fixed (bool): Looks like whether position is fixed (?).
01007                 Currently always passed as True.
01008 
01009         Returns:
01010             InteractiveMarkerControl
01011         '''
01012         control = InteractiveMarkerControl()
01013         control.name = name
01014         control.orientation = orientation
01015         control.always_visible = False
01016         if self._is_control_visible:
01017             if is_move:
01018                 control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
01019             else:
01020                 control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
01021         else:
01022             control.interaction_mode = InteractiveMarkerControl.NONE
01023         if is_fixed:
01024             control.orientation_mode = InteractiveMarkerControl.FIXED
01025         return control
01026 
01027     def _make_sphere_marker(self, uid, pose, frame_id, radius):
01028         '''Creates and returns a sphere marker.
01029 
01030         Args:
01031             uid (int): The id to use for the marker.
01032             pose (Pose): The pose of the marker.
01033             frame_id (str): Frame the marker is associated with. (See
01034                 std_msgs/Header.msg for more info.)
01035             radius (float): Amount to scale the marker by. Scales in all
01036                 directions (x, y, and z).
01037 
01038         Returns:
01039             Marker
01040         '''
01041         return Marker(
01042             type=Marker.SPHERE,
01043             id=uid,
01044             lifetime=rospy.Duration(2),
01045             scale=Vector3(radius, radius, radius),
01046             pose=pose,
01047             header=Header(frame_id=frame_id),
01048             color=self._color_traj_endpoint_spheres
01049         )
01050 
01051     def _delete_primitive_cb(self, feedback):
01052         '''Callback for when delete is requested.
01053 
01054         Args:
01055             feedback (InteractiveMarkerFeedback): Unused
01056         '''
01057         self._marker_delete_cb(self._number)
01058 
01059     def _get_traj_pose(self, index):
01060         '''Returns this trajectory's pose at index.
01061 
01062         Args:
01063             index (int): Which step in the trajectory to return the
01064                 pose from.
01065 
01066         Returns:
01067             Pose
01068         '''
01069         try:
01070             # intermediate_pose = self._tf_listener.transformPose(
01071             #                             BASE_LINK,
01072             #                             self._arm_states[index].ee_pose)
01073             offset_pose = ArmTrajectory._offset_pose(
01074                                             self._arm_states[index].ee_pose)
01075 
01076             new_pose = self._tf_listener.transformPose(
01077                                             "primitive_" + str(self._number),
01078                                             offset_pose)
01079             return new_pose
01080 
01081         except Exception, e:
01082             rospy.logwarn(e)
01083             rospy.logwarn("Unable to transform marker to" +
01084                     "correct frame: {}".format("primitive_" + str(self._number)))
01085             return None
01086 
01087     def _marker_feedback_cb(self, feedback):
01088         '''Callback for when an event occurs on the marker.
01089 
01090         Args:
01091             feedback (InteractiveMarkerFeedback)
01092         '''
01093         if feedback.event_type == InteractiveMarkerFeedback.POSE_UPDATE:
01094             rospy.logwarn(
01095                 'Modification of trajectory segments is not ' +
01096                 'implemented.')
01097         elif feedback.event_type == InteractiveMarkerFeedback.BUTTON_CLICK:
01098             # Set the visibility of the 6DOF controller.
01099             # This happens a ton, and doesn't need to be logged like
01100             # normal events (e.g. clicking on most marker controls
01101             # fires here).
01102             rospy.logdebug('Changing visibility of the pose controls.')
01103             self._is_control_visible = not self._is_control_visible
01104             self._marker_click_cb(
01105                 self._number, self._is_control_visible)
01106         else:
01107             # This happens a ton, and doesn't need to be logged like
01108             # normal events (e.g. clicking on most marker controls
01109             # fires here).
01110             rospy.logdebug('Unknown event: ' + str(feedback.event_type))


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