00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 import roslib
00035 roslib.load_manifest('pr2_plugs_actions')
00036 
00037 import rospy
00038 
00039 import threading
00040 import copy
00041 
00042 import actionlib
00043 import PyKDL
00044 
00045 from pr2_plugs_msgs.msg import *
00046 from pr2_plugs_msgs.srv import *
00047 from actionlib_msgs.msg import *
00048 from move_base_msgs.msg import *
00049 from geometry_msgs.msg import *
00050 from pr2_controllers_msgs.msg import *
00051 from pr2_common_action_msgs.msg import *
00052 from trajectory_msgs.msg import JointTrajectoryPoint, JointTrajectory
00053 from move_base_msgs.msg import MoveBaseAction, MoveBaseActionGoal
00054 
00055 from std_srvs.srv import *
00056 
00057 from tf_conversions.posemath import fromMsg, toMsg
00058 from pr2_arm_move_ik.tools import *
00059 
00060 
00061 import smach
00062 from smach import *
00063 from smach_ros import *
00064 
00065 from detect_outlet import construct_sm as construct_detect_outlet_sm
00066 from fetch_plug import construct_sm as construct_fetch_plug_sm
00067 from plug_in import construct_sm as construct_plug_in_sm
00068 
00069 from pr2_plugs_actions.tf_util import TFUtil
00070 
00071 def main():
00072     rospy.init_node("recharge_toplevel")
00073     TFUtil()
00074 
00075     
00076     close_gripper_goal = Pr2GripperCommandGoal()
00077     close_gripper_goal.command.position = 0.0
00078     close_gripper_goal.command.max_effort = 99999
00079 
00080     open_gripper_goal = Pr2GripperCommandGoal()
00081     open_gripper_goal.command.position = 0.07
00082     open_gripper_goal.command.max_effort = 99999
00083 
00084     
00085     clear_l_arm_goal = JointTrajectoryGoal()
00086     clear_l_arm_goal.trajectory.joint_names = ['l_shoulder_pan_joint', 'l_shoulder_lift_joint', 'l_upper_arm_roll_joint',
00087                                                'l_elbow_flex_joint', 'l_forearm_roll_joint', 'l_wrist_flex_joint', 'l_wrist_roll_joint']
00088     clear_l_arm_goal.trajectory.points.append(JointTrajectoryPoint(positions=[ 0.4,  1.0,   0.0,  -2.05,  0.0,  -0.1,  0.0],
00089                                                                    time_from_start=rospy.Duration(1.0)))
00090 
00091 
00092     stow_l_arm_goal = copy.deepcopy(clear_l_arm_goal)
00093     stow_l_arm_goal.trajectory.points = []
00094     stow_l_arm_goal.trajectory.points.append(JointTrajectoryPoint(positions=[ 0.0,  1.0,   0.0,  -2.05,  0.0,  -0.1,  0.0],
00095                                                                 time_from_start=rospy.Duration(1.0)))
00096     stow_l_arm_goal.trajectory.points.append(JointTrajectoryPoint(positions=[ 0.06,  1.24,   1.65,  -1.68,  -1.73,  -0.1,  0.0],
00097                                                                    time_from_start=rospy.Duration(2.0)))
00098 
00099     
00100 
00101     
00102     recharge_sm = StateMachine(
00103             outcomes=['plugged_in','unplugged','aborted','preempted'],
00104             input_keys = ['recharge_command'],
00105             output_keys = ['recharge_state'])
00106 
00107     
00108     recharge_sm.set_initial_state(['PROCESS_RECHARGE_COMMAND'])
00109     recharge_sm.userdata.recharge_state = RechargeState(state=RechargeState.UNPLUGGED)
00110 
00111     recharge_sm.userdata.base_to_outlet        = Pose(position=Point(-0.0178, -0.7474,  0.2824), orientation=Quaternion( 0.0002, -0.0002, -0.7061, 0.7081))
00112     recharge_sm.userdata.gripper_to_plug_grasp = Pose(position=Point( 0.0282, -0.0050, -0.0103), orientation=Quaternion(-0.6964,  0.1228,  0.1228, 0.6964))
00113     recharge_sm.userdata.base_to_plug_on_base  = Pose(position=Point( 0.0783,  0.0244,  0.2426), orientation=Quaternion( 0.4986,  0.4962,  0.4963, 0.5088))
00114     recharge_sm.userdata.gripper_to_plug       = Pose(position=Point( 0.0275, -0.0046, -0.0094), orientation=Quaternion(-0.6876,  0.1293,  0.1226, 0.7039))
00115 
00116     with recharge_sm:
00117         
00118         @smach.cb_interface(input_keys=['recharge_command'])
00119         def plug_in_cond(ud):
00120             command = ud.recharge_command.command
00121             if command is RechargeCommand.PLUG_IN:
00122                 return True
00123             elif command is RechargeCommand.UNPLUG:
00124                 return False
00125         StateMachine.add('PROCESS_RECHARGE_COMMAND',
00126                 ConditionState(cond_cb = plug_in_cond),
00127                 { 'true':'NAVIGATE_TO_OUTLET',
00128                     'false':'UNPLUG'})
00129         
00130         sm_nav = StateMachine(
00131                 outcomes=['succeeded','aborted','preempted'],
00132                 input_keys = ['recharge_command'])
00133         StateMachine.add('NAVIGATE_TO_OUTLET', sm_nav,
00134                 {'succeeded':'DETECT_OUTLET',
00135                     'aborted':'FAIL_STILL_UNPLUGGED'})
00136         with sm_nav:
00137             StateMachine.add('GOAL_IS_LOCAL', 
00138                     ConditionState(
00139                         cond_cb = lambda ud: ud.recharge_command.plug_id == 'local',
00140                         input_keys = ['recharge_command']),
00141                     {'true': 'UNTUCK_AT_OUTLET',
00142                         'false': 'SAFETY_TUCK'})
00143             StateMachine.add('SAFETY_TUCK', 
00144                     SimpleActionState('tuck_arms', TuckArmsAction,
00145                         goal = TuckArmsGoal(True,True)),
00146                     { 'succeeded':'GET_OUTLET_LOCATIONS',
00147                       'aborted':'SAFETY_TUCK'})
00148             StateMachine.add('GET_OUTLET_LOCATIONS',
00149                     ServiceState('outlet_locations', GetOutlets,
00150                         response_slots=['poses']),
00151                     {'succeeded':'NAVIGATE'},
00152                     remapping={'poses':'approach_poses'})
00153 
00154             @smach.cb_interface(input_keys=['approach_poses','recharge_command'])
00155             def get_outlet_approach_goal(ud,goal):
00156                 """Get the approach pose from the outlet approach poses list"""
00157 
00158                 
00159                 plug_id = ud.recharge_command.plug_id
00160 
00161                 
00162                 for outlet in ud.approach_poses:
00163                     if outlet.name == plug_id or outlet.id == plug_id:
00164                         target_pose = PoseStamped(pose=outlet.approach_pose)
00165 
00166                 
00167                 move_base_goal = MoveBaseGoal()
00168                 move_base_goal.target_pose = target_pose
00169                 move_base_goal.target_pose.header.stamp = rospy.Time.now()
00170                 move_base_goal.target_pose.header.frame_id = "map"
00171 
00172                 return move_base_goal
00173             StateMachine.add('NAVIGATE', 
00174                              SimpleActionState('pr2_move_base',MoveBaseAction,
00175                                                goal_cb=get_outlet_approach_goal,
00176                                                exec_timeout = rospy.Duration(20*60.0)),
00177                              { 'succeeded':'UNTUCK_AT_OUTLET' })
00178             StateMachine.add('UNTUCK_AT_OUTLET', 
00179                              SimpleActionState('tuck_arms', TuckArmsAction,
00180                                                goal = TuckArmsGoal(False, False)))
00181 
00182         StateMachine.add('DETECT_OUTLET', 
00183                          SimpleActionState('detect_outlet',DetectOutletAction,
00184                                            result_slots = ['base_to_outlet_pose']),
00185                          {'succeeded':'FETCH_PLUG',
00186                           'aborted':'FAIL_STILL_UNPLUGGED'},
00187                          remapping = {'base_to_outlet_pose':'base_to_outlet'})
00188 
00189         StateMachine.add('FETCH_PLUG',
00190                          SimpleActionState('fetch_plug',FetchPlugAction,
00191                                            result_slots = ['plug_on_base_pose', 'gripper_plug_grasp_pose']),
00192                          {'succeeded':'PLUG_IN',
00193                           'aborted':'FAIL_OPEN_GRIPPER'},
00194                          remapping = {'plug_on_base_pose':'base_to_plug_on_base', 'gripper_plug_grasp_pose':'gripper_to_plug_grasp'})
00195         
00196         @smach.cb_interface(input_keys=['recharge_state'], output_keys=['recharge_state'])
00197         def set_plug_in_result(ud, result_status, result):
00198             if result_status == GoalStatus.SUCCEEDED:
00199                 ud.recharge_state.state = RechargeState.PLUGGED_IN
00200         StateMachine.add('PLUG_IN',
00201                          SimpleActionState('plug_in',PlugInAction,
00202                                            goal_slots = ['base_to_outlet'],
00203                                            result_slots = ['gripper_to_plug'],
00204                                            result_cb = set_plug_in_result),
00205                          { 'succeeded':'STOW_LEFT_ARM',
00206                            'aborted':'RECOVER_STOW_PLUG'})
00207         
00208         
00209         StateMachine.add('STOW_LEFT_ARM',
00210                          SimpleActionState('l_arm_controller/joint_trajectory_action', JointTrajectoryAction,
00211                                            goal = stow_l_arm_goal),
00212                          { 'succeeded':'plugged_in'})
00213 
00214         
00215         unplug_sm = StateMachine(
00216             outcomes = ['succeeded','aborted','preempted'],
00217             input_keys=['recharge_state','gripper_to_plug_grasp','gripper_to_plug','base_to_outlet','base_to_plug_on_base'],
00218             output_keys=['recharge_state'])
00219         StateMachine.add('UNPLUG', unplug_sm,
00220                          { 'succeeded':'unplugged',
00221                            'aborted':'FAIL_OPEN_GRIPPER'})
00222         with unplug_sm:
00223             """Unplug from outlet"""
00224             
00225             StateMachine.add('CLOSE_GRIPPER',
00226                     SimpleActionState('r_gripper_controller/gripper_action', Pr2GripperCommandAction,
00227                         goal = close_gripper_goal),
00228                     { 'succeeded':'aborted',
00229                         'aborted':'CLEAR_LEFT_ARM'})
00230             
00231             
00232             StateMachine.add('CLEAR_LEFT_ARM',
00233                              SimpleActionState('l_arm_controller/joint_trajectory_action', JointTrajectoryAction,
00234                                                goal = clear_l_arm_goal),
00235                              { 'succeeded':'WIGGLE_OUT'})
00236 
00237             
00238             def get_wiggle_out_goal(ud, goal):
00239                 
00240                 goal.wiggle_period = rospy.Duration(0.5)
00241                 goal.insert = 0
00242                 return goal
00243             StateMachine.add('WIGGLE_OUT',
00244                     SimpleActionState('wiggle_plug',WigglePlugAction,
00245                         goal_slots = ['gripper_to_plug','base_to_outlet'],
00246                         goal_cb = get_wiggle_out_goal),
00247                     {'succeeded':'PULL_BACK_FROM_WALL'})
00248 
00249             @smach.cb_interface(input_keys=['base_to_outlet','gripper_to_plug'])
00250             def get_pull_back_goal(ud, goal):
00251                 """Generate an ik goal to move along the local x axis of the outlet."""
00252 
00253                 pose_outlet_plug = PyKDL.Frame(PyKDL.Vector(-0.10, 0, 0))
00254                 pose_gripper_wrist = fromMsg(TFUtil.wait_and_lookup('r_gripper_tool_frame', 'r_wrist_roll_link').pose)
00255 
00256                 pose_base_wrist = fromMsg(ud.base_to_outlet) * pose_outlet_plug * fromMsg(ud.gripper_to_plug).Inverse() * pose_gripper_wrist
00257 
00258                 goal.pose.pose = toMsg(pose_base_wrist)
00259                 goal.pose.header.stamp = rospy.Time.now()
00260                 goal.pose.header.frame_id = 'base_link'
00261                 goal.ik_seed = get_action_seed('pr2_plugs_configuration/approach_outlet_seed')
00262                 goal.move_duration = rospy.Duration(5.0)
00263 
00264             StateMachine.add('PULL_BACK_FROM_WALL',
00265                              SimpleActionState('r_arm_ik', ArmMoveIKAction, goal_cb = get_pull_back_goal),
00266                              {'succeeded':'STOW_PLUG',
00267                               'aborted':'WIGGLE_OUT'})
00268             
00269             
00270             @smach.cb_interface(input_keys=['recharge_state'],output_keys=['recharge_state'])
00271             def set_unplug_result(ud, result_state, result):
00272                 if result_state is GoalStatus.SUCCEEDED:
00273                     ud.recharge_state.state = RechargeState.UNPLUGGED
00274 
00275             StateMachine.add('STOW_PLUG', SimpleActionState('stow_plug',StowPlugAction,
00276                                                             goal_slots = ['gripper_to_plug_grasp','base_to_plug'],
00277                                                             result_cb = set_unplug_result),
00278                              {'succeeded':'SUCCEED_TUCK'},
00279                              remapping = {'base_to_plug':'base_to_plug_on_base'})
00280             
00281             StateMachine.add('SUCCEED_TUCK', SimpleActionState('tuck_arms', TuckArmsAction, goal=TuckArmsGoal(True, True)), { 'succeeded': 'SUCCEED_FREE_BASE' })
00282             
00283             
00284             @smach.cb_interface(input_keys=[])
00285             def get_free_base_goal(ud, goal):
00286                 goal.target_pose.pose.position.y =  -0.05
00287                 goal.target_pose.pose.position.x =  0.02
00288                 goal.target_pose.pose.orientation.w = 1.0
00289                 goal.target_pose.header.stamp = rospy.Time.now()
00290                 goal.target_pose.header.frame_id = "base_footprint"
00291 
00292             StateMachine.add('SUCCEED_FREE_BASE', SimpleActionState('move_base_omnidirectional', MoveBaseAction, goal_cb = get_free_base_goal), { 'succeeded': 'succeeded', 'aborted': 'succeeded' })
00293 
00294         
00295         StateMachine.add('RECOVER_STOW_PLUG', SimpleActionState('stow_plug',StowPlugAction,
00296                                                                 goal_slots = ['gripper_to_plug_grasp','base_to_plug']),
00297                          { 'succeeded':'FAIL_STILL_UNPLUGGED',
00298                            'aborted':'FAIL_OPEN_GRIPPER'},
00299                          remapping = {'base_to_plug':'base_to_plug_on_base'})
00300 
00301         
00302         
00303         @smach.cb_interface(input_keys=['recharge_state'],output_keys=['recharge_state'],outcomes=['done'])
00304         def remain_unplugged(ud):
00305             ud.recharge_state.state = RechargeState.UNPLUGGED
00306             return 'done'
00307         StateMachine.add('FAIL_STILL_UNPLUGGED', 
00308                          CBState(cb = remain_unplugged),
00309                          {'done':'FAIL_LOWER_SPINE'})
00310         
00311         
00312         StateMachine.add('FAIL_OPEN_GRIPPER',
00313                          SimpleActionState('r_gripper_controller/gripper_action', Pr2GripperCommandAction,
00314                                            goal = open_gripper_goal),
00315                          {'succeeded':'FAIL_UNTUCK'})
00316         
00317         StateMachine.add('FAIL_UNTUCK',
00318                          SimpleActionState('tuck_arms',TuckArmsAction,
00319                                            goal = TuckArmsGoal(False, False)),
00320                          {'succeeded':'FAIL_LOWER_SPINE'})
00321         
00322         
00323         StateMachine.add('FAIL_LOWER_SPINE',
00324                 SimpleActionState('torso_controller/position_joint_action', SingleJointPositionAction,
00325                                   goal = SingleJointPositionGoal(position=0.02)),
00326                 {'succeeded':'FAIL_TUCK_ARMS'})
00327 
00328         StateMachine.add('FAIL_TUCK_ARMS',
00329                          SimpleActionState('tuck_arms', TuckArmsAction,
00330                                            goal = TuckArmsGoal(True,True)),
00331                          { 'succeeded':'aborted'})
00332 
00333 
00334     
00335     intro_server = IntrospectionServer('recharge',recharge_sm,'/RECHARGE')
00336     intro_server.start()
00337 
00338     
00339     sms = ActionServerWrapper(
00340             'recharge', RechargeAction, recharge_sm,
00341             succeeded_outcomes = ['plugged_in','unplugged'],
00342             aborted_outcomes = ['aborted'],
00343             preempted_outcomes = ['preempted'],
00344             goal_slots_map = {'command':'recharge_command'},
00345             result_slots_map = {'state':'recharge_state'})
00346     sms.run_server()
00347 
00348     rospy.spin()
00349 
00350     intro_server.stop()
00351 
00352 if __name__ == "__main__":
00353     main()
00354