00001
00002
00003 import roslib; roslib.load_manifest('simulation_object_tracker')
00004 import rospy
00005 import actionlib
00006
00007 import sys, traceback
00008 import copy
00009 import math
00010 from hardcoded_facts.geometry_pose_loader import read_pose_stamped_file
00011 from visualization_msgs import msg as visualization
00012 from geometry_msgs import msg as geometry
00013 from tidyup_msgs import srv
00014 from tidyup_msgs import msg
00015 from arm_navigation_msgs.msg import CollisionObject, Shape, OrderedCollisionOperations, CollisionOperation, ArmNavigationErrorCodes
00016 from pr2_python.world_interface import WorldInterface
00017 from pr2_python.arm_mover import ArmMover
00018 from pr2_python.arm_planner import ArmPlanner
00019 from pr2_python.planning_scene_interface import get_planning_scene_interface
00020 from pr2_python import transform_listener
00021 from pr2_python.exceptions import ArmNavError
00022 from pr2_python.arm_mover import ArmMover
00023 import tf
00024
00025 class SimulatedDoor():
00026 def __init__(self, name):
00027 self.open = False
00028 self._poses = dict()
00029 self.name = name
00030 def current_pose(self):
00031 return self._poses[self.open]
00032 def add_pose(self, open, pose):
00033 self._poses[open] = pose
00034
00035 class ObjectTracker():
00036
00037 def __init__(self, simulate_moving):
00038 self.simulate_movable_objects = simulate_moving
00039
00040
00041 self._wi = WorldInterface()
00042 self._wi.reset()
00043 self._psi = get_planning_scene_interface()
00044 self._psi.reset()
00045 self._transformListener = transform_listener.get_transform_listener()
00046 self._arm_mover = ArmMover()
00047 self._right_arm_planner = self._arm_mover._planners['right_arm']
00048 self._left_arm_planner = self._arm_mover._planners['left_arm']
00049
00050 self._doors = dict()
00051
00052 self._movable_objects = dict()
00053
00054 if self.simulate_movable_objects:
00055
00056 self._detectGraspableObjectsService = rospy.Service('/tidyup/detect_objects', srv.DetectGraspableObjects, self._detect_objects_callback)
00057
00058
00059
00060
00061
00062
00063 self._detectDoorService = rospy.Service('/tidyup/detect_door_state', srv.DetectDoorState, self._detect_door_state_callback)
00064 self._openDoorActionServer = actionlib.SimpleActionServer('/tidyup/open_door', msg.OpenDoorAction, self._open_door_execute, False)
00065 self._openDoorActionServer.start()
00066
00067 rospy.loginfo('[{0}]initialized.'.format(rospy.get_name()))
00068
00069 def _detect_objects_callback(self, request):
00070 self._psi.reset()
00071 rospy.loginfo('request: detect objects.')
00072
00073 visibles = [self._create_tidyup_object(name, pose_stamped) for name, pose_stamped in self._movable_objects.items() if self._pose_in_view(pose_stamped)]
00074 for object in visibles:
00075
00076 self._movable_objects.pop(object.name)
00077 if object.name.startswith('plate'):
00078 rospy.loginfo('added plate {0} to environment.'.format(object.name))
00079 object.pose.pose.position.z += 0.015
00080 self._wi.add_collision_box(object.pose, [0.25, 0.25, 0.03], object.name)
00081 elif object.name.startswith('bowl'):
00082 rospy.loginfo('added bowl {0} to environment.'.format(object.name))
00083 object.pose.pose.position.z += 0.035
00084 self._wi.add_collision_box(object.pose, [0.17, 0.17, 0.07], object.name)
00085 elif object.name.startswith('cup'):
00086 rospy.loginfo('added cup {0} to environment.'.format(object.name))
00087 object.pose.pose.position.z += 0.075
00088 self._wi.add_collision_box(object.pose, [0.07, 0.07, 0.15], object.name)
00089
00090 ps_visibles = [self._convert_collision_object_to_tidyup_object(object) for object in self._psi.collision_objects() if self._object_in_view(object)]
00091 visibles.extend(ps_visibles)
00092 self._psi.reset()
00093 return { 'objects': visibles}
00094
00095 def _request_graspability_callback(self, request):
00096 rospy.loginfo('request: object graspability.')
00097 for object in request.objects:
00098 object.reachable_right_arm = self._object_in_reach(object, self._right_arm_planner)
00099 object.reachable_left_arm = self._object_in_reach(object, self._left_arm_planner)
00100 return { 'objects': request.objects}
00101
00102 def _pick_up_execute(self, goal):
00103 self._psi.reset()
00104 arm_name = 'no_arm'
00105 if goal.right_arm:
00106 arm_name = 'right_arm'
00107 elif goal.left_arm:
00108 arm_name = 'left_arm'
00109 target = self._wi.collision_object(goal.target.name)
00110 if not target:
00111 self._pickUpActionServer.set_aborted(text='pick-up: specified object {0} does not exist.'.format(goal.target.name))
00112 return
00113
00114 rospy.loginfo('executing: pick up of {0} with {1}.'.format(target.id, arm_name))
00115
00116 collisions = OrderedCollisionOperations()
00117 collision = CollisionOperation()
00118 collision.object1 = goal.target.name
00119 collision.object2 = collision.COLLISION_SET_ALL
00120 collision.operation = collision.DISABLE
00121 collisions.collision_operations.append(collision)
00122 gripper_pose = geometry.PoseStamped()
00123 gripper_pose.pose = transform_listener.transform_pose('/torso_lift_link', '/map', goal.target.pose.pose)
00124 gripper_pose.header.frame_id = '/torso_lift_link'
00125 gripper_pose.pose.position.z += 0.2
00126 gripper_pose.pose.orientation.x = 0.7071
00127 gripper_pose.pose.orientation.y = 0.0
00128 gripper_pose.pose.orientation.z = -0.7071
00129 gripper_pose.pose.orientation.w = 0.0
00130 reached_goal = self._arm_mover.move_to_goal(arm_name, gripper_pose, ordered_collisions=collisions)
00131 self._psi.reset()
00132 if reached_goal:
00133 self._wi.attach_object_to_gripper(arm_name, target.id)
00134 self._psi.reset()
00135 self._pickUpActionServer.set_succeeded(text='pickup successful')
00136 return
00137 self._pickUpActionServer.set_aborted(text='execution failed')
00138
00139 def _create_tidyup_object(self, name, pose_stamped):
00140 tidyup_object = msg.GraspableObject()
00141 tidyup_object.name = name
00142 tidyup_object.pose = pose_stamped
00143 return tidyup_object
00144
00145 def _convert_collision_object_to_tidyup_object(self, object):
00146 tidyup_object = msg.GraspableObject()
00147 tidyup_object.name = object.id
00148 tidyup_object.pose = geometry.PoseStamped()
00149 tidyup_object.pose.pose = object.poses[0]
00150 tidyup_object.pose.header.frame_id = object.header.frame_id
00151 return tidyup_object
00152
00153 def _detect_door_state_callback(self, request):
00154 rospy.loginfo('request: detect door state.')
00155 for door in self._doors.values():
00156 if self._pose_in_view(door.current_pose()):
00157 return { 'door_open': door.open}
00158
00159 rospy.loginfo('detect door: no door in view. assuming door is open.')
00160 return { 'door_open': True}
00161
00162 def _open_door_execute(self, goal):
00163 self._psi.reset()
00164 arm_name = 'no_arm'
00165 if goal.right_arm:
00166 arm_name = 'right_arm'
00167 elif goal.left_arm:
00168 arm_name = 'left_arm'
00169 rospy.loginfo('executing: open door with {0}.'.format(arm_name))
00170
00171 for door in self._doors.values():
00172 if self._pose_in_view(door.current_pose()):
00173
00174 door.open = True
00175
00176 self._update_door_pose(door)
00177 self._psi.reset()
00178 self._openDoorActionServer.set_succeeded(text='succeeded: door is open')
00179 return
00180 rospy.logerr('request failed: no door in view')
00181 self._openDoorActionServer.set_aborted(text='failed: not in front of door')
00182
00183 def _pose_in_view(self, pose_stamped):
00184
00185 object_pose = transform_listener.transform_pose('/head_pan_link', pose_stamped.header.frame_id, pose_stamped.pose)
00186
00187 yawAngle = math.atan2(object_pose.position.y, object_pose.position.x)
00188 maxYawAngle = math.pi/4.0
00189 minX = 0.2
00190 maxX = 2.0
00191 if math.fabs(yawAngle) < maxYawAngle and minX < object_pose.position.x < maxX:
00192 return True
00193 return False
00194
00195 def _object_in_view(self, object):
00196
00197 if object.id.startswith('table') or object.id.startswith('door'):
00198 return False
00199
00200
00201 object_pose = transform_listener.transform_pose('/head_pan_link', object.header.frame_id, object.poses[0])
00202
00203 yawAngle = math.atan2(object_pose.position.y, object_pose.position.x)
00204 maxYawAngle = math.pi/4.0
00205 minX = 0.2
00206 maxX = 2.0
00207 if math.fabs(yawAngle) < maxYawAngle and minX < object_pose.position.x < maxX:
00208
00209 return True
00210
00211 return False
00212
00213 def _object_in_reach(self, object, arm_planner):
00214
00215 self._psi.reset()
00216
00217 collisions = OrderedCollisionOperations()
00218 collision = CollisionOperation()
00219 collision.object1 = object.name
00220 collision.object2 = collision.COLLISION_SET_ALL
00221 collision.operation = collision.DISABLE
00222 collisions.collision_operations.append(collision)
00223 gripper_pose = geometry.PoseStamped()
00224 gripper_pose.pose = transform_listener.transform_pose('/torso_lift_link', '/map', object.pose.pose)
00225 gripper_pose.header.frame_id = '/torso_lift_link'
00226 gripper_pose.pose.position.z += 0.2
00227 gripper_pose.pose.orientation.x = 0.7071
00228 gripper_pose.pose.orientation.y = 0.0
00229 gripper_pose.pose.orientation.z = -0.7071
00230 gripper_pose.pose.orientation.w = 0.0
00231 response = arm_planner.get_ik(gripper_pose, ordered_collisions=collisions)
00232 self._psi.reset()
00233 return response.error_code.val == ArmNavigationErrorCodes.SUCCESS
00234
00235 def poseStampToStr(self, pose):
00236 (_, _, yaw) = tf.transformations.euler_from_quaternion([pose.pose.orientation.x, pose.pose.orientation.y, pose.pose.orientation.z, pose.pose.orientation.w])
00237 ps = "position: (%.2f, %.2f, %.2f) - quat: (%.2f, %.2f, %.2f, %.2f) - yaw: %.2f deg" % \
00238 (pose.pose.position.x, pose.pose.position.y, pose.pose.position.z, \
00239 pose.pose.orientation.x, pose.pose.orientation.y, pose.pose.orientation.z, pose.pose.orientation.w, 180.0/math.pi*yaw)
00240 return ps
00241
00242 def create_objects(self, dataFileName):
00243
00244 poses = read_pose_stamped_file(dataFileName)
00245 rospy.loginfo("Creating virtual objects:")
00246 for name, pose in poses.items():
00247 if name.startswith('table'):
00248 rospy.loginfo("Adding table: " + name + " at " + self.poseStampToStr(pose))
00249 self.add_table(pose, name)
00250 elif name.startswith('door'):
00251 rospy.loginfo("Adding door: " + name + " at " + self.poseStampToStr(pose))
00252 self.add_door(pose, name)
00253 elif self.simulate_movable_objects:
00254 rospy.loginfo("Adding movable object: " + name + " at " + self.poseStampToStr(pose))
00255 self._movable_objects[name] = pose
00256 self._psi.reset()
00257
00258 def add_door(self, pose, pose_name):
00259 if pose_name.endswith('_closed'):
00260 open_key = False
00261 name = pose_name[:-len('_closed')]
00262 elif pose_name.endswith('_open'):
00263 name = pose_name[:-len('_open')]
00264 open_key = True
00265 if self._doors.has_key(name):
00266 door = self._doors[name]
00267 else:
00268 door = SimulatedDoor(name)
00269 self._doors[name] = door
00270 door.add_pose(open_key, pose)
00271 if door.open == open_key:
00272 self._update_door_pose(door)
00273
00274 def _update_door_pose(self, door):
00275 self._wi.add_collision_box(door.current_pose(), [0.05, 1.0, 2.0], door.name)
00276
00277 def add_table(self, pose, id):
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 self._wi.add_collision_box(pose, [0.7, 1.0, 0.05], id)
00294