예제 #1
0
 def check_right_free(self, return_coords: bool = False):
     abs_degree = (self.cur_direction.value * 90 +
                   OT.orientation_to_degree[Orientation.EAST]) % 360
     displacement = OT.orientation_to_unit_displacement(
         OT.degree_to_orientation[abs_degree])
     right_coord = self.cur_coord.add(displacement)
     if return_coords:
         displacement = OT.orientation_to_unit_displacement(
             OT.degree_to_orientation[abs_degree]).multiply(2)
         viewed_cell = self.cur_coord.add(displacement)
         return viewed_cell
     else:
         if self.arena.coord_is_valid(
                 right_coord
         ) and not self.arena.get_cell_at_coord(right_coord).is_dangerous():
             return True
         else:
             displacement = OT.orientation_to_unit_displacement(
                 OT.degree_to_orientation[abs_degree]).multiply(2)
             viewed_cell = self.cur_coord.add(displacement)
             if self.arena.coord_is_valid(
                     viewed_cell) and self.arena.get_cell_at_coord(
                         viewed_cell).is_obstacle():
                 adj_obstacle = viewed_cell
                 surface_orientation = (abs_degree + 180) % 360
                 self.arena.get_cell_at_coord(
                     adj_obstacle).set_seen_surface(surface_orientation)
                 self.arena.get_cell_at_coord(adj_obstacle).set_is_seen(
                     True)
             return False
예제 #2
0
    def calculate_move(self, current_coord, target_coord) -> MoveCommand:
        displacement = target_coord.subtract(current_coord)
        target_orientation = OT.displacement_to_orientation(displacement)
        turn_angle = OT.calc_degree_of_turn(self.robot_info.get_orientation(),
                                            target_orientation)

        # update expected robot info
        self.expected_robot_info = RobotInfo(target_coord, target_orientation)

        return MoveCommand(turn_angle, displacement.manhattan_distance())
    def step(self):
        # calculate agent percepts
        sis = SensorInputSimulation(self.robot_info, self.arena)
        obstacle_coord_list, no_obs_coord_list = sis.calculate_percepts()
        for coord in obstacle_coord_list:
            self.arena.get_cell_at_coord(coord).set_is_explored(True)
        for coord in no_obs_coord_list:
            self.arena.get_cell_at_coord(coord).set_is_explored(True)
        self.arena.get_cell_at_coord(
            self.robot_info.get_coord()).set_is_visited(True)
        # get agent next move
        agent_output = self.agent.step(obstacle_coord_list, no_obs_coord_list,
                                       self.robot_info)
        print(agent_output.get_message())
        move_command = agent_output.get_move_command()
        if move_command == None:
            self.quit()

        # update internal representation of robot
        new_orientation = OrientationTransform.calc_orientation_after_turn(
            self.robot_info.get_orientation(), move_command.get_turn_angle())

        if new_orientation != self.robot_info.get_orientation():
            if abs(new_orientation.value -
                   self.robot_info.get_orientation().value) == 1 or abs(
                       new_orientation.value -
                       self.robot_info.get_orientation().value) == 3:
                self.robot_info.set_orientation(new_orientation)
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()
                time.sleep(self.speed)
            elif abs(new_orientation.value -
                     self.robot_info.get_orientation().value) == 2:
                self.robot_info.set_orientation(
                    Orientation((new_orientation.value - 1) % 3))
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()
                time.sleep(self.speed)
                self.robot_info.set_orientation(new_orientation)
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()
                time.sleep(self.speed)

        unit_move = OrientationTransform.orientation_to_unit_displacement(
            new_orientation)
        # move = unit_move.multiply(move_command.get_cells_to_advance()) # enable this if robot can move multiple squares
        move = unit_move  # enable this if robot can move one square at a time
        self.robot_info.set_coord(self.robot_info.get_coord().add(move))

        # update pygame display
        self.update_display()
예제 #4
0
 def main_sensor_parser(sensor_dict, robot_info):
     sensor_data = sensor_dict['data']
     cur_coord = robot_info.get_coord()
     orientation = robot_info.get_orientation()
     # cur_coord = Coord(6, 6)
     # orientation = Orientation.EAST
     obstacleList = []
     exploredList = []
     i = 0
     for key, val in SENSOR_CONSTANTS.items():
         sensor_abs_degree = (val['direction'] +
                              OT.orientation_to_degree[orientation]) % 360
         string1 = 'displacement_' + str(orientation.value)
         displacement_per_step = OT.orientation_to_unit_displacement(
             OT.degree_to_orientation[sensor_abs_degree])
         obstacleList.extend(
             SensorParser.individual_sensor_parser(cur_coord, val[string1],
                                                   displacement_per_step,
                                                   sensor_data[key],
                                                   val['range'])[0])
         exploredList.extend(
             SensorParser.individual_sensor_parser(cur_coord, val[string1],
                                                   displacement_per_step,
                                                   sensor_data[key],
                                                   val['range'])[1])
         i += 1
     # for item in obstacleList:
     #     for j in item:
     #         print(j.get_x(), j.get_y())
     # print("Break")
     # for i in exploredList:
     #     for z in i:
     #         print(z.get_x(), z.get_y())
     return obstacleList, exploredList
