00001
00002 import roslib
00003 roslib.load_manifest('pr2_approach_table')
00004 roslib.load_manifest('rfid_behaviors')
00005 import rospy
00006
00007 import tf
00008 import tf.transformations as tft
00009 import smach
00010 from smach_ros import SimpleActionState, ServiceState, IntrospectionServer
00011 import actionlib
00012 from geometry_msgs.msg import PoseStamped, PoseArray, Pose, Quaternion
00013 from move_base_msgs.msg import MoveBaseAction
00014
00015 from pr2_approach_table.srv import ApproachSrv
00016 from pr2_approach_table.msg import ApproachAction, ApproachResult, ApproachGoal
00017 from rfid_behaviors.srv import FloatFloat_Int32 as RotateBackupSrv
00018
00019 import numpy as np, math
00020
00021 class CheckHeading(smach.State):
00022 def __init__(self, listener):
00023 smach.State.__init__(self,
00024 outcomes=['succeeded', 'preempted'],
00025 input_keys = ['target_pose'],
00026 output_keys = ['angular_error'])
00027 self.listener = listener
00028 self.initialized = False
00029
00030 def execute(self, userdata):
00031 ps_desired = userdata.target_pose
00032 self.GLOBAL_FRAME = ps_desired.header.frame_id
00033
00034 if not self.initialized:
00035 self.initialized = True
00036
00037 rospy.logout( 'CheckHeading (smach): Waiting on transforms from (%s -> %s)'
00038 % ( self.GLOBAL_FRAME, '/base_link' ))
00039 self.listener.waitForTransform( '/base_link',
00040 self.GLOBAL_FRAME,
00041 rospy.Time(0), timeout = rospy.Duration(30) )
00042 rospy.logout( 'CheckHeading (smach): Ready.' )
00043
00044 try:
00045 ps = PoseStamped()
00046 ps.header.stamp = rospy.Time(0)
00047 ps.header.frame_id = '/base_link'
00048 ps.pose.orientation.w = 1.0
00049
00050 ps_global = self.listener.transformPose( self.GLOBAL_FRAME, ps )
00051 efq = tft.euler_from_quaternion
00052 r,p,yaw_curr = efq(( ps_global.pose.orientation.x,
00053 ps_global.pose.orientation.y,
00054 ps_global.pose.orientation.z,
00055 ps_global.pose.orientation.w ))
00056 r,p,yaw_des = efq(( ps_desired.pose.orientation.x,
00057 ps_desired.pose.orientation.y,
00058 ps_desired.pose.orientation.z,
00059 ps_desired.pose.orientation.w ))
00060
00061 rospy.logout( 'CheckHeading (smach): Error was %3.2f (deg)' % math.degrees(yaw_des - yaw_curr))
00062 userdata.angular_error = yaw_des - yaw_curr
00063 except:
00064 rospy.logout( 'CheckHeading (smach): TF failed. Returning ang error of 0.0' )
00065 userdata.angular_error = 0.0
00066 return 'succeeded'
00067
00068
00069 class PoseSelection(smach.State):
00070 def __init__(self, listener):
00071 smach.State.__init__(self,
00072 outcomes=['succeeded', 'aborted'],
00073 input_keys=['candidate_poses'],
00074 output_keys=['selected_pose_global',
00075 'movebase_pose_global' ])
00076 self.listener = listener
00077 self.poses = []
00078 self.initialized = False
00079 self.ind = 0
00080
00081 self.GLOBAL_FRAME = '/map'
00082
00083 def execute(self, userdata):
00084 rospy.logout( 'Executing POSE_SELECTION' )
00085
00086 poses_frame = userdata.candidate_poses.header.frame_id
00087
00088 dist = 0.80
00089
00090 if not self.initialized:
00091 self.initialized = True
00092 self.ind = 0
00093
00094 rospy.logout( 'PoseSelector (smach): Waiting on transforms from (%s -> %s)'
00095 % ( self.GLOBAL_FRAME, poses_frame ))
00096 self.listener.waitForTransform( poses_frame,
00097 self.GLOBAL_FRAME,
00098 rospy.Time(0), timeout = rospy.Duration(30) )
00099 rospy.logout( 'PoseSelector (smach): Ready.' )
00100
00101
00102
00103 frame_adjusted = [ self.frame_adjust(i,poses_frame,dist) for i in userdata.candidate_poses.poses ]
00104 self.poses = [ i for i in frame_adjusted if i != None ]
00105
00106 if len( self.poses ) == 0 or self.ind >= len( self.poses ):
00107 return 'aborted'
00108
00109
00110 userdata.selected_pose_global = self.poses[ self.ind ][0]
00111 userdata.movebase_pose_global = self.poses[ self.ind ][1]
00112
00113 self.ind += 1
00114 return 'succeeded'
00115
00116 def frame_adjust( self, pose, poses_frame, dist, arm_offset = 0.0 ):
00117
00118
00119 ps = PoseStamped()
00120 ps.header.frame_id = poses_frame
00121 ps.header.stamp = rospy.Time(0)
00122 ps.pose = pose
00123
00124
00125
00126 efq = tft.euler_from_quaternion
00127 r,p,y = efq(( pose.orientation.x,
00128 pose.orientation.y,
00129 pose.orientation.z,
00130 pose.orientation.w ))
00131 ps.pose.position.x = pose.position.x + arm_offset * np.cos( y + np.pi/2 )
00132 ps.pose.position.y = pose.position.y + arm_offset * np.sin( y + np.pi/2 )
00133
00134
00135
00136 try:
00137 ps_global = self.listener.transformPose( self.GLOBAL_FRAME, ps )
00138 ps_global.pose.position.z = 0.0
00139
00140
00141 r,p,y = efq(( ps_global.pose.orientation.x,
00142 ps_global.pose.orientation.y,
00143 ps_global.pose.orientation.z,
00144 ps_global.pose.orientation.w ))
00145
00146
00147 mps = PoseStamped()
00148 mps.header.frame_id = ps_global.header.frame_id
00149 mps.header.stamp = rospy.Time.now()
00150 mps.pose.position.x = ps_global.pose.position.x + dist * np.cos( y )
00151 mps.pose.position.y = ps_global.pose.position.y + dist * np.sin( y )
00152 qfe = tft.quaternion_from_euler
00153 mps.pose.orientation = Quaternion( *qfe( 0.0, 0.0, y - np.pi ))
00154
00155
00156
00157 rv = [ ps_global, mps ]
00158
00159 except:
00160 rospy.logout( 'PoseSelector (smach): TF failed. Ignoring pose.' )
00161 rv = None
00162
00163 return rv
00164
00165
00166
00167 def sm_approach_table( listener = None ):
00168
00169
00170 if listener == None:
00171 try:
00172 rospy.init_node( 'sm_approach' )
00173 except:
00174 rospy.logout( 'sm_approach_table: Node already initialized elsewhere' )
00175
00176 listener = tf.TransformListener()
00177
00178
00179
00180
00181
00182
00183 sm = smach.StateMachine( outcomes = ['succeeded','aborted','preempted'],
00184 input_keys = ['table_edge_poses'],
00185 output_keys = ['movebase_pose_global',
00186 'table_edge_global'])
00187
00188
00189 with sm:
00190 smach.StateMachine.add(
00191 'POSE_SELECTION',
00192 PoseSelection( listener = listener ),
00193 transitions = { 'succeeded' : 'MOVE_BASE' },
00194 remapping = {'candidate_poses':'table_edge_poses',
00195 'selected_pose_global':'table_edge_global',
00196 'movebase_pose_global':'movebase_pose_global'})
00197
00198
00199 smach.StateMachine.add(
00200 'MOVE_BASE',
00201 SimpleActionState( '/move_base',
00202 MoveBaseAction,
00203 goal_slots = ['target_pose'],
00204 outcomes = ['succeeded','aborted','preempted']),
00205 transitions = { 'succeeded' : 'CHECK_HEADING',
00206 'aborted' : 'POSE_SELECTION' },
00207 remapping = {'target_pose':'movebase_pose_global'})
00208
00209 smach.StateMachine.add(
00210 'CHECK_HEADING',
00211 CheckHeading( listener = listener ),
00212 transitions = { 'succeeded':'ADJUST_HEADING' },
00213 remapping = { 'target_pose':'movebase_pose_global',
00214 'angular_error':'angular_error' })
00215
00216 smach.StateMachine.add(
00217 'ADJUST_HEADING',
00218 ServiceState( '/rotate_backup',
00219 RotateBackupSrv,
00220 request_slots = ['rotate']),
00221 transitions = { 'succeeded':'MOVE_FORWARD' },
00222 remapping = {'rotate':'angular_error'})
00223
00224
00225 approach_goal = ApproachGoal()
00226 approach_goal.forward_vel = 0.05
00227 approach_goal.forward_mult = 0.50
00228 smach.StateMachine.add(
00229 'MOVE_FORWARD',
00230 SimpleActionState( '/approach_table/move_forward_act',
00231 ApproachAction,
00232 goal = approach_goal ),
00233 transitions = { 'succeeded' : 'succeeded' })
00234
00235 return sm
00236
00237
00238
00239
00240 if __name__ == '__main__':
00241 rospy.init_node('smach_example_state_machine')
00242
00243
00244
00245 sm = smach.StateMachine(outcomes=['succeeded','aborted','preempted'],
00246 input_keys = [ 'approach_poses' ])
00247
00248 p = Pose()
00249 p.position.x = 0.3879
00250 p.position.y = 0.79838
00251 p.position.z = 0.0
00252
00253 p.orientation.z = -0.704
00254 p.orientation.w = 0.709
00255
00256 pa = PoseArray()
00257 pa.header.frame_id = '/map'
00258 pa.poses = [ p ]
00259
00260 sm.userdata.table_edge_poses = pa
00261
00262 with sm:
00263 sm_table = sm_approach_table()
00264
00265 smach.StateMachine.add(
00266 'APPROACH_TABLE',
00267 sm_table,
00268 remapping = {'table_edge_poses':'table_edge_poses',
00269 'movebase_pose_global':'movebase_pose_global',
00270 'table_edge_global':'table_edge_global'},
00271
00272 transitions = {'succeeded':'succeeded'})
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 sis = IntrospectionServer('Approach_Table', sm, '/SM_APPROACH_TABLE')
00289 sis.start()
00290
00291
00292 rospy.sleep( 3.0 )
00293 outcome = sm.execute()
00294
00295 sis.stop()
00296
00297
00298
00299
00300
00301
00302
00303