Пример #1
0
def simulate(batch_file, preset_filename, bot_paths, seed, override_settings,
             *queues_sizes):
    result_queue = queues_sizes[0][0]
    result_queue._internal_size = queues_sizes[0][1]
    StateHandler.instance.shared_info = {
        "result_queue": result_queue,
    }
    send_queues = [q for q, _ in queues_sizes[1::2]]
    for i, (_, size) in enumerate(queues_sizes[1::2]):
        send_queues[i]._internal_size = size
    recv_queues = [q for q, _ in queues_sizes[2::2]]
    for i, (_, size) in enumerate(queues_sizes[2::2]):
        recv_queues[i]._internal_size = size

    Randomiser.createGlobalRandomiserWithSeed(seed)

    preset_file = find_abs(preset_filename, allowed_areas=preset_locations())
    with open(preset_file, "r") as f:
        config = yaml.safe_load(f)
    config["settings"] = config.get("settings", {})
    recursive_merge(config["settings"], override_settings)

    config["robots"] = config.get("robots", []) + bot_paths

    initialiseFromConfig(config, send_queues, recv_queues)
Пример #2
0
 def resetPositions(self):
     for team in range(len(self.spawns)):
         for index in range(self.BOTS_PER_TEAM):
             actual_index = team + index * len(self.spawns)
             if actual_index >= len(self.robots):
                 break
             # Generate a uniformly random point in radius of spawn for bot.
             diff_radius = Randomiser.random() * self.BOT_SPAWN_RADIUS
             diff_angle = Randomiser.random() * 2 * np.pi
             self.robots[actual_index].body.position = [
                 self.spawns[team][index][0][0] +
                 diff_radius * np.cos(diff_angle),
                 self.spawns[team][index][0][1] +
                 diff_radius * np.sin(diff_angle),
             ]
             self.robots[actual_index].body.angle = self.spawns[team][
                 index][1] * np.pi / 180
             self.robots[actual_index].body.velocity = (0.0, 0.0)
             self.robots[actual_index].body.angular_velocity = 0
     # Generate position for ball.
     diff_radius = Randomiser.random() * self.BALL_SPAWN_RADIUS
     diff_angle = Randomiser.random() * 2 * np.pi
     ScriptLoader.instance.object_map["IR_BALL"].body.position = [
         diff_radius * np.cos(diff_angle),
         diff_radius * np.sin(diff_angle) - 18,
     ]
     ScriptLoader.instance.object_map["IR_BALL"].body.velocity = (0.0, 0.0)
     for idx in range(len(self.bot_penalties)):
         if self.bot_penalties[idx] > 0:
             self.finishPenalty(idx)
Пример #3
0
 def connectDevices(self):
     self.devices = {}
     for interactor in ScriptLoader.instance.object_map[
             self.robot_key].device_interactors:
         self.devices[interactor.port] = interactor.device_class
         interactor.port_key = f"{self.filename}-{self.path_index}-{interactor.port}"
         Randomiser.createPortRandomiserWithSeed(interactor.port_key)
     ScriptLoader.instance.object_map[
         self.robot_key].robot_class = self.robot_class
Пример #4
0
    def _DistanceFromSensor(self, startPosition, centreRotation):
        top_length = self.MAX_RAYCAST
        while top_length > 0:
            endPosition = startPosition + top_length * np.array(
                [np.cos(centreRotation),
                 np.sin(centreRotation)])
            # Ignore all ignored objects by setting the category on them.
            cats = []
            for obj in self.ignore_objects:
                if isinstance(obj, PhysicsObject):
                    for shape in obj.shapes:
                        cats.append(shape.filter.categories)
                        shape.filter = pymunk.ShapeFilter(categories=0b1)
            raycast = World.instance.space.segment_query_first(
                [float(v) for v in startPosition],
                [float(v) for v in endPosition],
                self.RAYCAST_RADIUS,
                pymunk.ShapeFilter(mask=STATIC_CATEGORY | DYNAMIC_CATEGORY),
            )
            i = 0
            for obj in self.ignore_objects:
                if isinstance(obj, PhysicsObject):
                    for shape in obj.shapes:
                        shape.filter = pymunk.ShapeFilter(categories=cats[i])
                        i += 1

            if raycast == None:
                if top_length == self.MAX_RAYCAST or (
                        not ScriptLoader.RANDOMISE_SENSORS):
                    return max(0,
                               min(self.MAX_RAYCAST, top_length + self.offset))
                # If randomiser, linearly scale result by angle between surface normal of raycasted point.
                return max(
                    0,
                    min(
                        self.MAX_RAYCAST,
                        top_length +
                        (1 + (self.last_angle_diff +
                              self.STATIC_RANDOM_ANGLE * Randomiser.random()) *
                         (Randomiser.random() - 0.5) *
                         self.ANGLE_RANDOM_AMPLITUDE / np.pi * 2) +
                        self.offset,
                    ),
                )
            else:
                opposite_angle = centreRotation + np.pi
                while opposite_angle > raycast.normal.angle + np.pi:
                    opposite_angle -= 2 * np.pi
                while opposite_angle < raycast.normal.angle - np.pi:
                    opposite_angle += 2 * np.pi
                self.last_angle_diff = abs(opposite_angle -
                                           raycast.normal.angle)
            top_length = raycast.alpha * top_length - self.ACCEPTANCE_LEVEL
        return max(0, min(self.MAX_RAYCAST, self.offset))
