pomdp_execution.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import roslib; roslib.load_manifest('estirabot_apps')
00004 import rospy
00005 import smach
00006 import smach_ros
00007 import tf
00008 
00009 # Import the parent directory for common
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         # If place_point is None it implies special basket
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         # reset to 1 again
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         # reset to 1 again
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     # From magic number get configuration
00125     config = server.get_instance(magic_number)
00126 
00127     # Also set the grabbing zone
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     # 20 and 21 should get an special value for place.
00138     # Hack for this is set place_point to None and check for it
00139     # in PlaceHandler. Dirty as hell.
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         # Config and launch the deformable analysis
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         # Create the place handler
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         # Log the PCL
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         # Stupid trick to not declare sm_pomdp_config as input (SMACH goodies)
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         # Subscribe to count numbers
00212         sub = rospy.Subscriber("/estirabot/skills/iri_textile_count/num_objects_found",
00213                                Int32, self.recieve_number)
00214 
00215     def execute(self, userdata):
00216         # Left objects
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         # Right objects
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         # Publish the pcl in /estirabot/skills/table/pcl
00240         pub = rospy.Publisher('/estirabot/skills/table/pcl', PointCloud2, None, False, True)
00241         pub.publish(pcl)
00242         # Wait to recieve the callback
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         # Build observation
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         # 2. CALCULATE GRASP POINT
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         # 2.1.a GET KINECT IMAGE FROM LEFT
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         # 2.1.b GET KINECT IMAGE FROM RIGHT
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         # 2.2 ANALYSIS
00345         smach.StateMachine.add('PERFORM_ANALISYS', PerformAnalysis(),
00346                 transitions = {'success'        : 'CALCULATE_GRASP',
00347                                'timeout'        : 'PERFORM_ANALISYS', # hack relaunch since descriptors died
00348                                'fail'           : 'aborted'},
00349                 remapping   = {'pcl_RGB'         : 'sm_pcl_output',
00350                                'best_grasp_pose' : 'sm_best_grasp_pose'})
00351         # 2.3 CALCULATE GRASP
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         # 3.1 GRASP
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         # 3.2 LIFT
00370         smach.StateMachine.add('DO_LIFT', EstirabotGoHome(),
00371                         transitions={'success' : 'DO_PRE_PLACE',
00372                                      'fail'    : 'aborted'})
00373         # 3.3.1 DO PRE PLACE
00374         smach.StateMachine.add('DO_PRE_PLACE', PrePlace(),
00375                         transitions={'success' : 'DO_PLACE',
00376                                      'fail'    : 'aborted'})
00377         #
00378         # 3.3.2 DO PLACE
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         # 4. OBSERVATION
00394         # 4.1 GET PCL FROM LEFT
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         # 4.2 GET PCL FROM RIGHT
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         # 4.3 GET NUMBER OF OBJECTS
00407         smach.StateMachine.add('COUNT_OBJECTS', CountObjects(),
00408                         transitions={'success' : 'UPDATE_BELIEVE_STATE',
00409                                      'fail'    : 'aborted'})
00410         # 5 UPDATE BELIEVE STATE
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     # Run state machine introspection server for smach viewer
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()


estirabot_apps
Author(s): Jose Luis Rivero
autogenerated on Fri Dec 6 2013 23:20:59