예제 #5
0
 def move_back(self) -> Coord:
     abs_degree = (self.cur_direction.value * 90 +
                   OT.orientation_to_degree[Orientation.SOUTH]) % 360
     displacement = OT.orientation_to_unit_displacement(
         OT.degree_to_orientation[abs_degree])
     back_coord = self.cur_coord.add(displacement)
     return back_coord
예제 #6
0
 def move_right(self) -> Coord:
     abs_degree = (self.cur_direction.value * 90 +
                   OT.orientation_to_degree[Orientation.EAST]) % 360
     displacement = OT.orientation_to_unit_displacement(
         OT.degree_to_orientation[abs_degree])
     right_coord = self.cur_coord.add(displacement)
     return right_coord
예제 #7
0
 def move_forward(self) -> Coord:
     abs_degree = (self.cur_direction.value * 90 +
                   OT.orientation_to_degree[Orientation.NORTH]) % 360
     displacement = OT.orientation_to_unit_displacement(
         OT.degree_to_orientation[abs_degree])
     front_coord = self.cur_coord.add(displacement)
     return front_coord
예제 #8
0
 def check_right_free(self, return_coords: bool = False):
     abs_degree = (self.cur_direction.value * 90 +
                   OT.orientation_to_degree[Orientation.EAST]) % 360
     displacement = OT.orientation_to_unit_displacement(
         OT.degree_to_orientation[abs_degree])
     right_coord = self.cur_coord.add(displacement)
     if return_coords:
         displacement = OT.orientation_to_unit_displacement(
             OT.degree_to_orientation[abs_degree]).multiply(2)
         viewed_cell = self.cur_coord.add(displacement)
         return viewed_cell
     else:
         if self.arena.coord_is_valid(
                 right_coord
         ) and not self.arena.get_cell_at_coord(right_coord).is_dangerous():
             return True
         else:
             return False
예제 #9
0
    def update_robot_info(self, move_command):
        # update internal representation of robot
        new_orientation = OrientationTransform.calc_orientation_after_turn(self.robot_info.get_orientation(), move_command.get_turn_angle())
        
        if new_orientation != self.robot_info.get_orientation():
            if abs(new_orientation.value - self.robot_info.get_orientation().value) == 1 or abs(new_orientation.value - self.robot_info.get_orientation().value) == 3:
                self.robot_info.set_orientation(new_orientation)
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()
            elif abs(new_orientation.value - self.robot_info.get_orientation().value) == 2:
                self.robot_info.set_orientation(Orientation((new_orientation.value-1)%3))
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()
                self.robot_info.set_orientation(new_orientation)
                self.robot_info.set_coord(self.robot_info.get_coord())
                self.update_display()

        unit_move = OrientationTransform.orientation_to_unit_displacement(new_orientation)
        move = unit_move.multiply(move_command.get_cells_to_advance()) # enable this if robot can move multiple squares
        self.robot_info.set_coord(self.robot_info.get_coord().add(move))
예제 #10
0
    def move_back(self) -> Coord:
        abs_degree = (self.cur_direction.value * 90 +
                      OT.orientation_to_degree[Orientation.SOUTH]) % 360
        displacement = OT.orientation_to_unit_displacement(
            OT.degree_to_orientation[abs_degree])
        back_coord = self.cur_coord.add(displacement)

        obstacle_cell_abs_degree = (abs_degree + 90) % 360
        obstacle_cell = self.cur_coord.add(
            OT.orientation_to_unit_displacement(
                OT.degree_to_orientation[obstacle_cell_abs_degree]).multiply(
                    2))
        if self.arena.coord_is_valid(
                obstacle_cell) and self.arena.get_cell_at_coord(
                    obstacle_cell).is_obstacle():
            surface_orientation = (obstacle_cell_abs_degree + 180) % 360
            self.arena.get_cell_at_coord(obstacle_cell).set_seen_surface(
                surface_orientation)
            self.arena.get_cell_at_coord(obstacle_cell).set_is_seen(True)

        return back_coord
예제 #11
0
    def get_agent_output_list(self) -> list:
        # Calculate fastest path of coords
        coords_list = []
        cl_to_waypoint = self.algo.get_next_step(self.arena,
                                                 self.robot_info,
                                                 self.end_coord,
                                                 self.waypoint_coord,
                                                 full_path=True)
        last_displacement = cl_to_waypoint[-1].subtract(cl_to_waypoint[-2])
        last_orientation = OT.displacement_to_orientation(last_displacement)
        robot_info_at_waypoint = RobotInfo(cl_to_waypoint[-1],
                                           last_orientation)
        cl_to_end = self.algo.get_next_step(self.arena,
                                            robot_info_at_waypoint,
                                            self.end_coord,
                                            None,
                                            full_path=True)
        coords_list.extend(cl_to_waypoint)
        coords_list.extend(cl_to_end)

        return self.calc_agent_output_full_path(coords_list)
