00001
00002
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
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
00042 object_frame_corners = gt.bounding_box_corners(obj.shapes[0])
00043
00044
00045
00046 header_frame_corners = [gt.transform_list(c, object_pose) for c in object_frame_corners]
00047
00048 table_frame_corners = [gt.inverse_transform_list(c, table.poses[0]) for c in header_frame_corners]
00049
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
00056 obj_poses = free_spots_from_dimensions(table, object_dims, blocking_objs, res=res, blocking_padding=blocking_padding)
00057
00058
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
00087
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
00093
00094
00095
00096
00097
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
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
00125 for i, l in enumerate(locs_on_table):
00126 pt = Point()
00127 pt.x = l[0]
00128 pt.y = l[1]
00129
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
00137
00138
00139 forbidden=[]
00140 for i, o in enumerate(blocking_objs):
00141
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
00158 ps = PoseStamped()
00159 ps.header = table.header
00160 ps.pose = objpose
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
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
00210
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
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
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
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)