Пример #5
0
 def _SenseValueAboutPosition(self, centrePosition, valueGetter):
     # Randomly sample value from SENSOR_POINTS chosen around the centrePosition.
     points = [Randomiser.random() * self.SENSOR_RADIUS for _ in range(self.SENSOR_POINTS)]
     for x in range(len(points)):
         angle = Randomiser.random() * 2 * np.pi
         points[x] = valueGetter(np.array([np.cos(angle) * points[x], np.cos(angle) * points[x]]) + centrePosition)
         # For some reason the color module hangs otherwise :/
         if hasattr(points[x], "r"):
             points[x] = np.array([points[x].r, points[x].g, points[x].b])
     total = points[0]
     for x in range(1, len(points)):
         total += points[x]
     return total / len(points)
Пример #6
0
 def generateBias(self):
     if ScriptLoader.RANDOMISE_SENSORS:
         # Distribute points cyclically between 0 and 360.
         self.dist = CompassValueDistribution(
             0,
             360,
             self.NEAREST_POINTS_NUMBER,
             self.NEAREST_POINTS_VARIANCE,
             Randomiser.getPortRandom(self._interactor.port_key),
         )
     else:
         self.dist = CompassValueDistributionNoRandom(0, 360, 360)
     self.current_offset = 0
     self.device_y_offset = self.NOISE_Y_OFFSET_MAX * self._interactor.random()
     self.noise_tick = 0
     self._value = 0
     self.noise = OpenSimplex(seed=Randomiser.getInstance().seeds[self._interactor.port_key])
     self.calibrate()
Пример #7
0
    def captureBotImage(self, directory, filename):
        self.resetVisualElements()
        from os.path import join
        from ev3sim.simulation.loader import ScriptLoader
        from ev3sim.robot import initialise_bot, RobotInteractor
        from ev3sim.simulation.randomisation import Randomiser

        Randomiser.createGlobalRandomiserWithSeed(0)
        ScriptLoader.instance.reset()
        ScriptLoader.instance.startUp()
        elems = {}
        initialise_bot(elems, find_abs(filename, [directory]), "", 0)
        ScriptLoader.instance.loadElements(elems.get("elements", []))
        for interactor in ScriptLoader.instance.active_scripts:
            if isinstance(interactor, RobotInteractor):
                interactor.connectDevices()
                interactor.initialiseDevices()
        for interactor in ScriptLoader.instance.active_scripts:
            interactor.startUp()
            interactor.tick(0)
            interactor.afterPhysics()
        screen = pygame.Surface((480, 480), pygame.SRCALPHA)
        custom_map = {
            "SCREEN_WIDTH": 480,
            "SCREEN_HEIGHT": 480,
            "MAP_WIDTH": 25,
            "MAP_HEIGHT": 25,
        }
        for elem in self.objects.values():
            elem.customMap = custom_map
            elem.calculatePoints()
        self.applyToScreen(screen, bg=pygame.Color(self.instance.background_colour))
        colorkey = pygame.Color(self.instance.background_colour)
        for x in range(480):
            for y in range(480):
                val = screen.get_at((x, y))
                val.a = 0 if (val.r == colorkey.r and val.g == colorkey.g and val.b == colorkey.b) else 255
                screen.set_at((x, y), val)
        self.resetVisualElements()
        ScriptLoader.instance.reset()
        config_path = join(find_abs(filename, [directory]), "config.bot")
        with open(config_path, "r") as f:
            config = yaml.safe_load(f)
        pygame.image.save(screen, join(find_abs(filename, [directory]), config.get("preview_path", "preview.png")))
