class GetPipePose(EventState):
	'''
	># centerpose	PoseStamped()		Pose of centered pipe.
	#> pipepose	PoseStamped()		Pose of desired pipe.
	'''
	TOP_LEFT = 1
	TOP_RIGHT = 2
	CENTER = 3
	DOWN_LEFT = 4
	DOWN_RIGHT = 5

	def __init__(self, choice):
		'''
		Constructor
		'''
		super(GetPipePose, self).__init__(outcomes=['succeeded'], input_keys = ['centerpose'], output_keys = ['pipepose'])
		self._choice = choice
		
		self._tf = ProxyTransformListener().listener()
		self._succeeded = False
		
	def execute(self, userdata):
		'''
		Execute this state
		'''
		if self._succeeded:
			return 'succeeded'
		
			
	def on_enter(self, userdata):
		tempPose = PoseStamped()
		tempPose = self._tf.transformPose('base_link', userdata.centerpose)
		
		if self._choice == GetPipePose.TOP_LEFT:
			tempPose.pose.position.y = tempPose.pose.position.y + 0.105
			tempPose.pose.position.z = tempPose.pose.position.z + 0.105
		if self._choice == GetPipePose.TOP_RIGHT:
			tempPose.pose.position.y = tempPose.pose.position.y - 0.105
			tempPose.pose.position.z = tempPose.pose.position.z + 0.105
		if self._choice == GetPipePose.DOWN_RIGHT:
			tempPose.pose.position.y = tempPose.pose.position.y - 0.105
			tempPose.pose.position.z = tempPose.pose.position.z - 0.105
		if self._choice == GetPipePose.DOWN_LEFT:	
			tempPose.pose.position.y = tempPose.pose.position.y + 0.105
			tempPose.pose.position.z = tempPose.pose.position.z - 0.105

		userdata.pipepose = tempPose
		
		self._succeeded = True
