def main():
    rospy.init_node("recharge_toplevel")
    TFUtil()

    # Construct state machine
    recharge_sm = StateMachine(
        outcomes=['plugged_in', 'unplugged', 'aborted', 'preempted'],
        input_keys=['recharge_command'],
        output_keys=['recharge_state'])

    # Set the initial state explicitly
    recharge_sm.set_initial_state(['PROCESS_RECHARGE_COMMAND'])
    recharge_sm.userdata.recharge_state = RechargeState(
        state=RechargeState.UNPLUGGED)

    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))
    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))
    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))
    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))

    with recharge_sm:
        ### PLUGGING IN ###
        @smach.cb_interface(input_keys=['recharge_command'])
        def plug_in_cond(ud):
            command = ud.recharge_command.command
            if command is RechargeCommand.PLUG_IN:
                return True
            elif command is RechargeCommand.UNPLUG:
                return False

        StateMachine.add('PROCESS_RECHARGE_COMMAND',
                         ConditionState(cond_cb=plug_in_cond), {
                             'true': 'NAVIGATE_TO_OUTLET',
                             'false': 'UNPLUG'
                         })

        sm_nav = StateMachine(outcomes=['succeeded', 'aborted', 'preempted'],
                              input_keys=['recharge_command'])
        StateMachine.add('NAVIGATE_TO_OUTLET', sm_nav, {
            'succeeded': 'DETECT_OUTLET',
            'aborted': 'FAIL_STILL_UNPLUGGED'
        })
        with sm_nav:
            StateMachine.add(
                'GOAL_IS_LOCAL',
                ConditionState(
                    cond_cb=lambda ud: ud.recharge_command.plug_id == 'local',
                    input_keys=['recharge_command']), {
                        'true': 'UNTUCK_AT_OUTLET',
                        'false': 'SAFETY_TUCK'
                    })
            StateMachine.add(
                'SAFETY_TUCK',
                SimpleActionState('tuck_arms',
                                  TuckArmsAction,
                                  goal=TuckArmsGoal(True, True)), {
                                      'succeeded': 'GET_OUTLET_LOCATIONS',
                                      'aborted': 'SAFETY_TUCK'
                                  })
            StateMachine.add('GET_OUTLET_LOCATIONS',
                             ServiceState('outlet_locations',
                                          GetOutlets,
                                          response_slots=['poses']),
                             {'succeeded': 'NAVIGATE'},
                             remapping={'poses': 'approach_poses'})

            @smach.cb_interface(
                input_keys=['approach_poses', 'recharge_command'])
            def get_outlet_approach_goal(ud, goal):
                """Get the approach pose from the outlet approach poses list"""

                # Get id from command
                plug_id = ud.recharge_command.plug_id

                # Grab the relevant outlet approach pose
                for outlet in ud.approach_poses:
                    if outlet.name == plug_id or outlet.id == plug_id:
                        target_pose = PoseStamped(pose=outlet.approach_pose)

                # Create goal for move base
                move_base_goal = MoveBaseGoal()
                move_base_goal.target_pose = target_pose
                move_base_goal.target_pose.header.stamp = rospy.Time.now()
                move_base_goal.target_pose.header.frame_id = "map"

                return move_base_goal

            StateMachine.add(
                'NAVIGATE',
                SimpleActionState('pr2_move_base',
                                  MoveBaseAction,
                                  goal_cb=get_outlet_approach_goal,
                                  exec_timeout=rospy.Duration(20 * 60.0)),
                {'succeeded': 'UNTUCK_AT_OUTLET'})
            StateMachine.add(
                'UNTUCK_AT_OUTLET',
                SimpleActionState('tuck_arms',
                                  TuckArmsAction,
                                  goal=TuckArmsGoal(False, False)))

        StateMachine.add('DETECT_OUTLET',
                         SimpleActionState(
                             'detect_outlet',
                             DetectOutletAction,
                             result_slots=['base_to_outlet_pose']), {
                                 'succeeded': 'FETCH_PLUG',
                                 'aborted': 'FAIL_STILL_UNPLUGGED'
                             },
                         remapping={'base_to_outlet_pose': 'base_to_outlet'})

        StateMachine.add('FETCH_PLUG',
                         SimpleActionState('fetch_plug',
                                           FetchPlugAction,
                                           result_slots=[
                                               'plug_on_base_pose',
                                               'gripper_plug_grasp_pose'
                                           ]), {
                                               'succeeded': 'PLUG_IN',
                                               'aborted': 'FAIL_OPEN_GRIPPER'
                                           },
                         remapping={
                             'plug_on_base_pose': 'base_to_plug_on_base',
                             'gripper_plug_grasp_pose': 'gripper_to_plug_grasp'
                         })

        @smach.cb_interface(input_keys=['recharge_state'],
                            output_keys=['recharge_state'])
        def set_plug_in_result(ud, result_status, result):
            if result_status == GoalStatus.SUCCEEDED:
                ud.recharge_state.state = RechargeState.PLUGGED_IN

        StateMachine.add(
            'PLUG_IN',
            SimpleActionState('plug_in',
                              PlugInAction,
                              goal_slots=['base_to_outlet'],
                              result_slots=['gripper_to_plug'],
                              result_cb=set_plug_in_result), {
                                  'succeeded': 'STOW_LEFT_ARM',
                                  'aborted': 'RECOVER_STOW_PLUG'
                              })

        # Move L arm out of the way
        StateMachine.add(
            'STOW_LEFT_ARM',
            SimpleActionState('l_arm_controller/joint_trajectory_action',
                              JointTrajectoryAction,
                              goal=stow_l_arm_goal),
            {'succeeded': 'plugged_in'})