예제 #12
0
    def calculate_percepts(
        self
    ) -> list:  # this function calculates the coords of ALL cells in the visible range (including those behind obstacles)
        orientation = self.robot_info.get_orientation()
        cur_coord = self.robot_info.get_coord()

        # cells within robot 3x3 are obviously explored and not obstacles
        # self.no_obs_coord_list.extend([(coord, 1) for coord in self.arena.get_eight_adjacent_in_arena(cur_coord)]) # distance is 1
        # self.no_obs_coord_list.append((cur_coord, 0)) # distance is 0

        for sensor in SENSOR_CONSTANTS.values():
            sensor_abs_degree = (sensor['direction'] +
                                 OT.orientation_to_degree[orientation]) % 360
            displacement_per_step = OT.orientation_to_unit_displacement(
                OT.degree_to_orientation[sensor_abs_degree])
            sensor_displacement_key = 'displacement_' + str(
                orientation.value)  # key changes based on orientation of robot
            cil = self.get_coords_in_line(sensor[sensor_displacement_key],
                                          displacement_per_step,
                                          sensor['range'])
            self.update_explored_coord_lists(cil)

        return self.obstacles_coord_list, self.no_obs_coord_list
    def get_fastest_path(self, arena: Arena, robot_info: RobotInfo, end: Coord, waypoint:Coord=None):
        start = robot_info.get_coord()
        start_orientation = robot_info.get_orientation()
        if not arena.coord_is_valid(end):
            raise Exception(f'FastestPath: end coord out of arena: {end.get_x()}, {end.get_y()}')
        end_cell = arena.get_cell_at_coord(end)
        if end_cell.is_obstacle():
            raise Exception(f'FastestPath: cannot move to obstacle cell: {end.get_x()}, {end.get_y()}')

        if waypoint:
            # we haven't passed through it yet
            target = waypoint
        else:
            target = end

        root = DecisionNode(start, start_orientation, exact_cost=0, parent=None)
        fringe_nodes = PriorityQueue()
        queue_tie_breaker = 0
        fringe_nodes.put((
            FastestPathAlgo.heuristic(root.get_coord(), target),
            queue_tie_breaker,
            root
        ))
        examined = [[False for y in range(MAP_ROW)] for x in range(MAP_COL)]

        cur = fringe_nodes.get()[-1]
        while True:
            # two conditions to exit loop, one may or may not be enabled
            cur_coord = cur.get_coord()
            cur_orientation = cur.get_orientation()
            if not end_cell.is_dangerous():
                # normally exit when target is found
                if cur_coord.is_equal(target):
                    # found target so break and find first step
                    break
            else:
                # if cell is dangerous, move to any adjacent cell to it \
                # (some cells, surrounded by danger, will be left out, but they are likely to be obstacles)
                if cur_coord.subtract(target).manhattan_distance() <= 1 \
                    and cur_coord.subtract(start).manhattan_distance() > 0:
                    # target not found so return None
                    return None
                if fringe_nodes.qsize() >= 3000:
                    # if we've got such a long queue, there's probably no way to the target
                    return None
            examined[cur_coord.get_x()][cur_coord.get_y()] = True
            adjacent_coords = arena.get_adjacent_safe(cur_coord)
            for coord in adjacent_coords:
                if examined[coord.get_x()][coord.get_y()]:
                    # assume heuristic is admissible, otherwise need to assess total_cost \
                    # and remove node from examined set if g+h < existing g
                    continue
                # get costs
                target_orientation = OrientationTransform.displacement_to_orientation(coord.subtract(cur_coord))
                degree_of_turn = OrientationTransform.calc_degree_of_turn(cur_orientation, target_orientation)
                turning_cost = int(degree_of_turn/90)*TimeCosts.QUARTER_TURN
                displacement_cost = TimeCosts.MOVE_ONE_UNIT
                cost = turning_cost + displacement_cost
                exact_cost = cur.get_exact_cost() + cost
                estimated_cost = FastestPathAlgo.heuristic(cur_coord, target)
                total_cost = exact_cost + estimated_cost
                fringe_node = DecisionNode(coord, target_orientation, exact_cost=exact_cost, parent=cur)
                queue_tie_breaker += 1
                fringe_nodes.put((total_cost, queue_tie_breaker, fringe_node))

            if fringe_nodes.empty():
                return None
            cur = fringe_nodes.get()[-1]

        cur_list = []
        while cur.get_parent() and not cur.get_parent().get_coord().is_equal(start):
            cur_list.append(cur)
            cur = cur.get_parent()
        cur_list.append(cur)
        cur_list.reverse()

        return cur_list