예제 #2
0
class ObjectDetectionMonitor(EventState):
    '''
    Receive list of detected objects as cob_object_detection_msgs/DetectionArray messages and check if there is an object 
    which matches given (label, type) pair. Based on present of this object classify situation in `no_detections` state, 
    `have_detections` (there is objects but none of them matches give (label, type)),
    `detection_matches` (desired object found). In the last case its pose bublished on given topic.
    
    -- detection_topic                       string          DetectionArray message topic.
    -- label                                 string          Object label. Use '*' to match all labals.
    -- type                                  string          Object type. Use '*' to match all types.
    -- detection_period                      float           Parameteres: detection_period (s), position_tolerance (m), orientation_tolerance (rad).
    -- exit_states                           string[]        Stop monitoring and return outcome if detected situation in this list.
    -- pose_topic                            string          Topic for publishing matched object pose (may be Empty).
    -- pose_frame_id                         string          Frame in which pose should be published.

    #> pose                                  object          Object pose before exit.

    <= no_detections 	                     Nothing have been detected for detection_period.
    <= have_detections 	                     Objects were detected, but not of them matches (label, type)
    <= detecton_matches	                     Object presents and it is moving. `pose` key contains last pose.
    <= failure	                             Runtime error.

    '''
    def __init__(self,
                 detection_topic='detection',
                 label='*',
                 type='*',
                 exit_states=['no_detections'],
                 pose_topic='',
                 pose_frame_id='odom_combined',
                 detection_period=1.0):
        super(ObjectDetectionMonitor, self).__init__(outcomes=[
            'no_detections', 'have_detections', 'detection_matches', 'failure'
        ],
                                                     output_keys=['pose'])

        # store state parameter for later use.
        self._detection_topic = detection_topic
        self._label = label
        self._type = type
        self._pose_topic = pose_topic
        self._frame_id = pose_frame_id
        self._exit_states = exit_states
        self._detection_period = detection_period

        # setup proxies
        self._detection_subscriber = ProxySubscriberCached(
            {self._detection_topic: DetectionArray})
        self._detection_subscriber.enable_buffer(self._detection_topic)
        if self._pose_topic:
            self._pose_publisher = ProxyPublisher(
                {self._pose_topic: PoseStamped})
        else:
            self._pose_publisher = None
        self._tf_listener = ProxyTransformListener().listener()

        # check parameters
        if not isinstance(
                self._frame_id,
                str):  # or not self._tf_listener.frameExists(self._frame_id):
            raise ValueError(
                'ObjectDetectionMonitor: %s is not a valid frame' %
                self._frame_id)
        if not isinstance(self._label, str) or not isinstance(self._type, str):
            raise ValueError(
                'ObjectDetectionMonitor: label and type parameters must be string.'
            )
        if not isinstance(self._detection_period,
                          float) or self._detection_period < 0.0:
            raise ValueError(
                'ObjectDetectionMonitor: detection_period must be float.')
        if not isinstance(self._exit_states, list) or not all([
                state
                in ['no_detections', 'have_detections', 'detection_matches']
                for state in self._exit_states
        ]):
            raise ValueError(
                'ObjectDetectionMonitor: incorrect list of exit states.')

        # pose buffers
        self._pose = None
        self._last_detection_stamp = None
        self._last_match_stamp = None
        self._last_match_id = None

    def on_enter(self, userdata):
        # reset pose buffers
        self._pose = None
        stamp = rospy.Time.now()
        self._last_detection_stamp = stamp
        self._last_match_stamp = stamp
        self._last_match_id = None

        Logger.loginfo('ObjectDetectionMonitor: start monitoring.')

    def execute(self, userdata):
        # list of found matches
        have_detections = False
        best_match = None
        match = None
        # check if new message is available
        while self._detection_subscriber.has_buffered(self._detection_topic):
            # get detections msg
            detections_msg = self._detection_subscriber.get_from_buffer(
                self._detection_topic)
            # check if have detections
            if len(detections_msg.detections) > 0:
                have_detections = True
            # process detections
            for detection in detections_msg.detections:
                # check match
                is_match = True
                if self._label != '*' and detection.label != self._label:
                    is_match = False
                if self._type != '*' and detection.type != self._type:
                    is_match = False
                # register match
                if is_match:
                    match = detection
                    if match.id == self._last_match_id:
                        best_match = match

        if best_match:
            match = best_match

        # result
        stamp = rospy.Time.now()
        if not have_detections:
            # no object detected
            # check if detection preiod exceeded
            if (stamp - self._last_detection_stamp
                ).to_sec() > self._detection_period:
                # no detections state
                if 'no_detections' in self._exit_states:
                    Logger.loginfo('ObjectDetectionMonitor: no detections.')
                    return 'no_detections'
        elif not match:
            # object detected but it is not match
            self._last_detection_stamp = stamp
            # check if detection perod exceeded
            if (stamp - self._last_detection_stamp
                ).to_sec() > self._detection_period:
                # have_detections state
                if 'have_detections' in self._exit_states:
                    Logger.loginfo('ObjectDetectionMonitor: detection.')
                    return 'have_detections'
        else:
            # appropriate match is found
            self._last_match_stamp = stamp
            self._last_match_id = match.id
            # publish
            if self._pose_publisher:
                # transform to frame_id
                try:
                    # transform
                    pose_stamped = PoseStamped(
                        pose=match.pose,
                        header=Header(frame_id=match.header.frame_id))
                    self._pose = self._tf_listener.transformPose(
                        self._frame_id, pose_stamped)
                except tf.Exception as e:
                    Logger.logwarn(
                        'Unable to transform from %s to %s' %
                        (match.pose.header.frame_id, self._frame_id))
                    return 'failure'
                # publish
                self._pose_publisher.publish(self._pose_topic, self._pose)
            # match_detection state
            if 'detection_matches' in self._exit_states:
                Logger.loginfo('ObjectDetectionMonitor: match.')
                return 'detection_matches'

        return None

    def on_exit(self, userdata):
        userdata.pose = self._pose
