find_free_space.py
Go to the documentation of this file.
00001 #!/usr/bin/env python 
00002 #find_free_space.py
00003 '''
00004 Functions for finding free space on a table.
00005 '''
00006 
00007 from __future__ import division
00008 
00009 __docformat__ = "restructuredtext en"
00010 
00011 
00012 import roslib
00013 roslib.load_manifest('pr2_python')
00014 import rospy
00015 import random
00016 import pr2_python.geometry_tools as gt
00017 import pr2_python.transform_listener as tl
00018 from geometry_msgs.msg import Point, PointStamped, Pose, PoseStamped, Quaternion
00019 from pr2_python.point_on_table import point_on_table
00020 import copy
00021 import pr2_python.visualization_tools as vt
00022 from visualization_msgs.msg import MarkerArray, Marker
00023 import tf
00024 import numpy as np
00025 
00026 NUM_TRIES = 100
00027 
00028 ############################################################
00029 # External API
00030 ############################################################
00031 
00032 vpub = rospy.Publisher('free_space_markers', MarkerArray)
00033 marray = MarkerArray()
00034 
00035 def free_spots_on_table(table, obj, orientation, blocking_objs, res=0.1, orientation_count=10, blocking_padding=0.05):
00036 
00037     object_pose = Pose()
00038     object_pose.orientation = orientation
00039     _, _, base_yaw = tf.transformations.euler_from_quaternion([orientation.x, orientation.y, orientation.z, orientation.w])
00040 
00041     #these are the corners of the object in the object's frame
00042     object_frame_corners = gt.bounding_box_corners(obj.shapes[0])
00043     #rospy.loginfo('Corners are')
00044     #for c in object_frame_corners: rospy.loginfo(str(c))
00045     #these are the corners after we apply the rotation
00046     header_frame_corners = [gt.transform_list(c, object_pose) for c in object_frame_corners]
00047     #these are the corners relative to the table's lower left corner
00048     table_frame_corners = [gt.inverse_transform_list(c, table.poses[0]) for c in header_frame_corners]
00049     #the footprint of the object above the table
00050     oxmax = max([c[0] for c in table_frame_corners])
00051     oxmin = min([c[0] for c in table_frame_corners])
00052     oymax = max([c[1] for c in table_frame_corners])
00053     oymin = min([c[1] for c in table_frame_corners])
00054     object_dims = (oxmax - oxmin, oymax - oymin)
00055     #rospy.loginfo('Object dimensions are '+str(object_dims))
00056     obj_poses = free_spots_from_dimensions(table, object_dims, blocking_objs, res=res, blocking_padding=blocking_padding)
00057     #return these as proper object poses with the object sitting on the table
00058     #the height of the object in the world in its place orientation
00059     obj_height = -1.0*min([c[2] for c in header_frame_corners])
00060     above_table = gt.transform_list([0, 0, obj_height], table.poses[0])
00061     place_height = above_table[2]
00062     orientated_poses = []
00063     angle_increment = np.pi*2.0 / orientation_count
00064     for pose in obj_poses:
00065         pose.pose.position.z = place_height
00066         pose.pose.orientation = copy.deepcopy(orientation)
00067         for dyaw in range(orientation_count):
00068             ori_pose = PoseStamped()
00069             ori_pose.header = pose.header
00070             ori_pose.pose.position = pose.pose.position
00071             ori_pose.pose.orientation = Quaternion()
00072             quat = tf.transformations.quaternion_from_euler(0, 0, base_yaw + angle_increment*float(dyaw))
00073             ori_pose.pose.orientation.x = quat[0]
00074             ori_pose.pose.orientation.y = quat[1]
00075             ori_pose.pose.orientation.z = quat[2]
00076             ori_pose.pose.orientation.w = quat[3]
00077             orientated_poses.append(ori_pose)
00078     return orientated_poses
00079 
00080 def free_spots_from_dimensions(table, object_dims, blocking_objs, res=0.1, blocking_padding=0.05):
00081     '''
00082     Currently works only with a single shape
00083 
00084     Assumes table is in xy plane
00085     '''
00086     #find the lower left corner of the table in the header frame
00087     #we want everything relative to this point
00088     table_corners = gt.bounding_box_corners(table.shapes[0])
00089     lower_left = Pose()
00090     lower_left.position = gt.list_to_point(table_corners[1])
00091     lower_left.orientation.w = 1.0
00092     #rospy.loginfo('Table corners are:')
00093     #for c in table_corners: rospy.loginfo('\n'+str(c))
00094     #rospy.loginfo('Lower left =\n'+str(lower_left))
00095     #rospy.loginfo('Table header =\n'+str(table.header))
00096     #rospy.loginfo('Table pose =\n'+str(table.poses[0]))
00097     #this is the position of the minimum x, minimum y point in the table's header frame
00098     table_box_origin = gt.transform_pose(lower_left, table.poses[0])
00099     tr = gt.inverse_transform_list(gt.transform_list(table_corners[-1], table.poses[0]), table_box_origin)
00100     table_dims = (tr[0], tr[1])
00101     tbos = PoseStamped()
00102     tbos.header = table.header
00103     tbos.pose = table_box_origin
00104     marray.markers.append(vt.marker_at(tbos, ns='table_origin', mtype=Marker.CUBE, r=1.0))
00105     max_box = PointStamped()
00106     max_box.header = table.header
00107     max_box.point = gt.list_to_point(gt.transform_list([table_dims[0], table_dims[1], 0], table_box_origin)) 
00108     marray.markers.append(vt.marker_at_point(max_box, ns='table_max', mtype=Marker.CUBE, r=1.0))
00109 
00110     #rospy.loginfo('Table box origin is '+str(table_box_origin)+' dimensions are '+str(table_dims))
00111 
00112                 
00113     locs_on_table =  _get_feasible_locs(table_dims, object_dims, res)
00114     for i, l in enumerate(locs_on_table):
00115         pt = Point()
00116         pt.x = l[0]
00117         pt.y = l[1]
00118         mpt = PointStamped()
00119         mpt.header = table.header
00120         mpt.point = gt.transform_point(pt, table_box_origin)
00121         marray.markers.append(vt.marker_at_point(mpt, mid=i, ns='locations', r=1.0, g=1.0, b=0.0))
00122 
00123     feasible_locs = []
00124     #check that these points really are on the table
00125     for i, l in enumerate(locs_on_table):
00126         pt = Point()
00127         pt.x = l[0]
00128         pt.y = l[1]
00129         #this point is now defined relative to the origin of the table (rather than its minimum x, minimum y point)
00130         table_pt = gt.inverse_transform_point(gt.transform_point(pt, table_box_origin), table.poses[0])
00131         if table.shapes[0].type == table.shapes[0].BOX or point_on_table(table_pt, table.shapes[0]):
00132             feasible_locs.append(l)
00133             marray.markers[i+2].color.r = 0.0
00134             marray.markers[i+2].color.b = 1.0
00135     rospy.loginfo('Testing '+str(len(feasible_locs))+' locations')
00136 #    if not feasible_locs:
00137 #        return feasible_locs
00138 
00139     forbidden=[]
00140     for i, o in enumerate(blocking_objs):
00141         # add padding blocking objects, to avoid putting down to close and failing on subsequent object detections
00142         ofcs = gt.bounding_box_corners(o.shapes[0])
00143         for corner in ofcs:
00144           for x, dimension in enumerate(corner):
00145             if dimension > 0:
00146               corner[x] += blocking_padding
00147             else:
00148               corner[x] -= blocking_padding
00149         objpose = tl.transform_pose(table.header.frame_id, o.header.frame_id, o.poses[0])
00150         hfcs = [gt.transform_list(c, objpose) for c in ofcs]
00151         tfcs = [gt.inverse_transform_list(c, table_box_origin) for c in hfcs]
00152         oxmax = max([c[0] for c in tfcs])
00153         oxmin = min([c[0] for c in tfcs])
00154         oymax = max([c[1] for c in tfcs])
00155         oymin = min([c[1] for c in tfcs])
00156         forbidden.append(((oxmin, oymin), (oxmax - oxmin, oymax - oymin)))
00157         #rospy.loginfo('\n'+str(forbidden[-1]))
00158         ps = PoseStamped()
00159         ps.header = table.header
00160         ps.pose = objpose
00161         
00162 #        ps = PoseStamped()
00163 #        ps.header = table.header
00164 #        ps.pose.position = gt.list_to_point(gt.transform_list([oxmin, oymin, 0], table_box_origin))
00165 #        ps.pose.orientation.w = 1.0
00166 #        marray.markers.append(vt.marker_at(ps, ns='forbidden0', mid=i, mtype=Marker.CUBE, sx=0.01, sy=0.01, sz=0.01, r=1.0, b=0.0))
00167 #        
00168 #        ps = PoseStamped()
00169 #        ps.header = table.header
00170 #        ps.pose.position = gt.list_to_point(gt.transform_list([oxmin, oymax, 0], table_box_origin))
00171 #        ps.pose.orientation.w = 1.0
00172 #        marray.markers.append(vt.marker_at(ps, ns='forbidden1', mid=i, mtype=Marker.CUBE, sx=0.01, sy=0.01, sz=0.01, r=1.0, b=0.0))
00173 #        
00174 #        ps = PoseStamped()
00175 #        ps.header = table.header
00176 #        ps.pose.position = gt.list_to_point(gt.transform_list([oxmax, oymax, 0], table_box_origin))
00177 #        ps.pose.orientation.w = 1.0
00178 #        marray.markers.append(vt.marker_at(ps, ns='forbidden2', mid=i, mtype=Marker.CUBE, sx=0.01, sy=0.01, sz=0.01, r=1.0, b=0.0))
00179 #        
00180 #        ps = PoseStamped()
00181 #        ps.header = table.header
00182 #        ps.pose.position = gt.list_to_point(gt.transform_list([oxmax, oymin, 0], table_box_origin))
00183 #        ps.pose.orientation.w = 1.0
00184 #        marray.markers.append(vt.marker_at(ps, ns='forbidden3', mid=i, mtype=Marker.CUBE, sx=0.01, sy=0.01, sz=0.01, r=1.0, b=0.0))
00185         
00186 
00187     # Remove forbidden rectangles
00188     for (bottom_left, dims) in forbidden:
00189         _remove_feasible_locs(feasible_locs, object_dims,
00190                               bottom_left,
00191                               _add(bottom_left, dims),
00192                               res)
00193     rospy.loginfo('There are '+str(len(feasible_locs))+' possible locations')
00194     obj_poses = []
00195     for i, fl in enumerate(feasible_locs):
00196         table_frame_pose = Pose()
00197         table_frame_pose.position.x = fl[0] + object_dims[0]/2.0
00198         table_frame_pose.position.y = fl[1] + object_dims[1]/2.0
00199         table_frame_pose.orientation.w = 1.0
00200         pose = PoseStamped()
00201         pose.header = copy.deepcopy(table.header)
00202         pose.pose = gt.transform_pose(table_frame_pose, table_box_origin)
00203         obj_poses.append(pose)
00204         pt = PointStamped()
00205         pt.header = table.header
00206         pt.point = pose.pose.position
00207         marray.markers.append(vt.marker_at_point(pt, mid=i, ns='final_locations', g=1.0, b=0.0))
00208 
00209     #rospy.loginfo('Object poses are:')
00210     #for op in obj_poses: rospy.loginfo(str(op))
00211     for i in range(10):
00212         vpub.publish(marray)
00213         rospy.sleep(0.1)
00214     return obj_poses
00215 
00216 def free_spots(table, objects, res=0.1, forbidden=[]):
00217     """
00218     Find free spots on a table
00219 
00220     @param table: Dimensions of table
00221     @type table: Tuple (x, y)
00222     @param objects: Object dimensions
00223     @type objects: List of tuples of form (x, y)
00224     @param res: Resolution
00225     @type res: Positive float 
00226     @param forbidden: Forbidden rectangles
00227     @type forbidden: List of tuples ((x0, y0), (x_size, y_size)) where (x0, y0) is the bottom left.
00228     @return: list of positions of (lower left corners of) objects, or None
00229     """
00230     feasible_locs = {}
00231     for i, o in enumerate(objects):
00232         feasible_locs[i] = _get_feasible_locs(table, o, res)
00233     locs = {}
00234 
00235     # Remove forbidden rectangles
00236     for (bottom_left, dims) in forbidden:
00237         for i, o in enumerate(objects):
00238             _remove_feasible_locs(feasible_locs[i], o,
00239                                  bottom_left,
00240                                  _add(bottom_left, dims),
00241                                  res)
00242                                  
00243     # Place the objects one by one
00244     for i, o in enumerate(objects):
00245         if len(feasible_locs[i])==0:
00246             rospy.logdebug("No feasible locs for object {0}".format(i))
00247             return None
00248         locs[i] = random.sample(feasible_locs[i], 1)[0]
00249         rospy.logdebug("Trying {0} for object {1}".format(locs[i], i))
00250         for j in range(i+1, len(objects)):
00251             _remove_feasible_locs(feasible_locs[j], objects[j], locs[i],
00252                                  _add(locs[i], objects[i]), res)
00253     return locs
00254 
00255 
00256 ############################################################
00257 # Internal
00258 ############################################################
00259 
00260 def _get_feasible_locs(table, o, res):
00261     locs = set()
00262     rx = int((table[0]-o[0])/res)+1
00263     for x in range(rx):
00264         for y in range(int((table[1]-o[1])/res)+1):
00265              locs.add((x*res,y*res))
00266     return locs
00267 
00268 def _remove_feasible_locs(locs, o, bottom_left, top_right, res):
00269 
00270     xmin = bottom_left[0] - o[0]
00271     xmax = top_right[0]
00272     ymin = bottom_left[1] - o[1]
00273     ymax = top_right[1]
00274     remove = []
00275     for l in locs:
00276         if l[0] > xmin and l[0] < xmax and l[1] > ymin and l[1] < ymax:
00277             remove.append(l)
00278     for r in remove:
00279         locs.remove(r)
00280 
00281 def _add(v1, v2):
00282     return [x+y for (x,y) in zip(v1, v2)]
00283 
00284 def _tuplize(vec2d):
00285     return (vec2d.x, vec2d.y)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


tidyup_arm_services
Author(s): Andreas Hertle, Christian Dornhege
autogenerated on Wed Dec 26 2012 15:48:37