00001
00002
00003 import roslib; roslib.load_manifest('estirabot_apps')
00004 import rospy
00005 import smach
00006 import smach_ros
00007 import tf
00008
00009
00010 import os, sys
00011 _root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
00012 sys.path.insert(0, _root_dir)
00013
00014 from estirabot_common import *
00015 from pomdp_create_model import *
00016
00017 from smach import StateMachine, CBState, Iterator
00018 from smach_ros import ServiceState
00019 from actionlib import *
00020 from actionlib.msg import *
00021 from std_msgs.msg import String
00022 from object_manipulation_msgs.msg import PickupAction,PickupGoal,PlaceAction,PlaceGoal
00023 from sensor_msgs.msg import PointCloud2, JointState
00024 from iri_deformable_analysis.srv import DoDeformableAnalysis, DoDeformableAnalysisRequest
00025 from estirabot_msgs.msg import PomdpGraspConfig
00026 from estirabot_msgs.srv import obs2action, obs2actionRequest
00027 from geometry_msgs.msg import Transform, PoseStamped, Pose
00028 from pprint import pprint
00029 from std_msgs.msg import Int8, Int32
00030
00031 class PlaceHandler():
00032 def __init__(self):
00033 self.next_left_zone = 1
00034 self.next_right_zone = 1
00035
00036 def calculate_place_pose(self, pomdp_config):
00037
00038 if (pomdp_config.place_point == None):
00039 return self.get_basket_pose()
00040
00041 if (pomdp_config.grabbing_zone == pomdp_config.LEFT_ZONE):
00042 return self.get_right_place_pose()
00043 elif (pomdp_config.grabbing_zone == pomdp_config.RIGHT_ZONE):
00044 return self.get_left_place_pose()
00045 else:
00046 rospy.logerr("Value for graspping zone is not LEFT or RIGHT")
00047 return build_home_pose()
00048
00049 def get_basket_pose(self):
00050 return build_pose(-0.165, 0.514, -0.188, 1, 0, 0, 0)
00051
00052 def get_right_place_pose(self):
00053 if (self.next_right_zone == 1):
00054 pose = build_pose(0.422, -0.390, -0.234, 1, 0, 0, 0)
00055 elif (self.next_right_zone == 2):
00056 pose = build_pose(0.584, -0.390, -0.234, 1, 0, 0, 0)
00057 elif (self.next_right_zone == 3):
00058 pose = build_pose(0.633, -0.160, -0.234, 1, 0, 0, 0)
00059 elif (self.next_right_zone == 4):
00060 pose = build_pose(0.476, -0.160, -0.234, 1, 0, 0, 0)
00061 else:
00062 rospy.logerr("Righ pose next zone is out of range: " + str(self.next_right_zone))
00063
00064 self.next_right_zone = self.next_right_zone + 1
00065
00066
00067 if (self.next_right_zone > 4):
00068 self.next_right_zone = 1
00069
00070 return pose
00071
00072 def get_left_place_pose(self):
00073 if (self.next_left_zone == 1):
00074 pose = build_pose(0.422, 0.390, -0.234, 1, 0, 0, 0)
00075 elif (self.next_left_zone == 2):
00076 pose = build_pose(0.584, 0.390, -0.234, 1, 0, 0, 0)
00077 elif (self.next_left_zone == 3):
00078 pose = build_pose(0.633, 0.160, -0.234, 1, 0, 0, 0)
00079 elif (self.next_left_zone == 4):
00080 pose = build_pose(0.476, 0.160, -0.234, 1, 0, 0, 0)
00081 else:
00082 rospy.logerr("Left pose next zone is out of range: " + str(self.next_left_zone))
00083
00084 self.next_left_zone = self.next_left_zone + 1
00085
00086
00087 if (self.next_left_zone > 4):
00088 self.next_left_zone = 1
00089
00090 return pose
00091
00092 def get_config_from_pomdp_action(pomdp_action):
00093
00094 if (pomdp_action > 21):
00095 rospy.logfatal("Pomdp action id out of range: " + str(pomdp_action))
00096
00097 server = PomdpConfigFactory()
00098
00099 if (pomdp_action == 20):
00100 magic_number = 114
00101 elif (pomdp_action == 21):
00102 magic_number = 114
00103 elif (pomdp_action % 10 == 0):
00104 magic_number = 1
00105 elif (pomdp_action % 10 == 1):
00106 magic_number = 3
00107 elif (pomdp_action % 10 == 2):
00108 magic_number = 5
00109 elif (pomdp_action % 10 == 3):
00110 magic_number = 11
00111 elif (pomdp_action % 10 == 4):
00112 magic_number = 14
00113 elif (pomdp_action % 10 == 5):
00114 magic_number = 101
00115 elif (pomdp_action % 10 == 6):
00116 magic_number = 103
00117 elif (pomdp_action % 10 == 7):
00118 magic_number = 105
00119 elif (pomdp_action % 10 == 8):
00120 magic_number = 111
00121 elif (pomdp_action % 10 == 9):
00122 magic_number = 114
00123
00124
00125 config = server.get_instance(magic_number)
00126
00127
00128 if (pomdp_action == 20):
00129 config.grabbing_zone = config.RIGHT_ZONE
00130 elif (pomdp_action == 21):
00131 config.grabbing_zone = config.LEFT_ZONE
00132 elif (pomdp_action > 9):
00133 config.grabbing_zone = config.LEFT_ZONE
00134 else:
00135 config.grabbing_zone = config.RIGHT_ZONE
00136
00137
00138
00139
00140 if (pomdp_action == 20) or (pomdp_action == 21):
00141 config.place_point = None
00142
00143 return config
00144
00145 class FirstAction(smach.State):
00146 def __init__(self):
00147 smach.State.__init__(self, outcomes = ['ok','fail'],
00148 output_keys = ['pomdp_action','place_handler'])
00149
00150 def execute(self, userdata):
00151
00152 request = obs2actionRequest()
00153 request.first = True
00154 handler = rospy.ServiceProxy('/estirabot/skills/planner/obs2action', obs2action)
00155 response = handler(request)
00156
00157 pprint(response)
00158 userdata.pomdp_action = response.action
00159 pub = rospy.Publisher('/log/pomdp/action', Int8, None, False, True)
00160 pub.publish(response.action)
00161
00162 if (not response):
00163 return 'fail'
00164
00165
00166 userdata.place_handler = PlaceHandler()
00167
00168 return 'ok'
00169
00170 class LogPCL(smach.State):
00171 def __init__(self):
00172 smach.State.__init__(self, outcomes=['success','fail'],
00173 input_keys=['sm_pcl_to_log'],
00174 output_keys=[''])
00175
00176 def execute(self, userdata):
00177
00178 pub = rospy.Publisher('/log/pcl_table', PointCloud2, None, False, True)
00179 pub.publish(userdata.sm_pcl_to_log)
00180 return 'success'
00181
00182
00183 class TranslatePomdp(smach.State):
00184 def __init__(self):
00185 smach.State.__init__(self, outcomes = ['fail','image_from_left','image_from_right'],
00186 input_keys = ['pomdp_action','place_handler'],
00187 output_keys = ['sm_pomdp_config','place_handler'])
00188
00189 def execute(self, userdata):
00190
00191 config = get_config_from_pomdp_action(userdata.pomdp_action)
00192 config.place_point = userdata.place_handler.calculate_place_pose(config)
00193
00194 userdata.sm_pomdp_config = config
00195
00196 pub_config = rospy.Publisher('/debug/pomdp_config', PomdpGraspConfig, None, False, True)
00197 pub_config.publish(config)
00198 pprint(config)
00199
00200 if (config.grabbing_zone == config.LEFT_ZONE):
00201 return 'image_from_left'
00202 else:
00203 return 'image_from_right'
00204
00205 class CountObjects(smach.State):
00206 def __init__(self):
00207 smach.State.__init__(self, outcomes = ['fail','success'],
00208 input_keys = ['sm_pcl_table_left','sm_pcl_table_right'],
00209 output_keys = ['left_objects','right_objects'])
00210 self.number = -1
00211
00212 sub = rospy.Subscriber("/estirabot/skills/iri_textile_count/num_objects_found",
00213 Int32, self.recieve_number)
00214
00215 def execute(self, userdata):
00216
00217 self.calculate_objects(userdata.sm_pcl_table_left)
00218 userdata.left_objects = self.number
00219 pprint ("Left objects: " + str(self.number))
00220 pub = rospy.Publisher('/debug/observation/left_objects', Int8, None, False, True)
00221 pub.publish(self.number)
00222
00223 rospy.sleep(2)
00224
00225
00226 self.calculate_objects(userdata.sm_pcl_table_right)
00227 userdata.right_objects = self.number
00228 pprint ("Right objects: " + str(self.number))
00229 pub = rospy.Publisher('/debug/observation/right_objects', Int8, None, False, True)
00230 pub.publish(self.number)
00231
00232 return 'success'
00233
00234 def recieve_number(self, data):
00235 self.number = data.data
00236
00237 def calculate_objects(self, pcl):
00238 self.number = -1
00239
00240 pub = rospy.Publisher('/estirabot/skills/table/pcl', PointCloud2, None, False, True)
00241 pub.publish(pcl)
00242
00243 while (self.number == -1 and (not rospy.is_shutdown())):
00244 pprint("waiting")
00245 time.sleep(.1)
00246
00247 class PrePlace(smach.State):
00248 def __init__(self):
00249 smach.State.__init__(self, outcomes = ['fail','success'],
00250 input_keys = ['sm_pomdp_config'])
00251
00252 def execute(self, userdata):
00253 tf = Transform()
00254 tf.translation.z = -0.4
00255
00256 return wam_cartesian_move(homogeneous_product_pose_transform(userdata.sm_pomdp_config.place_point,
00257 tf))
00258
00259
00260 class UpdateBelieve(smach.State):
00261 def __init__(self):
00262 smach.State.__init__(self, outcomes = ['fail','finish','continue'],
00263 input_keys = ['left_objects','right_objects'],
00264 output_keys = ['pomdp_action'])
00265
00266 def execute(self, userdata):
00267 request = obs2actionRequest()
00268
00269 right_objs = userdata.right_objects
00270 left_objs = userdata.left_objects
00271
00272 if (right_objs > 3):
00273 right_objs = 4
00274
00275 if (left_objs > 4):
00276 left_objs = 4
00277
00278 request.first = False
00279 request.observation = right_objs * 5 + left_objs
00280 pub = rospy.Publisher('/log/pomdp/observation', Int8, None, False, True)
00281 pub.publish(request.observation)
00282
00283 pprint(request)
00284 handler = rospy.ServiceProxy('/estirabot/skills/planner/obs2action', obs2action)
00285 response = handler(request)
00286
00287 if (not response):
00288 return 'fail'
00289
00290 pprint(response)
00291 if (response.goal_reached == True):
00292 return 'finish'
00293
00294 userdata.pomdp_action = response.action
00295 pub = rospy.Publisher('/log/pomdp/action', Int8, None, False, True)
00296 pub.publish(response.action)
00297
00298 return 'continue'
00299
00300
00301 def construct_main_sm():
00302 sm = StateMachine(outcomes = ['succeeded','aborted'])
00303
00304 with sm:
00305 smach.StateMachine.add('GIVE_FIRST_ACTION', FirstAction(),
00306 transitions = { 'ok':'START_ROUND',
00307 'fail':'aborted'},
00308 remapping = { 'pomdp_action' : 'pomdp_action'})
00309
00310 smach.StateMachine.add('START_ROUND', EstirabotGoHome(),
00311 transitions={'success': 'LOG_PCL',
00312 'fail' : 'aborted'})
00313 smach.StateMachine.add('LOG_PCL',
00314 EstirabotGetPCL("/estirabot/ceiling_kinect/camera/rgb/points"),
00315 transitions = {'success' : 'LOG_IMAGE',
00316 'fail' : 'aborted'},
00317 remapping = {'pcl_RGB' : 'sm_pcl_to_log'})
00318 smach.StateMachine.add('LOG_IMAGE', LogPCL(),
00319 transitions={'success': 'TRANSLATE_POMDP_ACTION',
00320 'fail' : 'aborted'})
00321
00322
00323 smach.StateMachine.add('TRANSLATE_POMDP_ACTION', TranslatePomdp(),
00324 transitions = { 'image_from_left' : 'GET_KINECT_IMAGE_FROM_LEFT',
00325 'image_from_right' : 'GET_KINECT_IMAGE_FROM_RIGHT',
00326 'fail':'aborted'},
00327 remapping = { 'sm_pomdp_config' : 'sm_pomdp_config'})
00328
00329
00330
00331 smach.StateMachine.add('GET_KINECT_IMAGE_FROM_LEFT',
00332 EstirabotGetPCL("/estirabot/skills/table/left/pcl"),
00333 transitions = {'success' : 'PERFORM_ANALISYS',
00334 'fail' : 'aborted'},
00335 remapping = {'pcl_RGB' : 'sm_pcl_output'})
00336
00337
00338 smach.StateMachine.add('GET_KINECT_IMAGE_FROM_RIGHT',
00339 EstirabotGetPCL("/estirabot/skills/table/right/pcl"),
00340 transitions = {'success' : 'PERFORM_ANALISYS',
00341 'fail' : 'aborted'},
00342 remapping = {'pcl_RGB' : 'sm_pcl_output'})
00343
00344
00345 smach.StateMachine.add('PERFORM_ANALISYS', PerformAnalysis(),
00346 transitions = {'success' : 'CALCULATE_GRASP',
00347 'timeout' : 'PERFORM_ANALISYS',
00348 'fail' : 'aborted'},
00349 remapping = {'pcl_RGB' : 'sm_pcl_output',
00350 'best_grasp_pose' : 'sm_best_grasp_pose'})
00351
00352 smach.StateMachine.add('CALCULATE_GRASP', CalculateGrasp(),
00353 transitions = {'success' : 'DO_GRASP',
00354 'no_ik_solution' : 'CALCULATE_GRASP',
00355 'fail' : 'aborted',
00356 'all_ik_fail' : 'GET_TABLE_IMAGE_FROM_LEFT'},
00357 remapping = {'pcl_RGB' : 'sm_pcl_output',
00358 'best_grasp_pose' : 'sm_best_grasp_pose',
00359 'grasp_goal' : 'sm_grasp_goal'})
00360
00361 smach.StateMachine.add('DO_GRASP',
00362 smach_ros.SimpleActionState('/estirabot/skills/grasp/pickup',
00363 PickupAction,
00364 goal_cb = get_sm_grasp_goal_callback,
00365 input_keys=['sm_grasp_goal']),
00366 {'succeeded': 'DO_LIFT',
00367 'preempted': 'aborted',
00368 'aborted' : 'aborted'})
00369
00370 smach.StateMachine.add('DO_LIFT', EstirabotGoHome(),
00371 transitions={'success' : 'DO_PRE_PLACE',
00372 'fail' : 'aborted'})
00373
00374 smach.StateMachine.add('DO_PRE_PLACE', PrePlace(),
00375 transitions={'success' : 'DO_PLACE',
00376 'fail' : 'aborted'})
00377
00378
00379 smach.StateMachine.add('DO_PLACE',
00380 smach_ros.SimpleActionState('/estirabot/skills/iri_place/place',
00381 PlaceAction,
00382 goal_cb = get_sm_place_goal_callback,
00383 input_keys=['sm_pomdp_config']),
00384 {'succeeded': 'BACK_TO_HOME',
00385 'preempted': 'aborted',
00386 'aborted' : 'aborted'})
00387
00388 smach.StateMachine.add('BACK_TO_HOME', EstirabotGoHome(),
00389 transitions={'success': 'GET_TABLE_IMAGE_FROM_LEFT',
00390 'fail' : 'aborted'})
00391
00392
00393
00394
00395 smach.StateMachine.add('GET_TABLE_IMAGE_FROM_LEFT',
00396 EstirabotGetPCL("/estirabot/skills/table/left/pcl"),
00397 transitions = {'success' : 'GET_TABLE_IMAGE_FROM_RIGHT',
00398 'fail' : 'aborted'},
00399 remapping = {'pcl_RGB' : 'sm_pcl_table_left'})
00400
00401 smach.StateMachine.add('GET_TABLE_IMAGE_FROM_RIGHT',
00402 EstirabotGetPCL("/estirabot/skills/table/right/pcl"),
00403 transitions = {'success' : 'COUNT_OBJECTS',
00404 'fail' : 'aborted'},
00405 remapping = {'pcl_RGB' : 'sm_pcl_table_right'})
00406
00407 smach.StateMachine.add('COUNT_OBJECTS', CountObjects(),
00408 transitions={'success' : 'UPDATE_BELIEVE_STATE',
00409 'fail' : 'aborted'})
00410
00411 smach.StateMachine.add('UPDATE_BELIEVE_STATE', UpdateBelieve(),
00412 transitions={'continue' : 'START_ROUND',
00413 'finish' : 'succeeded',
00414 'fail' : 'aborted'})
00415
00416 return sm
00417
00418 def main():
00419 rospy.init_node("pomdp_sm")
00420 sm_main = construct_main_sm()
00421
00422
00423 sis = smach_ros.IntrospectionServer('estirabot_smach_replicable', sm_main,
00424 '/estirabot_smach_replicable')
00425
00426 sis.start()
00427
00428 outcome = sm_main.execute()
00429
00430 rospy.spin()
00431 sis.stop()
00432
00433 if __name__ == "__main__":
00434 main()