class DetectPipesSM(Behavior):
	'''
	Position as required and try different ways to detect the pipe positions
	'''


	def __init__(self):
		super(DetectPipesSM, self).__init__()
		self.name = 'Detect Pipes'

		# parameters of this behavior
		self.add_parameter('pose_offset', 0.3)
		self.add_parameter('close_offset', 0.1)

		# references to used behaviors

		# Additional initialization code can be added inside the following tags
		# [MANUAL_INIT]
		self._tf = ProxyTransformListener().listener()
		# [/MANUAL_INIT]

		# Behavior comments:

		# O 98 480 
		# Run in full autonomy to skip looking, run in high to decide



	def create(self):
		joints_arm_with_gripper = ['arm_joint_%d'%i for i in range(5)]
		srdf = "hector_tracker_robot_moveit_config/config/taurob_tracker.srdf"
		percept_class = 'pipes'
		move_group = "arm_with_gripper_group"
		move_group_no_eef = "arm_group"
		# x:268 y:162, x:472 y:46
		_state_machine = OperatableStateMachine(outcomes=['finished', 'failed'])
		_state_machine.userdata.object_pose = None
		_state_machine.userdata.object_type = percept_class
		_state_machine.userdata.test_pregrasp = [0, 1.57, 0.77, 0.38, 0]
		_state_machine.userdata.index = -1

		# Additional creation code can be added inside the following tags
		# [MANUAL_CREATE]
		
		# [/MANUAL_CREATE]

		# x:30 y:365, x:569 y:352, x:45 y:183
		_sm_gripper_action_0 = OperatableStateMachine(outcomes=['finished', 'failed', 'back'])

		with _sm_gripper_action_0:
			# x:168 y:53
			OperatableStateMachine.add('Decide_Close_Gripper',
										OperatorDecisionState(outcomes=['close_gripper', 'move_back'], hint="Grasp pipe?", suggestion='close_gripper'),
										transitions={'close_gripper': 'Close_Gripper', 'move_back': 'back'},
										autonomy={'close_gripper': Autonomy.Full, 'move_back': Autonomy.Full})

			# x:221 y:173
			OperatableStateMachine.add('Close_Gripper',
										GripperState(action=0.8, duration=2.0),
										transitions={'done': 'Manipulate_Pipe', 'failed': 'failed'},
										autonomy={'done': Autonomy.Low, 'failed': Autonomy.High})

			# x:229 y:391
			OperatableStateMachine.add('Decide_Open_Gripper',
										OperatorDecisionState(outcomes=['open_gripper', 'move_back'], hint="Open gripper or pull pipe?", suggestion='open_gripper'),
										transitions={'open_gripper': 'Open_Gripper', 'move_back': 'back'},
										autonomy={'open_gripper': Autonomy.High, 'move_back': Autonomy.Full})

			# x:241 y:290
			OperatableStateMachine.add('Manipulate_Pipe',
										LogState(text="Perform desired pipe manipulation", severity=Logger.REPORT_HINT),
										transitions={'done': 'Decide_Open_Gripper'},
										autonomy={'done': Autonomy.High})

			# x:215 y:511
			OperatableStateMachine.add('Open_Gripper',
										GripperState(action=GripperState.OPEN, duration=1.0),
										transitions={'done': 'finished', 'failed': 'failed'},
										autonomy={'done': Autonomy.Low, 'failed': Autonomy.High})


		# x:153 y:384, x:388 y:221
		_sm_move_back_out_1 = OperatableStateMachine(outcomes=['finished', 'failed'], input_keys=['pipes_out_pose'])

		with _sm_move_back_out_1:
			# x:118 y:87
			OperatableStateMachine.add('Get_Cartesian_Path_Back',
										CalculateCartesianPathState(move_group=move_group, ignore_collisions=True),
										transitions={'planned': 'Execute_Cartesian_Path_Back', 'failed': 'failed'},
										autonomy={'planned': Autonomy.Low, 'failed': Autonomy.High},
										remapping={'eef_pose': 'pipes_out_pose', 'joint_trajectory': 'joint_trajectory', 'plan_fraction': 'plan_fraction'})

			# x:116 y:216
			OperatableStateMachine.add('Execute_Cartesian_Path_Back',
										MoveitExecuteTrajectoryState(),
										transitions={'done': 'finished', 'failed': 'failed'},
										autonomy={'done': Autonomy.Low, 'failed': Autonomy.High},
										remapping={'joint_trajectory': 'joint_trajectory'})


		# x:230 y:517, x:550 y:229
		_sm_move_to_close_pose_2 = OperatableStateMachine(outcomes=['finished', 'failed'], input_keys=['pipes_pose'])

		with _sm_move_to_close_pose_2:
			# x:97 y:43
			OperatableStateMachine.add('Move_Pose_Cartesian',
										CalculationState(calculation=lambda p: self.update_pose(p, self.close_offset)),
										transitions={'done': 'Visualize_Pipes_Close_Pose'},
										autonomy={'done': Autonomy.Off},
										remapping={'input_value': 'pipes_pose', 'output_value': 'pipes_close_pose'})

			# x:113 y:140
			OperatableStateMachine.add('Visualize_Pipes_Close_Pose',
										PublishPoseState(topic='/pipes/close_pose'),
										transitions={'done': 'Get_Cartesian_Path'},
										autonomy={'done': Autonomy.Low},
										remapping={'pose': 'pipes_close_pose'})

			# x:147 y:371
			OperatableStateMachine.add('Execute_Cartesian_Path',
										MoveitExecuteTrajectoryState(),
										transitions={'done': 'finished', 'failed': 'failed'},
										autonomy={'done': Autonomy.Low, 'failed': Autonomy.High},
										remapping={'joint_trajectory': 'joint_trajectory'})

			# x:121 y:260
			OperatableStateMachine.add('Get_Cartesian_Path',
										CalculateCartesianPathState(move_group=move_group, ignore_collisions=True),
										transitions={'planned': 'Execute_Cartesian_Path', 'failed': 'failed'},
										autonomy={'planned': Autonomy.Low, 'failed': Autonomy.High},
										remapping={'eef_pose': 'pipes_close_pose', 'joint_trajectory': 'joint_trajectory', 'plan_fraction': 'plan_fraction'})


		# x:119 y:516, x:358 y:275
		_sm_move_to_out_pose_3 = OperatableStateMachine(outcomes=['finished', 'failed'], input_keys=['pipes_pose'], output_keys=['pipes_out_pose'])

		with _sm_move_to_out_pose_3:
			# x:83 y:35
			OperatableStateMachine.add('Move_Pose_Out',
										CalculationState(calculation=lambda p: self.update_pose(p, self.pose_offset)),
										transitions={'done': 'Visualize_Pipes_Out_Pose'},
										autonomy={'done': Autonomy.Off},
										remapping={'input_value': 'pipes_pose', 'output_value': 'pipes_out_pose'})

			# x:85 y:307
			OperatableStateMachine.add('Move_To_Joints',
										MoveitToJointsState(move_group=move_group, joint_names=joints_arm_with_gripper, action_topic='/move_group'),
										transitions={'reached': 'Correct_Gripper_Rotation', 'planning_failed': 'failed', 'control_failed': 'failed'},
										autonomy={'reached': Autonomy.Low, 'planning_failed': Autonomy.High, 'control_failed': Autonomy.High},
										remapping={'joint_config': 'joint_config'})

			# x:77 y:118
			OperatableStateMachine.add('Visualize_Pipes_Out_Pose',
										PublishPoseState(topic='/pipes/out_pose'),
										transitions={'done': 'Get_Joint_Target'},
										autonomy={'done': Autonomy.Low},
										remapping={'pose': 'pipes_out_pose'})

			# x:83 y:211
			OperatableStateMachine.add('Get_Joint_Target',
										CalculateIKState(move_group=move_group, ignore_collisions=False),
										transitions={'planned': 'Move_To_Joints', 'failed': 'failed'},
										autonomy={'planned': Autonomy.Low, 'failed': Autonomy.High},
										remapping={'eef_pose': 'pipes_out_pose', 'joint_config': 'joint_config'})

			# x:71 y:408
			OperatableStateMachine.add('Correct_Gripper_Rotation',
										GripperRollState(rotation=GripperRollState.HORIZONTAL, duration=1.0),
										transitions={'done': 'finished', 'failed': 'failed'},
										autonomy={'done': Autonomy.Low, 'failed': Autonomy.High})


		# x:272 y:264, x:55 y:574
		_sm_eef_to_detected_4 = OperatableStateMachine(outcomes=['finished', 'failed'], input_keys=['pipes_pose'], output_keys=['pipes_pose'])

		with _sm_eef_to_detected_4:
			# x:58 y:35
			OperatableStateMachine.add('Move_To_Out_Pose',
										_sm_move_to_out_pose_3,
										transitions={'finished': 'Decide_Move_Close', 'failed': 'failed'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit},
										remapping={'pipes_pose': 'pipes_pose', 'pipes_out_pose': 'pipes_out_pose'})

			# x:568 y:38
			OperatableStateMachine.add('Move_To_Close_Pose',
										_sm_move_to_close_pose_2,
										transitions={'finished': 'Gripper_Action', 'failed': 'failed'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit},
										remapping={'pipes_pose': 'pipes_pose'})

			# x:175 y:448
			OperatableStateMachine.add('Move_Back_Out',
										_sm_move_back_out_1,
										transitions={'finished': 'finished', 'failed': 'failed'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit},
										remapping={'pipes_out_pose': 'pipes_out_pose'})

			# x:326 y:34
			OperatableStateMachine.add('Decide_Move_Close',
										OperatorDecisionState(outcomes=['close', 'end'], hint="Move closer to pipe?", suggestion='close'),
										transitions={'close': 'Move_To_Close_Pose', 'end': 'finished'},
										autonomy={'close': Autonomy.High, 'end': Autonomy.Full})

			# x:626 y:219
			OperatableStateMachine.add('Gripper_Action',
										_sm_gripper_action_0,
										transitions={'finished': 'Decide_Move_Back', 'failed': 'failed', 'back': 'Move_Back_Out'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit, 'back': Autonomy.Inherit})

			# x:408 y:452
			OperatableStateMachine.add('Decide_Move_Back',
										OperatorDecisionState(outcomes=['move_back', 'end'], hint="Move back from pipe?", suggestion='move_back'),
										transitions={'move_back': 'Move_Back_Out', 'end': 'finished'},
										autonomy={'move_back': Autonomy.High, 'end': Autonomy.Full})


		# x:30 y:365, x:130 y:365
		_sm_select_pipe_5 = OperatableStateMachine(outcomes=['finished', 'next'], input_keys=['index', 'object_pose', 'object_data'], output_keys=['index', 'pipe_pose'])

		with _sm_select_pipe_5:
			# x:98 y:78
			OperatableStateMachine.add('Increment_Index',
										CalculationState(calculation=lambda x: x+1),
										transitions={'done': 'Select_Pipe'},
										autonomy={'done': Autonomy.Off},
										remapping={'input_value': 'index', 'output_value': 'index'})

			# x:102 y:178
			OperatableStateMachine.add('Select_Pipe',
										SelectPipePose(),
										transitions={'selected': 'next', 'out_of_range': 'finished'},
										autonomy={'selected': Autonomy.Off, 'out_of_range': Autonomy.Off},
										remapping={'object_pose': 'object_pose', 'object_data': 'object_data', 'pose_choice': 'index', 'pipe_pose': 'pipe_pose'})


		# x:427 y:433, x:453 y:131
		_sm_get_pipes_6 = OperatableStateMachine(outcomes=['finished', 'failed'], input_keys=['object_pose'], output_keys=['object_pose', 'object_data'])

		with _sm_get_pipes_6:
			# x:51 y:28
			OperatableStateMachine.add('Get_Observation_Arm_Config',
										GetJointsFromSrdfState(config_name="observation_pose", srdf_file=srdf, move_group="", robot_name=""),
										transitions={'retrieved': 'Move_To_Observation_Pose', 'file_error': 'failed'},
										autonomy={'retrieved': Autonomy.Off, 'file_error': Autonomy.Off},
										remapping={'joint_values': 'joints_observation_pose'})

			# x:53 y:111
			OperatableStateMachine.add('Move_To_Observation_Pose',
										MoveitToJointsState(move_group="arm_group", joint_names=joints_arm_with_gripper[0:4], action_topic='/move_group'),
										transitions={'reached': 'Detect_Pipes', 'planning_failed': 'failed', 'control_failed': 'failed'},
										autonomy={'reached': Autonomy.Low, 'planning_failed': Autonomy.High, 'control_failed': Autonomy.High},
										remapping={'joint_config': 'joints_observation_pose'})

			# x:67 y:303
			OperatableStateMachine.add('Get_Pipes_Pose',
										MonitorPerceptState(required_support=0, percept_class='pipes', track_percepts=False),
										transitions={'detected': 'Visualize_Pipes_Pose'},
										autonomy={'detected': Autonomy.Off},
										remapping={'object_id': 'object_id', 'object_pose': 'object_pose', 'object_data': 'object_data'})

			# x:59 y:396
			OperatableStateMachine.add('Visualize_Pipes_Pose',
										PublishPoseState(topic='/pipes/center_pose'),
										transitions={'done': 'finished'},
										autonomy={'done': Autonomy.Low},
										remapping={'pose': 'object_pose'})

			# x:72 y:210
			OperatableStateMachine.add('Detect_Pipes',
										PipeDetectionState(max_attempts=100),
										transitions={'found': 'Get_Pipes_Pose', 'unknown': 'failed'},
										autonomy={'found': Autonomy.Low, 'unknown': Autonomy.High})



		with _state_machine:
			# x:94 y:72
			OperatableStateMachine.add('Get_Pipes',
										_sm_get_pipes_6,
										transitions={'finished': 'Select_Pipe', 'failed': 'failed'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit},
										remapping={'object_pose': 'object_pose', 'object_data': 'object_data'})

			# x:492 y:328
			OperatableStateMachine.add('Move_To_Pregrasp',
										MoveitToJointsState(move_group="arm_group", joint_names=joints_arm_with_gripper[0:4], action_topic='/move_group'),
										transitions={'reached': 'EEF_To_Detected', 'planning_failed': 'failed', 'control_failed': 'failed'},
										autonomy={'reached': Autonomy.Low, 'planning_failed': Autonomy.High, 'control_failed': Autonomy.High},
										remapping={'joint_config': 'test_pregrasp'})

			# x:87 y:328
			OperatableStateMachine.add('Decide_Look_At',
										OperatorDecisionState(outcomes=['focus', 'skip'], hint="Should sensor head focus pipes?", suggestion='skip'),
										transitions={'focus': 'Look_At_Target', 'skip': 'Move_To_Pregrasp'},
										autonomy={'focus': Autonomy.Full, 'skip': Autonomy.High})

			# x:300 y:428
			OperatableStateMachine.add('Look_At_Target',
										LookAtWaypoint(),
										transitions={'reached': 'Move_To_Pregrasp', 'failed': 'failed'},
										autonomy={'reached': Autonomy.High, 'failed': Autonomy.Full},
										remapping={'waypoint': 'pipes_pose'})

			# x:94 y:222
			OperatableStateMachine.add('Select_Pipe',
										_sm_select_pipe_5,
										transitions={'finished': 'finished', 'next': 'Decide_Look_At'},
										autonomy={'finished': Autonomy.Inherit, 'next': Autonomy.Inherit},
										remapping={'index': 'index', 'object_pose': 'object_pose', 'object_data': 'object_data', 'pipe_pose': 'pipes_pose'})

			# x:783 y:322
			OperatableStateMachine.add('EEF_To_Detected',
										_sm_eef_to_detected_4,
										transitions={'finished': 'Select_Pipe', 'failed': 'Select_Pipe'},
										autonomy={'finished': Autonomy.Inherit, 'failed': Autonomy.Inherit},
										remapping={'pipes_pose': 'pipes_pose'})


		return _state_machine


	# Private functions can be added inside the following tags
	# [MANUAL_FUNC]
	def update_pose(self, pose, offset):
		new_pose = self._tf.transformPose('base_link', pose)
		new_pose.pose.position.x -= offset
		new_pose.pose.orientation.x = 0
		new_pose.pose.orientation.y = 0
		new_pose.pose.orientation.z = 0
		new_pose.pose.orientation.w = 1
		return new_pose
