def __init__(self, conf):
        logger = logging.getLogger('SimulationMultigoal')
        logger.info('Initializing simulation')

        self.conf = conf

        # for readability
        self.pop_size = conf.pop_size
        self.map = conf.map
        self.robot = conf.robot
        self.max_distance = math.sqrt((self.map.plane.shape[0]**2) +
                                      (self.map.plane.shape[1]**2))
        self.s_to_t_distance = utils.point_distance(
            conf.map.start_point[0, 0, :].tolist(),
            conf.map.end_point[0, 0, :].tolist())

        self.fitnesses = None
        self.net_ids = None
        self.robot_angles = None
        self.sensor_angles = None
        self.robot_positions = None
        self.robot_bodies = None
        self.sensor_lines = None
        self.angle_errors = None
        self.normalized_angle_errors = None
        self.target_distances = None
        self.normalized_target_distances = None
        self.max_distance_from_start = None
        self.nets = None
 def update(self, _origin):
     """Update the laser's position."""
     self.origin = _origin
     self.angle = self.find_angle(_origin, self.destination)
     self.length = utils.point_distance(_origin[0], self.destination[0],
                                        _origin[1], self.destination[1])
     self.polar = (self.length, self.angle)
    def __init__(self, _p_screen, _p_world):
        pygame.sprite.Sprite.__init__(self)
        self.screen = _p_screen
        self.world = _p_world
        self.image = pygame.image.load("robot.png")
        self.robot_size = 50
        self.image = pygame.transform.smoothscale(self.image,
                                                  (self.robot_size, self.robot_size))
        self.image = pygame.transform.rotate(self.image, 90)
        self.image_size = self.image.get_size()
        self.og_image = self.image.copy()
        self.rect = self.image.get_rect()
        self.x_pos = float(self.screen.get_size()[0] / 2)
        self.y_pos = float(self.screen.get_size()[1] / 2)
        self.angle = 0
        self.rect.center = (self.x_pos, self.y_pos)
        self.hitbox = pygame.Rect(self.x_pos - (self.image_size[0] / 2),
                                  self.y_pos - (self.image_size[1] / 2),
                                  self.image_size[0] + 2,
                                  self.image_size[1] + 2)
        self.mask = pygame.mask.from_surface(self.image)
        self.draw_lidar = True

        # Lidar setup
        self.sample_rate = 5  # Hz
        self.lidar_state = 0
        self.sample_count = 32
        self.angle_ref = []
        self.new_sample = True

        self.initial_laser_length = int(utils.point_distance(self.screen.get_width(), 0,
                                                             self.screen.get_height(), 0))
Example #4
0
 def __read_sensors(self):
     readings = np.zeros((len(self.sensor_lines[0]), len(self.sensor_lines))) + self.robot.sensor_len
     for robot in range(0, len(self.sensor_lines)):
         for sensor in range(0, len(self.sensor_lines[robot])):
             for line_point in self.sensor_lines[robot][sensor]:
                 if self.sim_map.plane[line_point[0], line_point[1]] != 1:  # 1 means free
                     # calc distance from start of the sensor line to point of contact
                     readings[sensor, robot] = utils.point_distance(self.sensor_lines[robot][sensor][0], line_point)
                     break
     readings = self.__normalize_sensor_readings(readings)
     return readings
Example #5
0
 def is_at_position(self, position):
     return utils.point_distance(position,
                                 self.get_position()) <= self.radius
Example #6
0
 def is_at_position(self, position):
     return utils.point_distance(position, self.get_position()) <= self.radius
