00001 '''Defines behaviour for ArmTrajectory primitive. This is for primitives
00002 where the arm moves to a series of poses.
00003 '''
00004
00005
00006
00007
00008
00009
00010 import rospy
00011
00012
00013 from collections import Counter
00014
00015
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
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
00033
00034
00035
00036
00037
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
00043
00044
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
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
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
00066
00067
00068
00069 ID_OFFSET_REF_ARROW = 1000
00070 ID_OFFSET_TRAJ_FIRST = 2000
00071 ID_OFFSET_TRAJ_LAST = 3000
00072
00073
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
00080
00081
00082 TOPIC_IM_SERVER = 'programmed_actions'
00083
00084
00085
00086 BASE_LINK = 'base_link'
00087 FIXED_LINK = 'torso_lift_link'
00088
00089
00090
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 = ''
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
00121
00122
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
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
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
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
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
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
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
00436
00437
00438
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
00462
00463
00464
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
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
00503
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
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
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
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
00785
00786
00787 def _update_menu(self):
00788 '''Recreates the menu when something has changed.'''
00789 self._menu_handler = MenuHandler()
00790
00791
00792 self._sub_entries = []
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 self._menu_handler.insert(
00807 MENU_OPTIONS['del'], callback=self._delete_primitive_cb)
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
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
00850
00851
00852
00853
00854
00855
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
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
00876
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
00914
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
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
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
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
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
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
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
01071
01072
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
01099
01100
01101
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
01108
01109
01110 rospy.logdebug('Unknown event: ' + str(feedback.event_type))