class RandPoseGenerator(EventState):
    '''
    Periodically generate geometry_msgs/PoseStamped messge in given parallelepiped. 
    Frames for parallelepiped is defined and the frame in which message is published can be different.

    -- topic        string          Topic where PoseStamped message should be published.
    -- duration     float           How long this state will be executed (seconds).
    -- interval     float[2]        Array of floats, maximal and minimal interval between movements.
    -- minXYZ       float[3]        Max values for x, y, z coordinates.
    -- maxXYZ       float[3]        Min values for x, y, z coordinates.
    -- frame_xyz    string          Coordinate frame of parallelepiped. 
    -- frame_out    string          Frame in which pose is publised.

    <= done 	                    Finished.
    <= failed 	                    Failed to activate FollowJointState controller.

    '''
    def __init__(self,
                 topic='motion/controller/look_at/in_pose_ref',
                 duration=120,
                 interval=[3, 5],
                 maxXYZ=[1, 0.3, 0.5],
                 minXYZ=[1.0, -0.3, 0.0],
                 frame_xyz='base_link',
                 frame_out='odom_combined'):
        super(RandPoseGenerator, self).__init__(outcomes=['done', 'failure'])

        # Store topic parameter for later use.
        if not isinstance(topic, str):
            raise ValueError("Topic name must be string.")
        if not isinstance(duration, (int, float)) or duration <= 0:
            raise ValueError("Duration must be positive number.")
        if len(interval) != 2 or any([
                not isinstance(t, (int, float)) for t in interval
        ]) or any([t < 0 for t in interval]) or interval[0] > interval[1]:
            raise ValueError("Interval must represent interval of time.")
        if len(minXYZ) != 3 or any(
            [not isinstance(v, (int, float)) for v in minXYZ]):
            raise ValueError("minXYZ: list of three numbers was expected.")
        if len(maxXYZ) != 3 or any(
            [not isinstance(v, (int, float)) for v in maxXYZ]):
            raise ValueError("maxXYZ: list of three numbers was expected.")
        if not isinstance(frame_xyz, str) or not isinstance(frame_out, str):
            raise ValueError("Frame names must be string.")

        self._topic = topic
        self._duration = Duration.from_sec(duration)
        self._interval = interval
        self._minXYZ = minXYZ
        self._maxXYZ = maxXYZ
        self._frame_in = frame_xyz
        self._frame_out = frame_out

        # create proxies
        self._publisher = ProxyPublisher({self._topic: PoseStamped})
        self._tf_listener = ProxyTransformListener().listener()
        self._tf_listener.waitForTransform(self._frame_out, self._frame_in,
                                           rospy.Time(), rospy.Duration(1))
        if not self._tf_listener.canTransform(self._frame_out, self._frame_in,
                                              rospy.Time(0)):
            raise ValueError(
                "Unable to perform transform between frames %s and %s." %
                (self._frame_out, self._frame_in))

        # state
        self._start_timestamp = None
        self._movement_timestamp = None
        self._movement_duration = Duration()

        # error in enter hook
        self._error = False

    def on_enter(self, userdata):
        self._error = False
        # set start timestamp
        self._start_timestamp = Time.now()
        self._movement_timestamp = Time.now()

        Logger.loginfo('Start random pose generation, topic `%s`.' %
                       self._topic)

    def execute(self, userdata):
        if self._error:
            return 'failure'

        time_now = Time.now()
        # check if time elasped
        if time_now - self._start_timestamp > self._duration:
            return 'done'
        # check if we have tosend new point
        if time_now - self._movement_timestamp > self._movement_duration:
            # determine new interval
            self._movement_timestamp = time_now
            self._movement_duration = Duration.from_sec(
                random.uniform(*self._interval))
            # form message
            msg = PoseStamped()
            msg.header.frame_id = self._frame_in
            msg.header.stamp = Time(0.0)
            # random position
            msg.pose.position.x = random.uniform(self._minXYZ[0],
                                                 self._maxXYZ[0])
            msg.pose.position.y = random.uniform(self._minXYZ[1],
                                                 self._maxXYZ[1])
            msg.pose.position.z = random.uniform(self._minXYZ[2],
                                                 self._maxXYZ[2])
            # transform to output frame
            try:
                # transform
                self._pose = self._tf_listener.transformPose(
                    self._frame_out, msg)
            except tf.Exception as e:
                Logger.logwarn('Unable to transform from %s to %s: %s' %
                               (self._frame_in, self._frame_out, e))
                return 'failure'
            # publish pose
            msg.header.stamp = self._movement_timestamp
            self._publisher.publish(self._topic, msg)

    def on_exit(self, userdata):
        Logger.loginfo('Done random pose generation.')
