segmented_clutter_grasp_planner.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 # Software License Agreement (BSD License)
00003 #
00004 # Copyright (c) 2011, Willow Garage, Inc.
00005 # All rights reserved.
00006 #
00007 # Redistribution and use in source and binary forms, with or without
00008 # modification, are permitted provided that the following conditions
00009 # are met:
00010 #
00011 #  * Redistributions of source code must retain the above copyright
00012 #    notice, this list of conditions and the following disclaimer.
00013 #  * Redistributions in binary form must reproduce the above
00014 #    copyright notice, this list of conditions and the following
00015 #    disclaimer in the documentation and/or other materials provided
00016 #    with the distribution.
00017 #  * Neither the name of the Willow Garage nor the names of its
00018 #    contributors may be used to endorse or promote products derived
00019 #    from this software without specific prior written permission.
00020 #
00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 # POSSIBILITY OF SUCH DAMAGE.
00033 #
00034 # author: Kaijen Hsiao
00035 
00036 ## @package segmented_clutter_grasp_planner
00037 # Finds clusters in clutter, then runs the cluster planner to plan grasps on regions of interest in PointCloud2s
00038 
00039 from __future__ import division
00040 import roslib
00041 roslib.load_manifest('segmented_clutter_grasp_planner')
00042 import rospy
00043 import actionlib
00044 import tf
00045 import time
00046 
00047 from sensor_msgs.msg import CameraInfo, JointState, RegionOfInterest, PointCloud2
00048 from object_manipulation_msgs.msg import Grasp
00049 from object_manipulator.convert_functions import *
00050 from object_manipulator.image_region_functions import *
00051 from object_manipulation_msgs.srv import GraspPlanning, GraspPlanningResponse, GraspPlanningRequest
00052 from object_manipulation_msgs.msg import GraspPlanningAction, GraspPlanningResult, GraspPlanningErrorCode
00053 from pr2_gripper_grasp_planner_cluster.srv import SetPointClusterGraspParams, SetPointClusterGraspParamsRequest
00054 from object_manipulation_msgs.msg import FindContainerAction, FindContainerGoal
00055 from arm_navigation_msgs.srv import SetPlanningSceneDiff, SetPlanningSceneDiffRequest
00056 
00057 class ClusteredClutterGraspPlanner(object):
00058 
00059     def __init__(self, tf_listener = None, advertise_service = False, advertise_action = True):
00060 
00061         #init a TF transform listener
00062         if tf_listener == None:
00063             self.tf_listener = tf.TransformListener()
00064         else:
00065             self.tf_listener = tf_listener
00066 
00067         #point cloud processing action
00068         self._container_client = actionlib.SimpleActionClient('find_container_action', FindContainerAction)
00069         rospy.loginfo("Waiting for find_container_action...")
00070         self._container_client.wait_for_server()
00071 
00072         #cluster grasp planning service
00073         service_name = "plan_point_cluster_grasp"
00074         rospy.loginfo("waiting for plan_point_cluster_grasp service")
00075         rospy.wait_for_service(service_name)
00076         rospy.loginfo("service found")
00077         self._cluster_grasp_srv = rospy.ServiceProxy(service_name, GraspPlanning)
00078 
00079         #cluster grasp planning params
00080         service_name = "set_point_cluster_grasp_params"
00081         rospy.loginfo("waiting for set_point_cluster_grasp_params service")
00082         rospy.wait_for_service(service_name)
00083         rospy.loginfo("service found")
00084         self._cluster_grasp_params_srv = rospy.ServiceProxy(service_name, SetPointClusterGraspParams)
00085 
00086         #planning scene setting service
00087         planning_scene_srv_name = "environment_server/set_planning_scene_diff"
00088         rospy.loginfo("waiting for %s service"%planning_scene_srv_name)
00089         rospy.wait_for_service(planning_scene_srv_name)
00090         self._planning_scene_srv = rospy.ServiceProxy(planning_scene_srv_name, SetPlanningSceneDiff)
00091 
00092         #what approximate directions should the grasps be pointing into (as with a container)?
00093         self._opening_dir_list = rospy.get_param("~opening_dir_list", [[0,0,1],[-1,0,0]])
00094 
00095         #inserted for HRI studies--if the task number is set, change the opening_dir_list
00096         task_number = rospy.get_param("interactive_grasping/task_number", 0)
00097         if task_number == 3:            
00098             rospy.loginfo("Task number is 3, doing front grasps only.")
00099             self._opening_dir_list = [[-1,0,0]]
00100         elif task_number > 0:
00101             rospy.loginfo("Task number is 1 or 2, doing overhead grasps only.")
00102             self._opening_dir_list = [[0,0,1]]           
00103 
00104         #whether to make the pregrasp just outside the cluster bounding box, or let it be the default (10 cm)
00105         self._pregrasp_just_outside_box = rospy.get_param("~pregrasp_just_outside_box", False)
00106 
00107         #name of the cluster planner service topic
00108         self._cluster_planner_name = rospy.get_param("cluster_planner_name", "point_cluster_grasp_planner")
00109 
00110         #advertise the grasp planning service
00111         if advertise_service:
00112             rospy.Service('plan_segmented_clutter_grasps', GraspPlanning, self.plan_segmented_clutter_grasps_callback)
00113             rospy.loginfo("segmented clutter grasp planner is ready for queries")
00114 
00115         #advertise the grasp planning action
00116         if advertise_action:
00117             self._as = actionlib.SimpleActionServer(rospy.get_name(), GraspPlanningAction, execute_cb = self.segmented_clutter_grasps_execute_cb)
00118             self._as.start()
00119             rospy.loginfo(rospy.get_name()+" is ready for queries")
00120             
00121 
00122     ##service callback for the plan_segmented_clutter_grasps service
00123     def plan_segmented_clutter_grasps_callback(self, req):
00124         rospy.loginfo("planning grasps for a point cloud")
00125         resp = GraspPlanningResponse()        
00126         (grasps, error_code) = self.plan_grasps_for_target(req.target, req.arm_name)
00127         resp.grasps = grasps
00128         resp.error_code = error_code
00129         return resp
00130 
00131 
00132     ##action callback for the segmented_clutter_grasps_action 
00133     def segmented_clutter_grasps_execute_cb(self, goal):
00134         result = GraspPlanningResult()
00135         (grasps, error_code) = self.plan_grasps_for_target(goal.target, goal.arm_name)
00136         result.grasps = grasps
00137         result.error_code = error_code
00138         self._as.set_succeeded(result)
00139 
00140 
00141     ##return grasps for either a service or action request
00142     def plan_grasps_for_target(self, target, arm_name):
00143 
00144         #what approximate directions should the grasps be pointing into (as with a container)?
00145         self._opening_dir_list = rospy.get_param("~opening_dir_list", [[0,0,1],[-1,0,0]])
00146 
00147         #plan grasps for the point cloud region (returned in the roi_box_pose frame)
00148         grasps = []
00149         for opening_dir in self._opening_dir_list:
00150             some_grasps = self.find_grasps(target.region.cloud, target.region.roi_box_pose, target.region.roi_box_dims, arm_name, target.reference_frame_id, opening_dir)
00151             grasps.extend(some_grasps)
00152 
00153         error_code = GraspPlanningErrorCode()
00154         error_code.value = error_code.SUCCESS
00155         if grasps == None:
00156             error_code.value = error_code.OTHER_ERROR
00157             return ([], error_code)
00158 
00159         #if grasps aren't in the reference_frame_id, transform them
00160         #if target.region.roi_box_pose.header.frame_id == target.reference_frame_id:
00161         #    transformed_grasps = grasps
00162         #else:
00163         #    for grasp in grasps:
00164         #        transformed_grasp_pose = change_pose_stamped_frame(self.tf_listener, 
00165         #                                 stamp_pose(grasp.grasp_pose, target.region.roi_box_pose.header.frame_id), 
00166         #                                 target.reference_frame_id).pose
00167         #        grasp.grasp_pose = transformed_grasp_pose
00168 
00169         return (grasps, error_code)
00170 
00171 
00172     ##call the find_container_action to remove parallel-to-container-side points and cluster the contents 
00173     def process_point_cloud(self, point_cloud, box_pose, box_dims, opening_dir):
00174 
00175         # x: 0 - 0.5 y: -0.3 to -0.7  z: 0.22 - 0.82
00176         container_goal = FindContainerGoal()
00177         container_goal.cloud = point_cloud
00178         container_goal.box_pose = box_pose
00179         container_goal.box_dims = box_dims
00180         set_xyz(container_goal.opening_dir, opening_dir)
00181 
00182         success = self._container_client.send_goal_and_wait(container_goal, rospy.Duration(10.0))
00183 
00184         if not success:
00185           rospy.logerr("Timed out while processing find_container_action")
00186           return []
00187 
00188         result = self._container_client.get_result()
00189         return result.clusters            
00190 
00191 
00192     #call plan_point_cluster_grasp to get candidate grasps for a cluster
00193     def call_plan_point_cluster_grasp(self, cluster, arm_name, reference_frame_id, side = False):
00194 
00195         req = GraspPlanningRequest()
00196         req.target.reference_frame_id = reference_frame_id
00197         req.target.region.cloud = cluster
00198         req.arm_name = arm_name   #not that cluster planner cares right now which arm
00199         try:
00200             res = self._cluster_grasp_srv(req)
00201         except rospy.ServiceException, e:
00202             rospy.logerr("error when calling plan_point_cluster_grasp: %s"%e)  
00203             return 0
00204         if res.error_code.value != 0:
00205             return []
00206         return res.grasps
00207 
00208 
00209     #call the set_point_cluster_grasp_params service with appropriate params
00210     def call_set_point_cluster_grasp_params(self, side = False, pregrasp_just_outside_box = False):
00211         
00212         req = SetPointClusterGraspParamsRequest()
00213         req.height_good_for_side_grasps = 0.02
00214         req.gripper_opening = 0.083
00215         req.side_step = 0.04
00216         req.palm_step = 0.02
00217         if side:
00218             req.side_grasps_only = True
00219             req.overhead_grasps_only = False
00220         else:
00221             req.side_grasps_only = False
00222             req.overhead_grasps_only = True
00223         req.include_high_point_grasps = False
00224         req.pregrasp_just_outside_box = pregrasp_just_outside_box
00225         req.backoff_depth_steps = 1
00226         req.disable_grasp_neighbor_check = True
00227         try:
00228             res = self._cluster_grasp_params_srv(req)
00229         except rospy.ServiceException, e:
00230             rospy.logerr("error when calling set_cluster_grasp_params: %s"%e)  
00231             return 0
00232         return 1
00233 
00234 
00235     #find grasps on a point cloud inside a bounding box
00236     def find_grasps(self, point_cloud, box_pose, box_dims, arm_name, reference_frame_id, opening_dir):
00237         
00238         start_time = time.time()
00239 
00240         #remove container-parallel points and cluster the contents
00241         clusters = self.process_point_cloud(point_cloud, box_pose, box_dims, opening_dir)
00242         if len(clusters) == 0:
00243             return []
00244 
00245         #whether to make the pregrasp just outside the cluster bounding box, or let it be the default (10 cm)
00246         self._pregrasp_just_outside_box = rospy.get_param("~pregrasp_just_outside_box", False)
00247 
00248         #set the params for the point cluster grasp planner
00249         side_opening = False
00250         if opening_dir[2] == 0:
00251             side_opening = True
00252         self.call_set_point_cluster_grasp_params(side_opening, self._pregrasp_just_outside_box)
00253 
00254         #compute grasps on all the clusters in turn
00255         grasp_plan_start_time = time.time()
00256         grasps = []
00257         rospy.loginfo("computing grasps on %d clusters"%len(clusters))
00258         for (ind, cluster) in enumerate(clusters):
00259             cluster_grasps = self.call_plan_point_cluster_grasp(cluster, arm_name, reference_frame_id, side_opening)
00260             grasps.extend(cluster_grasps)
00261             rospy.loginfo("%d grasps from cluster %d"%(len(cluster_grasps), ind))
00262         grasp_plan_end_time = time.time()
00263         rospy.loginfo("total cluster planning time elapsed: %.2f"%(grasp_plan_end_time-grasp_plan_start_time))
00264 
00265         #sort the grasps by quality
00266         sorted(grasps, key=lambda t:t.success_probability, reverse=True)
00267 
00268         #filter out grasps pointing the wrong way
00269         filtered_grasps = [] 
00270         print "%d grasps before filtering"%len(grasps)
00271         start_angles = [0]*7
00272         for grasp in grasps:
00273 
00274             #if side, filter out ones that are pointing the wrong way
00275             if side_opening:                
00276                 grasp_mat = pose_to_mat(grasp.grasp_pose)
00277 
00278                 ### TODO: compare to opening dir
00279                 if grasp_mat[0,0] < 0.7:
00280                     continue
00281 
00282             filtered_grasps.append(grasp)
00283 
00284         end_time = time.time()
00285         print "total grasp planning time elapsed: %.2f"%(end_time - start_time)
00286         print "returning with %d grasps"%len(filtered_grasps)
00287         return filtered_grasps
00288 
00289 
00290 if __name__ == '__main__':
00291     rospy.init_node('segmented_clutter_grasp_planner_server', anonymous=False)
00292 
00293     ccgps = ClusteredClutterGraspPlanner(advertise_service = False, advertise_action = True)
00294     rospy.spin()


segmented_clutter_grasp_planner
Author(s): Kaijen Hsiao
autogenerated on Fri Jan 3 2014 12:08:13