Example #1
0
class Core:
    def __init__(self):
        self.state = State.Init
        self.config = {
            'hover_height':
            1.0,

            # States for which movement.fix_hover() will NOT be called (to make sure the drone is at `hover_height`)
            'exclude_from_fix_hover': [
                State.Init,
                State.Takeoff,
                State.Land,
                State.Done,
            ],

            # Radius in meters around a blacklisted goal that the robot will ignore
            'blacklisted_goal_radius':
            2.0
        }

        self.store = DataStore()
        self.movement = MovementHandler(core=self, datastore=self.store)
        self.actions = Actions(core=self,
                               datastore=self.store,
                               movement_handler=self.movement)
        self.planner = Planner(core=self,
                               datastore=self.store,
                               movement_handler=self.movement)

        # Aux files
        self.temp_data = {}
        self.last_goal = None

    def handle_state(self, state):
        """
        :param state: Current state
        :return: Returns either next state or None (i.e. stay in the same state)
        """

        if state == State.Init:

            # Make sure there are no lingering goals
            self.planner.cancel_all_goals()

            return State.WaitingForData

        elif state == State.WaitingForData:
            self.store.wait_for_data()
            return State.Takeoff

        elif state == State.Takeoff:
            return State.ExploreStart if self.actions.takeoff() else None

        elif state == State.ExploreStart:
            return State.FullRadialScan

        elif state == State.FullRadialScan:
            fr_scan_start = self.temp_data.get('fr_scan_start')
            if fr_scan_start is None:
                fr_scan_start = rospy.Time.now()
                self.temp_data['fr_scan_start'] = fr_scan_start

            done = self.actions.full_radial_scan(start_time=fr_scan_start)
            if done:
                self.temp_data['fr_scan_start'] = None
                return State.FindGoal
            else:
                return None

        elif state == State.FindGoal:
            goal = self.planner.find_goal()
            if goal is None:
                rospy.loginfo(
                    'Cannot find any more goals, finishing exploration.')
                return State.ExplorationFinish
            if goal == self.last_goal:
                rospy.loginfo(
                    'The new goal is the same as the old goal, finishing exploration.'
                )
                return State.ExplorationFinish

            self.last_goal = goal
            x_coord, y_coord, yaw = goal
            self.planner.publish_goal(x_coord, y_coord, yaw)
            return State.TravelToGoal

        elif state == State.TravelToGoal:
            if self.planner.travel_to_goal():
                self.planner.cancel_all_goals()
                return State.FullRadialScan
            else:
                return None

        elif state == State.ExplorationFinish:
            self.planner.cancel_all_goals()
            return State.Land

        elif state == State.Land:
            return State.Done if self.actions.land() else None

        rospy.logwarn('Unrecognised state `{}` detected - ignoring.'.format(
            State(state).name))
        return None

    def step(self):

        self.store.step()

        current_state = self.state
        self.movement.start_step(current_state)
        next_state = self.handle_state(current_state)

        if next_state is not None:
            if next_state != current_state:
                rospy.loginfo('[?] Switching state from {} to {}'.format(
                    State(current_state).name,
                    State(next_state).name))
            self.state = next_state

        self.movement.finish_step()
        return next_state