class BrohoofSM(Behavior):
	'''
	Move leg1 up to specified target, perform greeting, wait and pt leg down. 

Robot is assumed to be standing on four legs.
	'''


	def __init__(self):
		super(BrohoofSM, self).__init__()
		self.name = 'Brohoof'

		# parameters of this behavior
		self.add_parameter('wait_time', 5)
		self.add_parameter('neck_angle', 0.25)
		self.add_parameter('brohoof_cone', 0.78)
		self.add_parameter('brohoof_upper_limit', 0.30)

		# references to used behaviors

		# Additional initialization code can be added inside the following tags
		# [MANUAL_INIT]

                self._tf = ProxyTransformListener().listener()
		
		# [/MANUAL_INIT]

		# Behavior comments:



	def create(self):
		# x:228 y:396, x:225 y:240, x:1010 y:659
		_state_machine = OperatableStateMachine(outcomes=['finished', 'unreachable', 'failed'], input_keys=['pose'])
		_state_machine.userdata.pose = PoseStamped(Header(frame_id = 'base_link'), Pose(Point(0.4, 0.0, -0.05), Quaternion(0, 0, 0, 1)))

		# Additional creation code can be added inside the following tags
		# [MANUAL_CREATE]
		
		# [/MANUAL_CREATE]


		with _state_machine:
			# x:118 y:85
			OperatableStateMachine.add('CheckHandPosition',
										DecisionState(outcomes=['good','bad'], conditions=self.checkHandPosition),
										transitions={'good': 'GetHeadPose', 'bad': 'unreachable'},
										autonomy={'good': Autonomy.Off, 'bad': Autonomy.Off},
										remapping={'input_value': 'pose'})

			# x:890 y:253
			OperatableStateMachine.add('SayHello',
										TextCommandState(type='voice/play_wav', command='hello_im_sweetie_bot_friedship_programms', topic='control'),
										transitions={'done': 'Wait'},
										autonomy={'done': Autonomy.Off})

			# x:663 y:69
			OperatableStateMachine.add('RaiseHead',
										MoveitToJointsState(move_group='head', joint_names=['joint51', 'joint52', 'joint53', 'joint54'], action_topic='move_group'),
										transitions={'reached': 'RaiseLegProgram', 'planning_failed': 'failed', 'control_failed': 'failed'},
										autonomy={'reached': Autonomy.Off, 'planning_failed': Autonomy.Off, 'control_failed': Autonomy.Off},
										remapping={'joint_config': 'head_pose'})

			# x:309 y:66
			OperatableStateMachine.add('GetHeadPose',
										GetJointValuesState(joints=['joint51', 'joint52', 'joint53', 'joint54']),
										transitions={'retrieved': 'CalcRaisedHeadPose'},
										autonomy={'retrieved': Autonomy.Off},
										remapping={'joint_values': 'head_pose'})

			# x:485 y:73
			OperatableStateMachine.add('CalcRaisedHeadPose',
										CalculationState(calculation=self.calculateHeadPoseFunc),
										transitions={'done': 'RaiseHead'},
										autonomy={'done': Autonomy.Off},
										remapping={'input_value': 'head_pose', 'output_value': 'head_pose'})

			# x:891 y:65
			OperatableStateMachine.add('RaiseLegProgram',
										ExecuteJointTrajectory(action_topic='motion/controller/joint_trajectory', trajectory_param='brohoof_begin', trajectory_ns='/saved_msgs/joint_trajectory'),
										transitions={'success': 'SayHello', 'partial_movement': 'failed', 'invalid_pose': 'failed', 'failure': 'failed'},
										autonomy={'success': Autonomy.Off, 'partial_movement': Autonomy.Off, 'invalid_pose': Autonomy.Off, 'failure': Autonomy.Off},
										remapping={'result': 'result'})

			# x:510 y:396
			OperatableStateMachine.add('ReturnLegProgrammed',
										ExecuteJointTrajectory(action_topic='motion/controller/joint_trajectory', trajectory_param='brohoof_end', trajectory_ns='/saved_msgs/joint_trajectory'),
                                                                                transitions={'success': 'finished', 'partial_movement': 'failed', 'invalid_pose': 'failed', 'failure': 'failed'},
										autonomy={'success': Autonomy.Off, 'partial_movement': Autonomy.Off, 'invalid_pose': Autonomy.Off, 'failure': Autonomy.Off},
										remapping={'result': 'result'})

			# x:851 y:399
			OperatableStateMachine.add('Wait',
										WaitState(wait_time=self.wait_time),
										transitions={'done': 'ReturnLegProgrammed'},
										autonomy={'done': Autonomy.Off})


		return _state_machine


	# Private functions can be added inside the following tags
	# [MANUAL_FUNC]
        def calculateHeadPoseFunc(self, joints):
	        joints = list(joints)
	        joints[0] = 0.0
	        joints[2] = self.neck_angle
	        return joints

	def checkHandPosition(self, input_pose):
	        '''
	        Check if hand is in good position for brohoof. Return 'good' or 'bad'.
	        '''
	        # check if frame header presents
	        if not input_pose.header.frame_id:
	            Logger.logerr('checkHandPosition: Header is missing.')
	            return 'bad'
	        # convert ot base_link frame
	        try:
	            output_pose = self._tf.transformPose('base_link', PoseStamped(Header(frame_id = input_pose.header.frame_id), input_pose.pose))
	        except tf.Exception as e:
	            Logger.logerr('calculateHeadPoseFunc: Cannot transform from `%s` to `base_link` frame.' % input_pose.header.frame_id)
	            return 'bad'
	        pos = output_pose.pose.position
	        Logger.loginfo('calculateHeadPoseFunc: object pos: %s' % str(pos))
	        # Check if boundarie are good
	        if pos.z > self.brohoof_upper_limit or pos.z < -0.15: 
	            # too high or to low
	            return 'bad'
	        if pos.x < 0.25:
	            # too close
                    return 'bad'
                # Move to shoulder1 point
                pos.x -= 0.080
                pos.y -= 0.037
                pos.z += 0.027
                # Check if angle is out of cone
                if abs(math.atan2(pos.y,pos.x)) > self.brohoof_cone:
                    # out of cone
                    return 'bad'
	        return 'good'