00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 import roslib; roslib.load_manifest('tabletop_pushing')
00035 import rospy
00036 import actionlib
00037 import hrl_pr2_lib.linear_move as lm
00038 import hrl_pr2_lib.pr2 as pr2
00039 import hrl_lib.tf_utils as tfu
00040 from geometry_msgs.msg import PoseStamped
00041 import tf
00042 import numpy as np
00043 from tabletop_pushing.srv import *
00044 from tabletop_pushing.msg import *
00045 from math import sin, cos, pi, fabs
00046 import sys
00047 
00048 GRIPPER_PUSH = 0
00049 GRIPPER_SWEEP = 1
00050 OVERHEAD_PUSH = 2
00051 OVERHEAD_PULL = 3
00052 
00053 class SingulationExecutive:
00054 
00055     def __init__(self, use_fake_push_pose=False):
00056         rospy.init_node('tabletop_executive_node',log_level=rospy.DEBUG)
00057         
00058         self.min_push_dist = rospy.get_param('~min_push_dist', 0.07)
00059         self.max_push_dist = rospy.get_param('~mix_push_dist', 0.3)
00060         self.use_overhead_x_thresh = rospy.get_param('~use_overhead_x_thresh',
00061                                                      0.55)
00062         self.use_sweep_angle_thresh = rospy.get_param('~use_sweep_angle_thresh',
00063                                                      pi*0.4)
00064         self.use_pull_angle_thresh = rospy.get_param('~use_sweep_angle_thresh',
00065                                                      pi*0.525)
00066         self.use_same_side_y_thresh = rospy.get_param('~use_same_side_y_thresh',
00067                                                      0.3)
00068         self.use_same_side_x_thresh = rospy.get_param('~use_same_side_x_thresh',
00069                                                       0.8)
00070 
00071         
00072         
00073         self.gripper_x_offset = rospy.get_param('~gripper_push_start_x_offset',
00074                                                 -0.05)
00075         self.gripper_y_offset = rospy.get_param('~gripper_push_start_y_offset',
00076                                                 0.0)
00077         self.gripper_start_z = rospy.get_param('~gripper_push_start_z',
00078                                                 -0.25)
00079 
00080         self.sweep_x_offset = rospy.get_param('~gripper_sweep_start_x_offset',
00081                                               -0.01)
00082         self.sweep_y_offset = rospy.get_param('~gripper_sweep_start_y_offset',
00083                                               0.03)
00084         self.sweep_start_z = rospy.get_param('~gripper_sweep_start_z',
00085                                               -0.22)
00086 
00087         self.overhead_x_offset = rospy.get_param('~overhead_push_start_x_offset',
00088                                                  0.00)
00089         self.overhead_y_offset = rospy.get_param('~overhead_push_start_y_offset',
00090                                                  0.00)
00091         self.overhead_start_z = rospy.get_param('~overhead_push_start_z',
00092                                                  -0.25)
00093         self.pull_dist_offset = rospy.get_param('~overhead_pull_dist_offset',
00094                                                 0.05)
00095         self.pull_start_z = rospy.get_param('~overhead_push_start_z',
00096                                             -0.27)
00097         
00098         self.push_pose_proxy = rospy.ServiceProxy('get_push_pose', PushVector)
00099         self.gripper_push_proxy = rospy.ServiceProxy('gripper_push',
00100                                                      GripperPush)
00101         self.gripper_pre_push_proxy = rospy.ServiceProxy('gripper_pre_push',
00102                                                          GripperPush)
00103         self.gripper_post_push_proxy = rospy.ServiceProxy('gripper_post_push',
00104                                                           GripperPush)
00105         self.gripper_pre_sweep_proxy = rospy.ServiceProxy('gripper_pre_sweep',
00106                                                           GripperPush)
00107         self.gripper_sweep_proxy = rospy.ServiceProxy('gripper_sweep',
00108                                                       GripperPush)
00109         self.gripper_post_sweep_proxy = rospy.ServiceProxy('gripper_post_sweep',
00110                                                            GripperPush)
00111         self.overhead_pre_push_proxy = rospy.ServiceProxy('overhead_pre_push',
00112                                                           GripperPush)
00113         self.overhead_push_proxy = rospy.ServiceProxy('overhead_push',
00114                                                       GripperPush)
00115         self.overhead_post_push_proxy = rospy.ServiceProxy('overhead_post_push',
00116                                                            GripperPush)
00117         self.overhead_pre_pull_proxy = rospy.ServiceProxy('overhead_pre_pull',
00118                                                           GripperPush)
00119         self.overhead_pull_proxy = rospy.ServiceProxy('overhead_pull',
00120                                                       GripperPush)
00121         self.overhead_post_pull_proxy = rospy.ServiceProxy('overhead_post_pull',
00122                                                            GripperPush)
00123         self.raise_and_look_proxy = rospy.ServiceProxy('raise_and_look',
00124                                                        RaiseAndLook)
00125         self.table_proxy = rospy.ServiceProxy('get_table_location', LocateTable)
00126         
00127         self.use_fake_push_pose = use_fake_push_pose
00128         self.push_count = 0
00129 
00130     def run(self, num_pushes=1, use_guided=True):
00131         
00132         self.raise_and_look()
00133         
00134         self.initialize_push_pose();
00135 
00136         
00137         for i in xrange(num_pushes):
00138             pose_res = self.request_singulation_push(use_guided)
00139             
00140             
00141             if pose_res is None:
00142                 rospy.logwarn("pose_res is None. Exiting pushing");
00143                 break
00144             if pose_res.no_push:
00145                 rospy.loginfo("No push. Exiting pushing.");
00146                 break
00147             rospy.loginfo('Performing push #' + str(i+1))
00148             
00149             rospy.loginfo('Push start_point: (' + str(pose_res.start_point.x) +
00150                           ', ' + str(pose_res.start_point.y) +
00151                           ', ' + str(pose_res.start_point.z) + ')')
00152             rospy.loginfo('Push angle: ' + str(pose_res.push_angle))
00153             rospy.loginfo('Push dist: ' + str(pose_res.push_dist))
00154 
00155             
00156             
00157             if fabs(pose_res.push_angle) > self.use_pull_angle_thresh:
00158                 push_opt = OVERHEAD_PULL
00159             elif pose_res.start_point.x < self.use_overhead_x_thresh:
00160                 push_opt = OVERHEAD_PUSH
00161             elif fabs(pose_res.push_angle) > self.use_sweep_angle_thresh:
00162                 push_opt = GRIPPER_SWEEP
00163             else:
00164                 push_opt = GRIPPER_PUSH
00165 
00166             
00167             
00168             if (fabs(pose_res.start_point.y) > self.use_same_side_y_thresh or
00169                 pose_res.start_point.x > self.use_same_side_x_thresh):
00170                 if (pose_res.start_point.y < 0):
00171                     which_arm = 'r'
00172                     rospy.loginfo('Setting arm to right because of limits')
00173                 else:
00174                     which_arm = 'l'
00175                     rospy.loginfo('Setting arm to left because of limits')
00176             elif pose_res.push_angle > 0:
00177                 which_arm = 'r'
00178                 rospy.loginfo('Setting arm to right because of angle')
00179             else:
00180                 which_arm = 'l'
00181                 rospy.loginfo('Setting arm to left because of angle')
00182 
00183             push_dist = pose_res.push_dist
00184             push_dist = max(min(push_dist, self.max_push_dist),
00185                             self.min_push_dist)
00186             if push_opt == GRIPPER_PUSH:
00187                 self.gripper_push_object(push_dist, which_arm, pose_res)
00188             if push_opt == GRIPPER_SWEEP:
00189                 self.sweep_object(push_dist, which_arm, pose_res)
00190             if push_opt == OVERHEAD_PUSH:
00191                 self.overhead_push_object(push_dist, which_arm, pose_res)
00192             if push_opt == OVERHEAD_PULL:
00193                 self.overhead_pull_object(push_dist, which_arm, pose_res)
00194             rospy.loginfo('Done performing push behavior.\n')
00195 
00196         if not (pose_res is None):
00197             rospy.loginfo('Singulated objects: ' + str(pose_res.singulated))
00198             rospy.loginfo('Final estimate of ' + str(pose_res.num_objects) +
00199                           ' objects')
00200 
00201     def request_singulation_push(self, use_guided=True, which_arm='l'):
00202         if (self.use_fake_push_pose):
00203             return request_fake_singulation_push(which_arm)
00204         pose_req = PushVectorRequest()
00205         pose_req.use_guided = use_guided
00206         pose_req.initialize = False
00207         pose_req.no_push_calc = False
00208         rospy.loginfo("Calling push pose service")
00209         try:
00210             pose_res = self.push_pose_proxy(pose_req)
00211             return pose_res
00212         except rospy.ServiceException, e:
00213             rospy.logwarn("Service did not process request: %s"%str(e))
00214             return None
00215 
00216     def request_fake_singulation_push(self, which_arm):
00217         pose_res = PushVectorResponse()
00218         push_opt = GRIPPER_PUSH
00219         if push_opt == GRIPPER_PUSH:
00220             pose_res = PushVectorResponse()
00221             pose_res.start_point.x = 0.5
00222             pose_res.header.frame_id = '/torso_lift_link'
00223             pose_res.header.stamp = rospy.Time(0)
00224             if which_arm == 'l':
00225                 pose_res.start_point.y = 0.3 - self.push_count*0.15
00226             else:
00227                 pose_res.start_point.y = -0.3 + self.push_count*0.15
00228             pose_res.start_point.z = -0.22
00229         elif push_opt == GRIPPER_SWEEP:
00230             pose_res.header.frame_id = '/torso_lift_link'
00231             pose_res.header.stamp = rospy.Time(0)
00232             pose_res.start_point.x = 0.75
00233             if which_arm == 'l':
00234                 pose_res.start_point.y = 0.05
00235             else:
00236                 pose_res.start_point.y = -0.15
00237             pose_res.start_point.z = -0.25
00238         elif push_opt == OVERHEAD_PUSH:
00239             pose_res.header.frame_id = '/torso_lift_link'
00240             pose_res.header.stamp = rospy.Time(0)
00241             pose_res.start_point.x = 0.7
00242             pose_res.start_point.y = 0.0
00243             pose_res.start_point.z = -0.25
00244             pose_res.push_dist = 0.15
00245             pose_res.push_angle = 0.75*pi
00246         return pose_res
00247 
00248     def initialize_push_pose(self):
00249         pose_req = PushVectorRequest()
00250         pose_req.initialize = True
00251         pose_req.use_guided = True
00252         pose_req.no_push_calc = False
00253         rospy.loginfo('Initializing push pose service.')
00254         self.push_pose_proxy(pose_req)
00255 
00256     def raise_and_look(self):
00257         table_req = LocateTableRequest()
00258         table_req.recalculate = True
00259         raise_req = RaiseAndLookRequest()
00260         raise_req.point_head_only = True
00261         raise_req.camera_frame = 'openni_rgb_frame'
00262         
00263         
00264         
00265         raise_req.init_arms = True
00266         rospy.loginfo("Moving head and arms")
00267         raise_res = self.raise_and_look_proxy(raise_req)
00268         try:
00269             rospy.loginfo("Getting table pose")
00270             table_res = self.table_proxy(table_req);
00271         except rospy.ServiceException, e:
00272             rospy.logwarn("Service did not process request: %s"%str(e))
00273             return
00274         if not table_res.found_table:
00275             return
00276         raise_req.table_centroid = table_res.table_centroid
00277 
00278         
00279 
00280         rospy.loginfo("Raising spine");
00281         raise_req.point_head_only = False
00282         raise_req.init_arms = False
00283         raise_res = self.raise_and_look_proxy(raise_req)
00284 
00285     def gripper_push_object(self, push_dist, which_arm, pose_res):
00286         
00287         push_req = GripperPushRequest()
00288         push_req.start_point.header = pose_res.header
00289         push_req.start_point.point = pose_res.start_point
00290         push_req.arm_init = True
00291         push_req.arm_reset = True
00292         push_req.high_arm_init = True
00293 
00294         
00295         wrist_yaw = pose_res.push_angle
00296         push_req.wrist_yaw = wrist_yaw
00297         push_req.desired_push_dist = push_dist + abs(self.gripper_x_offset)
00298 
00299         
00300         push_req.start_point.point.x += self.gripper_x_offset*cos(wrist_yaw)
00301         push_req.start_point.point.y += self.gripper_x_offset*sin(wrist_yaw)
00302         push_req.start_point.point.z = self.gripper_start_z
00303         push_req.left_arm = (which_arm == 'l')
00304         push_req.right_arm = not push_req.left_arm
00305 
00306         rospy.loginfo("Calling gripper pre push service")
00307         pre_push_res = self.gripper_pre_push_proxy(push_req)
00308         rospy.loginfo("Calling gripper push service")
00309         push_res = self.gripper_push_proxy(push_req)
00310         rospy.loginfo("Calling gripper post push service")
00311         post_push_res = self.gripper_post_push_proxy(push_req)
00312 
00313     def sweep_object(self, push_dist, which_arm, pose_res):
00314         
00315         sweep_req = GripperPushRequest()
00316         sweep_req.left_arm = (which_arm == 'l')
00317         sweep_req.right_arm = not sweep_req.left_arm
00318         push_req.high_arm_init = True
00319 
00320         
00321         if pose_res.push_angle > 0:
00322             y_offset_dir = -1
00323         else:
00324             y_offset_dir = +1
00325 
00326         
00327         if pose_res.push_angle > 0.0:
00328             wrist_yaw = pose_res.push_angle - pi/2
00329         else:
00330             wrist_yaw = pose_res.push_angle + pi/2
00331         sweep_req.wrist_yaw = wrist_yaw
00332         sweep_req.desired_push_dist = -y_offset_dir*(self.sweep_y_offset +
00333                                                      push_dist)
00334 
00335         
00336         sweep_req.start_point.header = pose_res.header
00337         sweep_req.start_point.point = pose_res.start_point
00338         sweep_req.start_point.point.x += self.sweep_x_offset
00339         sweep_req.start_point.point.y += y_offset_dir*self.sweep_y_offset
00340         sweep_req.start_point.point.z = self.sweep_start_z
00341         sweep_req.arm_init = True
00342         sweep_req.arm_reset = True
00343 
00344         rospy.loginfo("Calling gripper pre sweep service")
00345         pre_sweep_res = self.gripper_pre_sweep_proxy(sweep_req)
00346         rospy.loginfo("Calling gripper sweep service")
00347         sweep_res = self.gripper_sweep_proxy(sweep_req)
00348         rospy.loginfo("Calling gripper post sweep service")
00349         post_sweep_res = self.gripper_post_sweep_proxy(sweep_req)
00350 
00351     def overhead_push_object(self, push_dist, which_arm, pose_res):
00352         
00353         push_req = GripperPushRequest()
00354         push_req.start_point.header = pose_res.header
00355         push_req.start_point.point = pose_res.start_point
00356         push_req.arm_init = True
00357         push_req.arm_reset = True
00358         push_req.high_arm_init = True
00359 
00360         
00361         wrist_yaw = pose_res.push_angle
00362         push_req.wrist_yaw = wrist_yaw
00363         push_req.desired_push_dist = push_dist
00364 
00365         
00366         push_req.start_point.point.x += self.overhead_x_offset*cos(wrist_yaw)
00367         push_req.start_point.point.y += self.overhead_x_offset*sin(wrist_yaw)
00368         push_req.start_point.point.z = self.overhead_start_z
00369         push_req.left_arm = (which_arm == 'l')
00370         push_req.right_arm = not push_req.left_arm
00371 
00372         rospy.loginfo("Calling pre overhead push service")
00373         pre_push_res = self.overhead_pre_push_proxy(push_req)
00374         rospy.loginfo("Calling overhead push service")
00375         push_res = self.overhead_push_proxy(push_req)
00376         rospy.loginfo("Calling post overhead push service")
00377         post_push_res = self.overhead_post_push_proxy(push_req)
00378 
00379     def overhead_pull_object(self, push_dist, which_arm, pose_res):
00380         
00381         push_req = GripperPushRequest()
00382         push_req.start_point.header = pose_res.header
00383         push_req.start_point.point = pose_res.start_point
00384         push_req.arm_init = True
00385         push_req.arm_reset = True
00386         push_req.high_arm_init = True
00387 
00388         wrist_yaw = pose_res.push_angle
00389         
00390         while wrist_yaw < -pi*0.5:
00391             wrist_yaw += pi
00392         while wrist_yaw > pi*0.5:
00393             wrist_yaw -= pi
00394         push_req.wrist_yaw = wrist_yaw
00395         
00396         push_req.desired_push_dist = push_dist + self.pull_dist_offset
00397 
00398         
00399         rospy.loginfo('Pre pull offset (x,y): (' +
00400                       str(push_req.start_point.point.x) + ', ' +
00401                       str(push_req.start_point.point.y) + ')')
00402         push_req.start_point.point.x += self.pull_dist_offset*cos(wrist_yaw)
00403         push_req.start_point.point.y += self.pull_dist_offset*sin(wrist_yaw)
00404         push_req.start_point.point.z = self.pull_start_z
00405         push_req.left_arm = (which_arm == 'l')
00406         push_req.right_arm = not push_req.left_arm
00407 
00408         rospy.loginfo('Post pull offset (x,y): (' +
00409                       str(push_req.start_point.point.x) + ', ' +
00410                       str(push_req.start_point.point.y) + ')')
00411 
00412         rospy.loginfo("Calling pre overhead pull service")
00413         pre_push_res = self.overhead_pre_pull_proxy(push_req)
00414         rospy.loginfo("Calling overhead pull service")
00415         push_res = self.overhead_pull_proxy(push_req)
00416         rospy.loginfo("Calling post overhead pull service")
00417         post_push_res = self.overhead_post_pull_proxy(push_req)
00418 
00419 if __name__ == '__main__':
00420     guided = True
00421     node = SingulationExecutive(False)
00422     node.run(50, guided)