Пример #8
0
 def resetPositions(self):
     for i, robot in enumerate(self.robots):
         diff_radius = Randomiser.random() * self.BOT_SPAWN_RADIUS
         diff_angle = Randomiser.random() * 2 * np.pi
         robot.body.position = [
             self.BOT_SPAWN_POSITION[i][0][0] * self.TILE_LENGTH + diff_radius * np.cos(diff_angle),
             self.BOT_SPAWN_POSITION[i][0][1] * self.TILE_LENGTH + diff_radius * np.sin(diff_angle),
         ]
         robot.body.angle = (
             (
                 self.BOT_SPAWN_POSITION[i][1]
                 + self.BOT_SPAWN_ANGLE[0]
                 + Randomiser.random() * (self.BOT_SPAWN_ANGLE[1] - self.BOT_SPAWN_ANGLE[0])
             )
             * np.pi
             / 180
         )
         robot.body.velocity = (0.0, 0.0)
         robot.body.angular_velocity = 0
Пример #9
0
    def calibrate(self):
        """
        Set the sensor so the current bearing is interpreted as 0.

        Example usage:
        ```
        >>> compass.calibrate()
        >>> # Rotates 10 degrees to the left
        >>> compass.value()
        10
        ```
        """
        self._setRelative()
        self.current_offset = 0
        if ScriptLoader.RANDOMISE_SENSORS:
            self.current_sample_point = Randomiser.random() * self.NOISE_SAMPLE_HEIGHT
Пример #10
0
def single_run(preset_filename,
               robots,
               bind_addr,
               seed,
               batch_file=None,
               override_settings={}):
    if batch_file:
        ScreenObjectManager.BATCH_FILE = batch_file
    ScreenObjectManager.PRESET_FILE = preset_filename
    import ev3sim

    try:
        latest_version = get_version_pypi("ev3sim")
        ScreenObjectManager.NEW_VERSION = latest_version != ev3sim.__version__
        if ScreenObjectManager.NEW_VERSION:
            update_message = f"""\

==========================================================================================
There is a new version of ev3sim available ({latest_version}).
Keeping an up to date version of ev3sim ensures you have the latest bugfixes and features.
Please update ev3sim by running the following command:
    python -m pip install -U ev3sim
==========================================================================================

"""
            print(update_message)
    except:
        ScreenObjectManager.NEW_VERSION = False

    Randomiser.createGlobalRandomiserWithSeed(seed)

    preset_file = find_abs(preset_filename,
                           allowed_areas=[
                               "local", "local/presets/", "package",
                               "package/presets/"
                           ])
    with open(preset_file, "r") as f:
        config = yaml.safe_load(f)

    config["robots"] = config.get("robots", []) + robots

    shared_data = {
        "tick": 0,  # Current tick.
        "write_stack":
        deque(),  # All write actions are processed through this.
        "data_queue": {},  # Simulation data for each bot.
        "active_count":
        {},  # Keeps track of which code connection each bot has.
        "bot_locks":
        {},  # Threading Locks and Conditions for each bot to wait for connection actions.
        "bot_communications_data":
        {},  # Buffers and information for all bot communications.
        "tick_updates":
        {},  # Simply a dictionary where the simulation tick will push static data, so the other methods are aware of when the simulation has exited.
        "events": {},  # Any events that should be sent to robots.
    }

    result_bucket = Queue(maxsize=1)

    from threading import Thread
    from ev3sim.simulation.communication import start_server_with_shared_data

    def run(shared_data, result):
        try:
            runFromConfig(config, shared_data)
        except Exception as e:
            result.put(("Simulation", e))
            return
        result.put(True)

    # Handle any other settings modified by the preset.
    settings = config.get("settings", {})
    settings.update(override_settings)
    for keyword, value in settings.items():
        run = mock.patch(keyword, value)(run)

    comm_thread = Thread(target=start_server_with_shared_data,
                         args=(shared_data, result_bucket, bind_addr),
                         daemon=True)
    sim_thread = Thread(target=run,
                        args=(shared_data, result_bucket),
                        daemon=True)

    comm_thread.start()
    sim_thread.start()

    try:
        with result_bucket.not_empty:
            while not result_bucket._qsize():
                result_bucket.not_empty.wait(0.1)
        r = result_bucket.get()
        # Chuck it back on the queue so that other threads know we are quitting.
        result_bucket.put(r)
        if r is not True:
            print(
                f"An error occurred in the {r[0]} thread. Raising an error now..."
            )
            time.sleep(1)
            raise r[1]
    except KeyboardInterrupt:
        pass
Пример #11
0
 def random(self):
     return Randomiser.getPortRandom(self.port_key).random()