Example #7
0
    def world_editor(self, _mouse_click, _pos):
        """Draw onto the world grid if mouse is down and draw the current world grid."""
        def world_editor_button_hover(_bh_pos):
            """Return true if the position is within any of the world editor buttons."""
            _return = np.array([
                self.we_clear_btn.hover_point(_bh_pos[0], _bh_pos[1]),
                self.we_done_btn.hover_point(_bh_pos[0], _bh_pos[1]),
                self.we_mode_btn.hover_point(_bh_pos[0], _bh_pos[1])
            ])
            return _return.any()

        def world_editor_centre_hover(_ch_pos):
            """Return true if the position is within where the robot will spawn."""
            _hor_cen = self.screen.get_width() / 2
            _vert_cen = self.screen.get_height() / 2
            _robot_size = self.robot.robot.robot_size
            _return = np.array([
                _ch_pos[0] > _hor_cen - _robot_size,
                _ch_pos[0] < _hor_cen + _robot_size,
                _ch_pos[1] < _vert_cen + _robot_size,
                _ch_pos[1] > _vert_cen - _robot_size
            ])
            return _return.all()

        def pos_to_grid(_pos):
            """Converts game space coordinates to world map grid coordinates."""
            return int(_pos / self.world.size)

        if _mouse_click:
            if self.world.world_type == "Occupancy Grid" or not self.we_draw_mode:
                # If in Occupancy Grid mode, find the distance between the last known mouse
                # position and find the points in a line between them
                if self.last_mouse_pos != None:
                    _last_point_dis = utils.point_distance(
                        self.last_mouse_pos[0], _pos[0], _pos[1],
                        self.last_mouse_pos[1])
                else:
                    _last_point_dis = 0
                # If clicking on a button don't draw anything
                if (_last_point_dis < 8 and world_editor_button_hover(_pos)
                    ) or _last_point_dis == 0:
                    _line = []
                else:
                    _line = utils.line_between(self.last_mouse_pos[0],
                                               self.last_mouse_pos[1], _pos[0],
                                               _pos[1])
                # Write to the grid map all the points on the line if not in the spawn space
                for _point in _line:
                    if not world_editor_centre_hover(_point):
                        self.world.write_to_map(self.we_draw_mode,
                                                pos_to_grid(_point[0]),
                                                pos_to_grid(_point[1]))
                self.last_mouse_pos = _pos
            elif self.world.world_type == "Landmarks":
                # If in landmark mode, only place one wall per click
                if self.we_raise_click:
                    if not world_editor_centre_hover(_pos):
                        self.world.write_to_map(self.we_draw_mode,
                                                pos_to_grid(_pos[0]),
                                                pos_to_grid(_pos[1]))
                        self.we_raise_click = False

        for i in range(len(self.world.grid)):
            for j in range(len(self.world.grid[0])):
                if self.world.grid[i][j]:
                    pygame.draw.rect(
                        self.screen, (0, 0, 0),
                        pygame.Rect((j * self.world.size, i * self.world.size),
                                    (self.world.size, self.world.size)))
    def collision_detector(self):
        """Finds if the robot is colliding and the associated side.

        This function uses sprites to determine all of the objects the robot is colliding with,
        then finds the closest wall to determine which side of the robot is colliding. To solve for
        cases where the robot is colliding with two walls simultaneously, the function utilises
        recursion to find the second closest wall.
        """
        _collision_list = pygame.sprite.spritecollide(self.robot,
                                                      self.world.wall_list,
                                                      False,
                                                      pygame.sprite.collide_mask)
        if len(_collision_list) > 0:
            # Find the closest colliding wall
            _closest_distance = self.robot.initial_laser_length
            _closest_wall = None
            for _wall in _collision_list:
                cur_distance = utils.point_distance(self.robot.x_pos,
                                                    _wall.rect.center[0],
                                                    self.robot.y_pos,
                                                    _wall.rect.center[1])
                if cur_distance < _closest_distance:
                    s_closest_wall = _closest_wall
                    _closest_wall = _wall
                    _closest_distance = cur_distance
            # If performing recursion, find the second closest wall
            if self.recursion_depth > 0 and not s_closest_wall is None:
                _closest_wall = s_closest_wall
            _wall = _closest_wall

            # Find which side of the robot is closest to the closest wall
            _sides = [self.robot.hitbox.midtop, self.robot.hitbox.midright,
                      self.robot.hitbox.midbottom, self.robot.hitbox.midleft]
            _closest_side = -1
            _closest_side_distance = self.robot.initial_laser_length
            for _i, _side in enumerate(_sides):
                distance = utils.point_distance(_side[0],
                                                _wall.rect.center[0],
                                                _side[1],
                                                _wall.rect.center[1])
                if distance < _closest_side_distance:
                    _closest_side_distance = distance
                    _closest_side = _i
            _to_return = None
            if _closest_side == 0:
                _to_return = "TOP"
            if _closest_side == 1:
                _to_return = "RIGHT"
            if _closest_side == 2:
                _to_return = "BOTTOM"
            if _closest_side == 3:
                _to_return = "LEFT"

            # If the robot is already colliding with a wall, collide the second closest wall
            if len(self.collision_list) > 0:
                if _to_return == self.collision_list[len(self.collision_list) - 1]:
                    if self.recursion_depth <= 1:
                        self.recursion_depth += 1
                        return self.collision_detector()
            self.recursion_depth = 0
            return _to_return
        return None
    def lidar(self):
        """Performs all calculations for laser range finding and handles the drawing of lasers.

        This function uses sprites to determine all of the objects each laser around the robot is
        colliding with, then finds the closest wall. It then finds the closest point on that wall
        to the robot.
        """
        # TODO: Fix flickering on some diagonal lasers
        # TODO: Make lasers that don't find a result return max length instead of previous result
        _iterations_per_frame = int(
            self.sample_count / (30 / self.sample_rate))
        _slice_from = self.lidar_state * _iterations_per_frame
        if self.lidar_state == (30 // self.sample_rate) - 2:
            # Ensure final slice gets the remainder
            _slice_to = self.sample_count
        else:
            _slice_to = _slice_from + _iterations_per_frame
        # Update the position of each of the laser sprites in self.lasers
        _lidar = pygame.math.Vector2()
        _lidar.xy = (self.x_pos, self.y_pos)
        for _sprite in self.lasers.sprites()[_slice_from:_slice_to]:
            _sprite.origin = _lidar
            _sprite.update()

        # Check wall collisions in quadrants
        _quad_list = [[[0, 90], operator.ge, operator.ge],
                      [[90, 181], operator.lt, operator.ge],
                      [[-90, 0], operator.ge, operator.lt],
                      [[-181, -90], operator.lt, operator.lt]]
        _collision_list = {}
        _pixel_buffer = self.world.size * 2
        for _quad in _quad_list:
            _quad_lasers = pygame.sprite.Group()
            _quad_walls = pygame.sprite.Group()
            for _laser in self.lasers.sprites()[_slice_from:_slice_to]:
                _cur_angle = int(_laser.angle.as_polar()[1])
                if _cur_angle >= _quad[0][0] and _cur_angle < _quad[0][1]:
                    _quad_lasers.add(_laser)
            for _wall in self.world.wall_list:
                _cur_pos = _wall.rect.center
                if _quad[1] == operator.ge:
                    _x_buf = self.x_pos - _pixel_buffer
                else:
                    _x_buf = self.x_pos + _pixel_buffer
                if _quad[2] == operator.ge:
                    _y_buf = self.y_pos - _pixel_buffer
                else:
                    _y_buf = self.y_pos + _pixel_buffer
                if _quad[1](_cur_pos[0], _x_buf):
                    if _quad[2](_cur_pos[1], _y_buf):
                        _quad_walls.add(_wall)
            _collision_list.update(pygame.sprite.groupcollide(_quad_lasers,
                                                              _quad_walls,
                                                              False,
                                                              False,
                                                              pygame.sprite.collide_mask))

        if _collision_list:
            for _laser in _collision_list:
                # For each laser, find the closest wall to the robot it is colliding with
                _closest_wall = None
                _closest_distance = self.initial_laser_length
                for _wall in _collision_list[_laser]:
                    cur_distance = utils.point_distance(self.x_pos,
                                                        _wall.rect.center[0],
                                                        self.y_pos,
                                                        _wall.rect.center[1])
                    if cur_distance < _closest_distance:
                        _closest_wall = _wall
                        _closest_distance = cur_distance

                # Find the closest point on the closest wall to the robot
                _current_pos = pygame.math.Vector2()
                _current_pos.update(self.x_pos, self.y_pos)
                _heading = _laser.angle
                _direction = _heading.normalize()
                _closest_point = [self.initial_laser_length,
                                  self.initial_laser_length]
                for _ in range(self.initial_laser_length):
                    _current_pos += _direction
                    if _closest_wall.rect.collidepoint(_current_pos):
                        _r = np.sqrt(np.square(self.x_pos - _current_pos.x)
                                     + np.square(self.y_pos - _current_pos.y))
                        _theta = np.arctan2(-(self.y_pos - _current_pos.y), -
                                            (self.x_pos - _current_pos.x))
                        _closest_point = [_r, _theta]
                        break

                # Write resulting point to the point cloud
                if not _closest_point == [self.initial_laser_length, self.initial_laser_length]:
                    _cur_angle = (round(_heading.as_polar()[1]) + 450) % 360
                    try:
                        self.point_cloud[self.angle_ref.index(
                            _cur_angle)] = _closest_point
                    except ValueError:
                        pass

        if self.lidar_state == (30 // self.sample_rate) - 1:
            self.new_sample = True
            self.lidar_state = 0
        else:
            self.lidar_state += 1