diff --git a/.gitignore b/.gitignore index 292ef1f..7954551 100644 --- a/.gitignore +++ b/.gitignore @@ -160,9 +160,10 @@ cython_debug/ #.idea/ # Webots -.arena.wbproj +.*.wbproj .arena.jpg /simulator/controllers/usercode_runner/runtime.ini +/simulator/controllers/competition_supervisor/runtime.ini /zone_* /dist diff --git a/README.md b/README.md index 995ab16..eb73a6e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ # sbot_simulator A simulator built around Webots to use the sbot library virtually. -![sbot_simulator](assets/arena_overview.jpg) - -### This is a work in progress +![sbot_simulator](assets/arena_overview.png) ## Installation @@ -101,54 +99,3 @@ In order to keep the released simulator tidy and easy to use, the project is spl Alongside these folders that are placed in the releases, the `assets` folder contains images and other resources that are used in the documentation. These are used to render an HTML page user facing readme that is included in the release archive. Of the the folders that are not included in the release, the `tests` folder contains the unit and integration tests for the simulator that don't require running webots and the `test_simulator` folder contains a separate webots world that is used to test the simulator. - -## Project Status - -1. ~~device spinup~~ -2. ~~debug logs~~ -3. ~~test devices~~ -4. ~~webots devices~~ -5. ~~usercode runner~~ -6. ~~vision~~ -7. ~~arena~~ - - ~~box~~ - - ~~deck~~ - - ~~triangle deck~~ - - ~~floor texture~~ - - ~~line~~ - - ~~scoring lines~~ - - ~~starting zones~~ -8. ~~robot~~ -9. ~~device jitter~~ - - ~~in Webots~~ - - ~~Ultrasound noise~~ - - ~~Reflectance sensor noise~~ - - ~~in python~~ - - ~~motor noise~~ - - ~~servo noise~~ -10. sbot updates - 1. ~~simulator discovery~~ - 2. ~~vision~~ - 3. ~~leds~~ - 4. ~~sleep & time~~ - 5. Windows startup performance -11. ~~keyboard robot~~ -12. ~~setup script~~ -13. ~~releases~~ -14. documentation - 1. ~~dev setup~~ - 2. user usage - 3. ~~how it works~~ -15. simulator tests - - vision position - - vision orientation - - distance sensor - - reflectance sensor - - bump sensor - - motor - - servo -16. ~~linting~~ -17. ~~CI~~ -18. report currents -19. supervisor -20. comp match running diff --git a/assets/arena_overview.jpg b/assets/arena_overview.jpg deleted file mode 100755 index 784c6e6..0000000 Binary files a/assets/arena_overview.jpg and /dev/null differ diff --git a/assets/arena_overview.png b/assets/arena_overview.png new file mode 100644 index 0000000..5a2e2fe Binary files /dev/null and b/assets/arena_overview.png differ diff --git a/assets/user_readme.md b/assets/user_readme.md index 25c9153..0ee692b 100644 --- a/assets/user_readme.md +++ b/assets/user_readme.md @@ -139,7 +139,7 @@ The API for the simulator is the same as the API for the physical robot, so you As well as the logs being displayed in the console, they are also saved to a file. -This file is saved in the `zone_0` folder and has a name in the format `log-.log`. +This file is saved in the `zone_0` folder and has a name in the format `log-zone--.log`. The date is when that simulation was run. ### Simulation of Time @@ -252,6 +252,15 @@ If you see a message saying that Python cannot be found that looks similar to th As well as the guidance above, there are a few other points to note when using the simulator. These can help you to understand what is happening and how to get the most out of the simulator. +### Using Other Zones + +If the arena has multiple starting zones, you can run multiple robots in the simulator. +To test how your robot behaves in each starting zone of the arena, you can copy your robot's code to run in each corner. + +In the folder where you extracted the simulator, alongside the `zone_0` folder, you may have other `zone_` folders. +Such as `zone_1`, `zone_2`, etc. +Each of these folders can contain a `robot.py` file that will be run in the corresponding starting zone of the arena. + ### Performance Optimisations The default settings work for most users however if you are using a less powerful computer or one without a dedicated graphics card (as is the case on many laptops), you may wish to adjust the graphics settings to enable the simulation to run faster. diff --git a/example_robots/basic_robot.py b/example_robots/basic_robot.py index 25a16f5..c87070c 100644 --- a/example_robots/basic_robot.py +++ b/example_robots/basic_robot.py @@ -1,26 +1,26 @@ -from sbot import Robot +from sbot import arduino, motors, utils -robot = Robot() +# robot = Robot() -robot.motor_board.motors[0].power = 1 -robot.motor_board.motors[1].power = 1 +motors.set_power(0, 1) +motors.set_power(1, 1) # measure the distance of the right ultrasound sensor # pin 6 is the trigger pin, pin 7 is the echo pin -distance = robot.arduino.ultrasound_measure(6, 7) +distance = arduino.measure_ultrasound_distance(6, 7) print(f"Right ultrasound distance: {distance / 1000} meters") # motor board, channel 0 to half power forward -robot.motor_board.motors[0].power = 0.5 +motors.set_power(0, 0.5) # motor board, channel 1 to half power forward, -robot.motor_board.motors[1].power = 0.5 +motors.set_power(1, 0.5) # minimal time has passed at this point, # so the robot will appear to move forward instead of turning # sleep for 2 second -robot.sleep(2) +utils.sleep(2) # stop both motors -robot.motor_board.motors[0].power = 0 -robot.motor_board.motors[1].power = 0 +motors.set_power(0, 0) +motors.set_power(1, 0) diff --git a/example_robots/keyboard_robot.py b/example_robots/keyboard_robot.py index a717140..df21df1 100644 --- a/example_robots/keyboard_robot.py +++ b/example_robots/keyboard_robot.py @@ -1,7 +1,8 @@ +# mypy: ignore-errors import math from controller import Keyboard -from sbot import AnalogPins, Robot +from sbot import AnalogPin, Colour, arduino, comp, leds, motors, utils, vision # Any keys still pressed in the following period will be handled again # leading to rprinting sensors multiple times @@ -62,7 +63,7 @@ def angle_str(angle: float) -> str: return f"{angle:.4f} rad" -def print_sensors(robot: Robot) -> None: +def print_sensors() -> None: ultrasonic_sensor_names = { (2, 3): "Front", (4, 5): "Left", @@ -70,9 +71,9 @@ def print_sensors(robot: Robot) -> None: (8, 9): "Back", } reflectance_sensor_names = { - AnalogPins.A0: "Left", - AnalogPins.A1: "Center", - AnalogPins.A2: "Right", + AnalogPin.A0: "Left", + AnalogPin.A1: "Center", + AnalogPin.A2: "Right", } touch_sensor_names = { 10: "Front Left", @@ -83,29 +84,30 @@ def print_sensors(robot: Robot) -> None: print("Distance sensor readings:") for (trigger_pin, echo_pin), name in ultrasonic_sensor_names.items(): - dist = robot.arduino.ultrasound_measure(trigger_pin, echo_pin) + dist = arduino.measure_ultrasound_distance(trigger_pin, echo_pin) print(f"({trigger_pin}, {echo_pin}) {name: <12}: {dist:.0f} mm") print("Touch sensor readings:") for pin, name in touch_sensor_names.items(): - touching = robot.arduino.pins[pin].digital_value + touching = arduino.digital_read(pin) print(f"{pin} {name: <6}: {touching}") print("Reflectance sensor readings:") for Apin, name in reflectance_sensor_names.items(): - reflectance = robot.arduino.pins[Apin].analog_value + reflectance = arduino.analog_read(Apin) print(f"{Apin} {name: <12}: {reflectance:.2f} V") -def print_camera_detection(robot: Robot) -> None: - markers = robot.camera.see() +def print_camera_detection() -> None: + markers = vision.detect_markers() if markers: print(f"Found {len(markers)} makers:") for marker in markers: print(f" #{marker.id}") print( - f" Position: {marker.distance:.0f} mm, azi: {angle_str(marker.azimuth)}, " - f"elev: {angle_str(marker.elevation)}", + f" Position: {marker.position.distance:.0f} mm, " + f"{angle_str(marker.position.horizontal_angle)} right, " + f"{angle_str(marker.position.vertical_angle)} up", ) yaw, pitch, roll = marker.orientation print( @@ -119,11 +121,15 @@ def print_camera_detection(robot: Robot) -> None: print() -robot = Robot() - keyboard = KeyboardInterface() -key_sense = CONTROLS["sense"][robot.zone] +# Automatically set the zone controls based on the robot's zone +# Alternatively, you can set this manually +# ZONE_CONTROLS = 0 +ZONE_CONTROLS = comp.zone + +assert ZONE_CONTROLS < len(CONTROLS["forward"]), \ + "No controls defined for this zone, alter the ZONE_CONTROLS variable to use in this zone." print( "Note: you need to click on 3D viewport for keyboard events to be picked " @@ -138,36 +144,42 @@ def print_camera_detection(robot: Robot) -> None: keys = keyboard.process_keys() # Actions that are run continuously while the key is held - if CONTROLS["forward"][robot.zone] in keys["held"]: + if CONTROLS["forward"][ZONE_CONTROLS] in keys["held"]: left_power += 0.5 right_power += 0.5 - if CONTROLS["reverse"][robot.zone] in keys["held"]: + if CONTROLS["reverse"][ZONE_CONTROLS] in keys["held"]: left_power += -0.5 right_power += -0.5 - if CONTROLS["left"][robot.zone] in keys["held"]: + if CONTROLS["left"][ZONE_CONTROLS] in keys["held"]: left_power -= 0.25 right_power += 0.25 - if CONTROLS["right"][robot.zone] in keys["held"]: + if CONTROLS["right"][ZONE_CONTROLS] in keys["held"]: left_power += 0.25 right_power -= 0.25 - if CONTROLS["boost"][robot.zone] in keys["held"]: + if CONTROLS["boost"][ZONE_CONTROLS] in keys["held"]: boost = True # Actions that are run once when the key is pressed - if CONTROLS["sense"][robot.zone] in keys["pressed"]: - print_sensors(robot) - - if CONTROLS["see"][robot.zone] in keys["pressed"]: - print_camera_detection(robot) - - if CONTROLS["led"][robot.zone] in keys["pressed"]: - pass - - if CONTROLS["angle_unit"][robot.zone] in keys["pressed"]: + if CONTROLS["sense"][ZONE_CONTROLS] in keys["pressed"]: + print_sensors() + + if CONTROLS["see"][ZONE_CONTROLS] in keys["pressed"]: + print_camera_detection() + + if CONTROLS["led"][ZONE_CONTROLS] in keys["pressed"]: + leds.set_colour(0, Colour.MAGENTA) + leds.set_colour(1, Colour.MAGENTA) + leds.set_colour(2, Colour.MAGENTA) + elif CONTROLS["led"][ZONE_CONTROLS] in keys["released"]: + leds.set_colour(0, Colour.OFF) + leds.set_colour(1, Colour.OFF) + leds.set_colour(2, Colour.OFF) + + if CONTROLS["angle_unit"][ZONE_CONTROLS] in keys["pressed"]: USE_DEGREES = not USE_DEGREES print(f"Angle unit set to {'degrees' if USE_DEGREES else 'radians'}") @@ -176,7 +188,7 @@ def print_camera_detection(robot: Robot) -> None: left_power = max(min(left_power * 2, 1), -1) right_power = max(min(right_power * 2, 1), -1) - robot.motor_board.motors[0].power = left_power - robot.motor_board.motors[1].power = right_power + motors.set_power(0, left_power) + motors.set_power(1, right_power) - robot.sleep(KEYBOARD_SAMPLING_PERIOD / 1000) + utils.sleep(KEYBOARD_SAMPLING_PERIOD / 1000) diff --git a/requirements.txt b/requirements.txt index 12a4d12..4f9103a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -sbot==2024.0.1 +sbot==2025.1.0 april_vision==2.2.0 -opencv-python-headless >=4,<5 +opencv-python-headless >=4.8.0.76,<5 diff --git a/scripts/generate_release.py b/scripts/generate_release.py index 2abe1ca..a0ee683 100755 --- a/scripts/generate_release.py +++ b/scripts/generate_release.py @@ -78,8 +78,12 @@ logger.info("Copying helper scripts to temp directory") shutil.copy(project_root / "scripts/setup.py", temp_dir / "setup.py") for script in project_root.glob("scripts/run_*.py"): + if "run_comp_" in str(script): + continue shutil.copy(script, temp_dir) + script_dir = temp_dir / "scripts" + script_dir.mkdir() logger.info("Copying example code to temp directory") shutil.copytree(project_root / "example_robots", temp_dir / "example_robots") diff --git a/scripts/run_simulator.py b/scripts/run_simulator.py index 6a76e3e..e4a6a7d 100755 --- a/scripts/run_simulator.py +++ b/scripts/run_simulator.py @@ -3,10 +3,13 @@ A script to run the project in Webots. Largely just a shortcut to running the arena world in Webots. -Only functional in releases. """ +# ruff: noqa: E501 +from __future__ import annotations + import sys import traceback +from os.path import expandvars from pathlib import Path from shutil import which from subprocess import Popen @@ -14,53 +17,84 @@ if sys.platform == "win32": from subprocess import CREATE_NEW_PROCESS_GROUP, DETACHED_PROCESS -try: - if not (Path(__file__).parent / 'simulator/VERSION').exists(): - print("This script is only functional in releases.") - raise RuntimeError +if (Path(__file__).parent / 'simulator/VERSION').exists(): + print("Running in release mode") + SIM_BASE = Path(__file__).parent.resolve() +else: + print("Running in development mode") + # Assume the script is in the scripts directory + SIM_BASE = Path(__file__).parents[1].resolve() + +POSSIBLE_WEBOTS_PATHS = [ + ("darwin", "/Applications/Webots.app/Contents/MacOS/webots"), + ("win32", "C:\\Program Files\\Webots\\msys64\\mingw64\\bin\\webotsw.exe"), + ("win32", expandvars("%LOCALAPPDATA%\\Programs\\Webots\\msys64\\mingw64\\bin\\webotsw.exe")), + # Attempt to use the start menu shortcut + ("win32", expandvars("%ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs\\Cyberbotics\\Webots.lnk")), + ("win32", expandvars("%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Cyberbotics\\Webots.lnk")), + ("linux", "/usr/local/bin/webots"), + ("linux", "/usr/bin/webots"), +] + + +def get_webots_parameters() -> tuple[Path, Path]: + """ + Get the paths to the Webots executable and the arena world file. - world_file = Path(__file__).parent / "simulator/worlds/arena.wbt" + :return: The paths to the Webots executable and the arena world file + """ + world_file = SIM_BASE / "simulator/worlds/arena.wbt" + if not world_file.exists(): + raise RuntimeError("World file not found.") + + if not (SIM_BASE / "venv").exists(): + raise RuntimeError("Please run the setup.py script before running the simulator.") + + # Check if Webots is in the PATH webots = which("webots") # Find the webots executable, if it is not in the PATH if webots is None: - if sys.platform == "darwin": - webots = "/Applications/Webots.app/Contents/MacOS/webots" - elif sys.platform == "win32": - webots = "C:\\Program Files\\Webots\\msys64\\mingw64\\bin\\webotsw.exe" - elif sys.platform.startswith("linux"): - possible_paths = ["/usr/local/bin/webots", "/usr/bin/webots"] - for path in possible_paths: + for system_filter, path in POSSIBLE_WEBOTS_PATHS: + if sys.platform.startswith(system_filter): + print(f"Checking {path}") if Path(path).exists(): webots = path break - else: - print("Webots executable not found.") - raise RuntimeError + + if webots is None or not Path(webots).exists(): + raise RuntimeError("Webots executable not found.") + + return Path(webots), world_file + + +def main() -> None: + """Run the project in Webots.""" + try: + webots, world_file = get_webots_parameters() + + # Run the world file in Webots, + # detaching the process so it does not close when this script does + if sys.platform == "win32": + Popen( + [str(webots), str(world_file)], + creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP, + # shell=True is needed to run from shortcuts + shell=(webots.suffix == ".lnk"), + ) else: - print("Unsupported platform.") - raise RuntimeError - - if not Path(webots).exists(): - print("Webots executable not found.") - raise RuntimeError - - if not (Path(__file__).parent / "venv").exists(): - print("Please run the setup.py script before running the simulator.") - raise RuntimeError - - # Run the world file in Webots, - # detaching the process so it does not close when this script does - if sys.platform == "win32": - Popen([webots, world_file], creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP) - else: - Popen([webots, world_file], start_new_session=True) -except RuntimeError: - input("Press enter to continue...") - exit(1) -except Exception as e: - print(f"An error occurred: {e}") - print(traceback.format_exc()) - input("Press enter to continue...") - exit(1) + Popen([str(webots), str(world_file)], start_new_session=True) + except RuntimeError as e: + print(f"An error occurred: {e}") + input("Press enter to continue...") + exit(1) + except Exception as e: + print(f"An error occurred: {e}") + print(traceback.format_exc()) + input("Press enter to continue...") + exit(1) + + +if __name__ == "__main__": + main() diff --git a/scripts/setup.py b/scripts/setup.py index 928d9b7..b5776a0 100755 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -13,44 +13,24 @@ import logging import platform import shutil +import sys from pathlib import Path -from subprocess import run +from subprocess import SubprocessError, check_call from venv import create logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s: %(message)s") logger = logging.getLogger(__name__) -try: - if (Path(__file__).parent / 'simulator/VERSION').exists(): - # This is running from a release - project_root = Path(__file__).parent - requirements = project_root / "simulator/requirements.txt" - else: - # This is running from the repository - project_root = Path(__file__).parents[1] - requirements = project_root / "requirements.txt" - venv_dir = project_root / "venv" +def populate_python_config(runtime_ini: Path, venv_python: Path) -> None: + """ + Populate the python configuration in the runtime.ini file. - logger.info(f"Creating virtual environment in {venv_dir.absolute()}") - create(venv_dir, with_pip=True) + This will set the python command to the virtual environment python. - logger.info(f"Installing dependencies from {requirements.absolute()}") - if platform.system() == "Windows": - pip = venv_dir / "Scripts/pip.exe" - venv_python = venv_dir / "Scripts/python" - else: - pip = venv_dir / "bin/pip" - venv_python = venv_dir / "bin/python" - run( - [str(venv_python), "-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"], - cwd=venv_dir, - ) - run([str(pip), "install", "-r", str(requirements)], cwd=venv_dir) - - logger.info("Setting up Webots Python location") - - runtime_ini = project_root / "simulator/controllers/usercode_runner/runtime.ini" + :param runtime_ini: The path to the runtime.ini file + :param venv_python: The path to the virtual environment python executable + """ runtime_content: list[str] = [] if runtime_ini.exists(): prev_runtime_content = runtime_ini.read_text().splitlines() @@ -79,12 +59,56 @@ runtime_ini.write_text('\n'.join(runtime_content)) + +try: + if (Path(__file__).parent / 'simulator/VERSION').exists(): + # This is running from a release + print("Running in release mode") + project_root = Path(__file__).parent + requirements = project_root / "simulator/requirements.txt" + else: + # This is running from the repository + print("Running in development mode") + project_root = Path(__file__).parents[1] + requirements = project_root / "requirements.txt" + + print(f"Python version: {sys.version} on {platform.platform()}") + + venv_dir = project_root / "venv" + + logger.info(f"Creating virtual environment in {venv_dir.absolute()}") + create(venv_dir, with_pip=True) + + logger.info(f"Installing dependencies from {requirements.absolute()}") + if platform.system() == "Windows": + pip = venv_dir / "Scripts/pip.exe" + venv_python = venv_dir / "Scripts/python" + else: + pip = venv_dir / "bin/pip" + venv_python = venv_dir / "bin/python" + check_call( + [str(venv_python), "-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"], + cwd=venv_dir, + ) + check_call([str(pip), "install", "-r", str(requirements)], cwd=venv_dir) + + logger.info("Setting up Webots Python location") + + controllers_dir = project_root / "simulator/controllers" + usercode_ini = controllers_dir / "usercode_runner/runtime.ini" + supervisor_ini = controllers_dir / "competition_supervisor/runtime.ini" + populate_python_config(usercode_ini, venv_python) + populate_python_config(supervisor_ini, venv_python) + # repopulate zone 0 with example code if robot.py is missing zone_0 = project_root / "zone_0" if not (zone_0 / "robot.py").exists(): logger.info("Repopulating zone 0 with example code") zone_0.mkdir(exist_ok=True) shutil.copy(project_root / "example_robots/basic_robot.py", zone_0 / "robot.py") +except SubprocessError: + logger.error("Setup failed due to an error.") + input("An error occurred, press enter to close.") except Exception: logger.exception("Setup failed due to an error.") input("An error occurred, press enter to close.") diff --git a/simulator/controllers/competition_supervisor/competition_supervisor.py b/simulator/controllers/competition_supervisor/competition_supervisor.py new file mode 100644 index 0000000..1e73f0b --- /dev/null +++ b/simulator/controllers/competition_supervisor/competition_supervisor.py @@ -0,0 +1,263 @@ +""".""" +from __future__ import annotations + +import sys +import time +from contextlib import contextmanager +from pathlib import Path +from typing import Iterator + +from controller import Supervisor + +# Robot constructor lacks a return type annotation in R2023b +sys.path.insert(0, Supervisor().getProjectPath()) # type: ignore[no-untyped-call] +# from lighting_control import LightingControl +import environment # configure path to include modules +from robot_logging import get_match_identifier, prefix_and_tee_streams +from robot_utils import get_game_mode, get_match_data, get_robot_file + +# Get the robot object that was created when setting up the environment +_robot = Supervisor.created +assert _robot is not None, "Robot object not created" +supervisor: Supervisor = _robot # type: ignore[assignment] + + +class RobotData: + """Data about a robot in the arena.""" + + def __init__(self, zone: int): + self.registered_ready = False + self.zone = zone + self.robot = supervisor.getFromDef(f'ROBOT{zone}') + if self.robot is None: + raise ValueError(f"Failed to get Webots node for zone {zone}") + + def zone_occupied(self) -> bool: + """Check if this zone has a robot.py file associated with it.""" + try: + _ = get_robot_file(self.zone) + except FileNotFoundError: + return False + return True + + def remove_robot(self) -> None: + """Delete the robot proto from the world.""" + self.robot.remove() # type: ignore[attr-defined] + + def preset_robot(self) -> None: + """Arm the robot so that it waits for the start signal.""" + self.robot.getField('customData').setSFString('prestart') # type: ignore[attr-defined] + + def robot_ready(self) -> bool: + """Check if robot has set its pre-start flag.""" + return bool(self.robot.getField('customData').getSFString() == 'ready') # type: ignore[attr-defined] + + def start_robot(self) -> None: + """Signal to the robot that the start button has been pressed.""" + self.robot.getField('customData').setSFString('start') # type: ignore[attr-defined] + + +class Robots: + """A collection of robots in the arena.""" + + def __init__(self) -> None: + self.robots: dict[int, RobotData] = {} + + for zone in range(0, environment.NUM_ZONES): + try: + robot_data = RobotData(zone) + except ValueError as e: + print(e) + else: + self.robots[zone] = robot_data + + def remove_unoccupied_robots(self) -> None: + """Remove all robots that don't have usercode.""" + for robot in list(self.robots.values()): + if not robot.zone_occupied(): + robot.remove_robot() + _ = self.robots.pop(robot.zone) + + def preset_robots(self) -> None: + """Arm all robots so that they wait for the start signal.""" + for robot in self.robots.values(): + robot.preset_robot() + + def wait_for_ready(self, timeout: float) -> None: + """Wait for all robots to set their pre-start flags.""" + end_time = supervisor.getTime() + timeout + while supervisor.getTime() < end_time: + all_ready = True + # Sleep in individual timesteps to allow the robots to update + supervisor.step() + + for zone, robot in self.robots.items(): + if not robot.registered_ready: + if robot.robot_ready(): + print(f"Robot in zone {zone} is ready.") + # Log only once per robot when ready + robot.registered_ready = True + else: + all_ready = False + if all_ready: + break + else: + pending_robots = ', '.join([ + str(zone) + for zone, robot in self.robots.items() + if not robot.robot_ready() + ]) + raise TimeoutError( + f"Robots in zones {pending_robots} failed to initialise. " + f"Failed to reach wait_start() within {timeout} seconds." + ) + + def start_robots(self) -> None: + """Signal to all robots that their start buttons have been pressed.""" + for robot in self.robots.values(): + robot.start_robot() + + +def is_dev_mode() -> bool: + """Load the mode file and check if we are in dev mode.""" + return (get_game_mode() == 'dev') + + +@contextmanager +def record_animation(filename: Path) -> Iterator[None]: + """Record an animation for the duration of the manager.""" + filename.parent.mkdir(parents=True, exist_ok=True) + print(f"Saving animation to {filename}") + supervisor.animationStartRecording(str(filename)) + yield + supervisor.animationStopRecording() # type: ignore[no-untyped-call] + + +@contextmanager +def record_video( + filename: Path, + resolution: tuple[int, int], + skip: bool = False +) -> Iterator[None]: + """Record a video for the duration of the manager.""" + filename.parent.mkdir(parents=True, exist_ok=True) + + if skip: + print('Not recording movie') + yield + return + else: + print(f"Saving video to {filename}") + + supervisor.movieStartRecording( + str(filename), + width=resolution[0], + height=resolution[1], + quality=100, + codec=0, + acceleration=1, + caption=False, + ) + yield + supervisor.movieStopRecording() # type: ignore[no-untyped-call] + + while not supervisor.movieIsReady(): # type: ignore[no-untyped-call] + time.sleep(0.1) + + if supervisor.movieFailed(): # type: ignore[no-untyped-call] + print("Movie failed to record") + + +def save_image(filename: Path) -> None: + """Capture an image of the arena.""" + filename.parent.mkdir(parents=True, exist_ok=True) + print(f"Saving image to {filename}") + supervisor.exportImage(str(filename), 100) + + +def run_match( + match_duration: int, + media_path_stem: Path, + video_resolution: tuple[int, int], + skip_video: bool, +) -> None: + """Run a match in the arena.""" + robots = Robots() + robots.remove_unoccupied_robots() + + time_step = int(supervisor.getBasicTimeStep()) + match_timesteps = (match_duration * 1000) // time_step + # lighting_control = LightingControl(supervisor, match_timesteps) + + robots.preset_robots() + + robots.wait_for_ready(5) + + with record_animation(media_path_stem.with_suffix('.html')): + # Animations don't support lighting changes so start the animation before + # setting the lighting. Step the simulation to allow the animation to start. + supervisor.step() + # Set initial lighting + # lighting_control.service_lighting(0) + with record_video(media_path_stem.with_suffix('.mp4'), video_resolution, skip_video): + print("===========") + print("Match start") + print("===========") + + # We are ready to start the match now. "Press" the start button on the robots + robots.start_robots() + supervisor.simulationSetMode(Supervisor.SIMULATION_MODE_FAST) # type: ignore[attr-defined] + + # for current_step in range(match_timesteps + 1): + # lighting_control.service_lighting(current_step) + # supervisor.step(time_step) + supervisor.step(match_timesteps) + + print("==================") + print("Game over, pausing") + print("==================") + supervisor.simulationSetMode(Supervisor.SIMULATION_MODE_PAUSE) # type: ignore[attr-defined] + + # To allow for a clear image of the final state, we have reset the + # lighting after the final frame of the video. + save_image(media_path_stem.with_suffix('.jpg')) + # TODO score match + + +def main() -> None: + """Run the competition supervisor.""" + if is_dev_mode(): + robots = Robots() + robots.remove_unoccupied_robots() + exit() + + match_data = get_match_data() + match_id = get_match_identifier() + + prefix_and_tee_streams( + environment.ARENA_ROOT / f'supervisor-log-{match_id}.txt', + prefix=lambda: f'[{supervisor.getTime():0.3f}] ', + ) + + try: + # TODO check for required libraries? + + run_match( + match_data.match_duration, + environment.ARENA_ROOT / 'recordings' / match_id, + video_resolution=match_data.video_resolution, + skip_video=(not match_data.video_enabled), + ) + # Set the overall Webots exit code to follow the supervisor's exit code + except Exception as e: + # Print and step so error is printed to console + print(f"Error: {e}") + supervisor.step() + supervisor.simulationQuit(1) + raise + else: + supervisor.simulationQuit(0) + + +if __name__ == '__main__': + main() diff --git a/simulator/controllers/usercode_runner/usercode_runner.py b/simulator/controllers/usercode_runner/usercode_runner.py index 8680c17..002b3cd 100644 --- a/simulator/controllers/usercode_runner/usercode_runner.py +++ b/simulator/controllers/usercode_runner/usercode_runner.py @@ -12,10 +12,8 @@ import logging import os import runpy -import subprocess import sys import threading -from datetime import datetime from pathlib import Path from tempfile import TemporaryDirectory @@ -24,7 +22,8 @@ # Robot constructor lacks a return type annotation in R2023b sys.path.insert(0, Robot().getProjectPath()) # type: ignore[no-untyped-call] import environment # configure path to include modules -from robot_logging import prefix_and_tee_streams +from robot_logging import get_match_identifier, prefix_and_tee_streams +from robot_utils import get_game_mode, get_robot_file, print_simulation_version from sbot_interface.setup import setup_devices from sbot_interface.socket_server import SocketServer @@ -36,65 +35,6 @@ LOGGER = logging.getLogger('usercode_runner') -def get_robot_file(robot_zone: int) -> Path: - """ - Get the path to the robot file for the given zone. - - :param robot_zone: The zone number - :return: The path to the robot file - :raises FileNotFoundError: If no robot controller is found for the given zone - """ - robot_file = environment.ZONE_ROOT / f'zone_{robot_zone}' / 'robot.py' - - # Check if the robot file exists - if not robot_file.exists(): - raise FileNotFoundError(f"No robot controller found for zone {robot_file}") - - return robot_file - - -def get_game_mode() -> str: - """ - Get the game mode from the game mode file. - - Default to 'dev' if the file does not exist. - - :return: The game mode - """ - if environment.GAME_MODE_FILE.exists(): - game_mode = environment.GAME_MODE_FILE.read_text().strip() - else: - game_mode = 'dev' - - assert game_mode in ['dev', 'comp'], f'Invalid game mode: {game_mode}' - - return game_mode - - -def print_simulation_version() -> None: - """ - Print the version of the simulator that is running. - - Uses a VERSION file in the root of the simulator to determine the version. - For development, the version is uses the git describe command. - - The version is printed to the console. - """ - version_file = environment.SIM_ROOT / 'VERSION' - if version_file.exists(): - version = version_file.read_text().strip() - else: - try: - version = subprocess.check_output( - ['git', 'describe', '--tags', '--always'], - cwd=str(environment.SIM_ROOT.resolve()), - ).decode().strip() - except subprocess.CalledProcessError: - version = 'unknown' - - print(f"Running simulator version: {version}") - - def start_devices() -> SocketServer: """ Create the board simulators and return the SocketServer object. @@ -167,12 +107,13 @@ def main() -> bool: robot_file = get_robot_file(zone) except FileNotFoundError as e: print(e.args[0]) + robot.step() # Not having a robot file is not an error in dev mode - return game_mode == 'comp' + return game_mode != 'comp' # Setup log file prefix_and_tee_streams( - robot_file.parent / f'log-{datetime.now():%Y_%m_%dT%H_%M_%S}.txt', + robot_file.parent / f'log-zone-{zone}-{get_match_identifier()}.txt', prefix=lambda: f'[{zone}| {robot.getTime():0.3f}] ', ) diff --git a/simulator/environment.py b/simulator/environment.py index 65af930..2a1d673 100644 --- a/simulator/environment.py +++ b/simulator/environment.py @@ -3,15 +3,27 @@ Also contains constants for where several important files are located. """ +import os import sys from pathlib import Path SIM_ROOT = Path(__file__).absolute().parent -ZONE_ROOT = SIM_ROOT.parent MODULES_ROOT = SIM_ROOT / 'modules' -GAME_MODE_FILE = SIM_ROOT / 'mode.txt' -NUM_ZONES = 1 +ARENA_ROOT = Path(os.environ.get('ARENA_ROOT', SIM_ROOT.parent)) +ZONE_ROOT = ARENA_ROOT +GAME_MODE_FILE = ARENA_ROOT / 'mode.txt' + +NUM_ZONES = 4 +DEFAULT_MATCH_DURATION = 150 # seconds + + +if not ARENA_ROOT.is_absolute(): + # Webots sets the current directory of each controller to the directory of + # the controller file. As such, relative paths would be ambiguous. + # Hint: `$PWD` or `%CD%` may be useful to construct an absolute path from + # your relative path. + raise ValueError(f"'ARENA_ROOT' must be an absolute path, got {ARENA_ROOT!r}") def setup_environment() -> None: diff --git a/simulator/modules/robot_logging.py b/simulator/modules/robot_logging.py index 56ba910..a6d39ff 100644 --- a/simulator/modules/robot_logging.py +++ b/simulator/modules/robot_logging.py @@ -7,10 +7,15 @@ from __future__ import annotations import sys +from datetime import datetime from io import TextIOWrapper from pathlib import Path from typing import Callable, TextIO +from robot_utils import get_match_data + +DATE_IDENTIFIER = datetime.now().strftime("%Y_%m_%dT%H_%M_%S") + class Tee(TextIOWrapper): """Forwards calls from its `write` and `flush` methods to each of the given targets.""" @@ -109,3 +114,19 @@ def prefix_and_tee_streams(name: Path, prefix: Callable[[], str] | str | None = ), prefix=prefix, ) + + +def get_match_identifier() -> str: + """ + Get the identifier for this run of the simulator. + + This identifier is used to name the log files. + + :return: The match identifier + """ + match_data = get_match_data() + + if match_data.match_number is not None: + return f"match-{match_data.match_number}" + else: + return DATE_IDENTIFIER diff --git a/simulator/modules/robot_utils.py b/simulator/modules/robot_utils.py new file mode 100644 index 0000000..4cb02f5 --- /dev/null +++ b/simulator/modules/robot_utils.py @@ -0,0 +1,120 @@ +"""General utilities that are useful across runners.""" +from __future__ import annotations + +import json +import platform +import subprocess +import sys +from pathlib import Path +from typing import NamedTuple + +# Configure path to import the environment configuration +sys.path.insert(0, str(Path(__file__).parents[1])) +import environment + +# Reset the path +del sys.path[0] + + +class MatchData(NamedTuple): + """ + Data about the current match. + + :param match_number: The current match number + :param match_duration: The duration of the match in seconds + :param video_enabled: Whether video recording is enabled + :param video_resolution: The resolution of the video recording + """ + + match_number: int | None = None + match_duration: int = environment.DEFAULT_MATCH_DURATION + video_enabled: bool = True + video_resolution: tuple[int, int] = (1920, 1080) + + +def get_robot_file(robot_zone: int) -> Path: + """ + Get the path to the robot file for the given zone. + + :param robot_zone: The zone number + :return: The path to the robot file + :raises FileNotFoundError: If no robot controller is found for the given zone + """ + robot_file = environment.ZONE_ROOT / f'zone_{robot_zone}' / 'robot.py' + + # Check if the robot file exists + if not robot_file.exists(): + raise FileNotFoundError(f"No robot code to run for zone {robot_zone}") + + return robot_file + + +def get_game_mode() -> str: + """ + Get the game mode from the game mode file. + + Default to 'dev' if the file does not exist. + + :return: The game mode + """ + if environment.GAME_MODE_FILE.exists(): + game_mode = environment.GAME_MODE_FILE.read_text().strip() + else: + game_mode = 'dev' + + assert game_mode in ['dev', 'comp'], f'Invalid game mode: {game_mode}' + + return game_mode + + +def print_simulation_version() -> None: + """ + Print the version of the simulator that is running. + + Uses a VERSION file in the root of the simulator to determine the version. + For development, the version is uses the git describe command. + + The version is printed to the console. + """ + version_file = environment.SIM_ROOT / 'VERSION' + if version_file.exists(): + version = version_file.read_text().strip() + else: + try: + version = subprocess.check_output( + ['git', 'describe', '--tags', '--always'], + cwd=str(environment.SIM_ROOT.resolve()), + ).decode().strip() + except subprocess.CalledProcessError: + version = 'unknown' + + print( + f"Running simulator version: {version} in Python {platform.python_version()} " + f"({platform.system()}-{platform.machine()})" + ) + + +def get_match_data() -> MatchData: + """Load the match data from the match data file.""" + match_data_file = environment.ARENA_ROOT / 'match.json' + default_match_data = MatchData() + + if match_data_file.exists(): + # TODO error handling for invalid json + raw_data = json.loads(match_data_file.read_text()) + match_data = MatchData( + match_number=raw_data.get('match_number', default_match_data.match_number), + match_duration=raw_data.get('duration', default_match_data.match_duration), + video_enabled=( + raw_data.get('recording_config', {}) + .get('enabled', default_match_data.video_enabled) + ), + video_resolution=( + raw_data.get('recording_config', {}) + .get('video_resolution', default_match_data.video_resolution) + ), + ) + else: + match_data = default_match_data + + return match_data diff --git a/simulator/modules/sbot_interface/boards/servo_board.py b/simulator/modules/sbot_interface/boards/servo_board.py index 536f623..0aa922e 100644 --- a/simulator/modules/sbot_interface/boards/servo_board.py +++ b/simulator/modules/sbot_interface/boards/servo_board.py @@ -44,7 +44,7 @@ def handle_command(self, command: str) -> str: if args[0] == '*IDN?': return f'Student Robotics:SBv4B:{self.asset_tag}:{self.software_version}' elif args[0] == '*STATUS?': - return f"{self.watchdog_fail}:{self.pgood}" + return f"{self.watchdog_fail:d}:{self.pgood:d}" elif args[0] == '*RESET': LOGGER.info(f'Resetting servo board {self.asset_tag}') for servo in self.servos: diff --git a/simulator/modules/sbot_interface/devices/power.py b/simulator/modules/sbot_interface/devices/power.py index 849914d..71b06d1 100644 --- a/simulator/modules/sbot_interface/devices/power.py +++ b/simulator/modules/sbot_interface/devices/power.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from typing import Callable -from sbot_interface.devices.util import get_globals +from sbot_interface.devices.util import WebotsDevice, get_globals, get_robot_device class Output: @@ -36,6 +36,36 @@ def get_current(self) -> int: return 0 +class ConnectorOutput(Output): + """ + A class to represent a power output that controls a webots connector device. + + :param device_name: The name of the device in webots. + :param downstream_current: A function to get the current draw of the downstream device. + """ + + def __init__( + self, + device_name: str, + downstream_current: Callable[[], int] | None = None, + ) -> None: + super().__init__(downstream_current) + g = get_globals() + self._device = get_robot_device(g.robot, device_name, WebotsDevice.Connector) + self._enabled = False + + def set_output(self, enable: bool) -> None: + """Set the output state.""" + if enable: + self._device.lock() # type: ignore[no-untyped-call] + else: + self._device.unlock() # type: ignore[no-untyped-call] + + def get_output(self) -> bool: + """Get the output state.""" + return self._device.isLocked() + + class BaseBuzzer(ABC): """The base class for the buzzer device.""" diff --git a/simulator/modules/sbot_interface/devices/servo.py b/simulator/modules/sbot_interface/devices/servo.py index a25da32..e1daf1b 100644 --- a/simulator/modules/sbot_interface/devices/servo.py +++ b/simulator/modules/sbot_interface/devices/servo.py @@ -4,7 +4,10 @@ The servo will apply a small amount of variation to the power setting to simulate inaccuracies in the servo. """ +from __future__ import annotations + from abc import ABC, abstractmethod +from typing import TYPE_CHECKING from sbot_interface.devices.util import ( WebotsDevice, @@ -14,8 +17,13 @@ map_to_range, ) -MAX_POSITION = 2000 -MIN_POSITION = 1000 +if TYPE_CHECKING: + from controller import PositionSensor + +MAX_POSITION = 4000 +MIN_POSITION = 300 +SERVO_MAX = 1980 +SERVO_MIN = 350 class BaseServo(ABC): @@ -92,13 +100,16 @@ class Servo(BaseServo): """A servo connected to the Servo board.""" def __init__(self, device_name: str) -> None: - self.position = (MAX_POSITION + MIN_POSITION) // 2 + self.position = (SERVO_MAX + SERVO_MIN) // 2 # TODO use setAvailableForce to simulate disabled self._enabled = False g = get_globals() self._device = get_robot_device(g.robot, device_name, WebotsDevice.Motor) + self._pos_sensor: PositionSensor | None = self._device.getPositionSensor() # type: ignore[no-untyped-call] self._max_position = self._device.getMaxPosition() self._min_position = self._device.getMinPosition() + if self._pos_sensor is not None: + self._pos_sensor.enable(g.timestep) def disable(self) -> None: """Disable the servo.""" @@ -112,11 +123,11 @@ def set_position(self, value: int) -> None: """ # Apply a small amount of variation to the power setting to simulate # inaccuracies in the servo - value = int(add_jitter(value, (MIN_POSITION, MAX_POSITION))) + value = int(add_jitter(value, (SERVO_MIN, SERVO_MAX))) self._device.setPosition(map_to_range( value, - (MIN_POSITION, MAX_POSITION), + (SERVO_MIN, SERVO_MAX), (self._min_position + 0.001, self._max_position - 0.001), )) self.position = value @@ -128,6 +139,12 @@ def get_position(self) -> int: Position is the pulse width in microseconds. """ + if self._pos_sensor is not None: + self.position = int(map_to_range( + self._pos_sensor.getValue(), + (self._min_position + 0.001, self._max_position - 0.001), + (MIN_POSITION, MAX_POSITION), + )) return self.position def get_current(self) -> int: diff --git a/simulator/modules/sbot_interface/devices/util.py b/simulator/modules/sbot_interface/devices/util.py index 9724b74..a160215 100644 --- a/simulator/modules/sbot_interface/devices/util.py +++ b/simulator/modules/sbot_interface/devices/util.py @@ -13,6 +13,7 @@ Accelerometer, Camera, Compass, + Connector, DistanceSensor, Emitter, Gyro, @@ -45,6 +46,7 @@ class WebotsDevice: Accelerometer = Accelerometer Camera = Camera Compass = Compass + Connector = Connector DistanceSensor = DistanceSensor Emitter = Emitter GPS = GPS @@ -152,6 +154,6 @@ def add_jitter( std_dev = value * (std_dev_percent / 100.0) mean_offset = value * (offset_percent / 100.0) - error = value + gauss(mean_offset, std_dev) + error = gauss(mean_offset, std_dev) # Ensure the error is within the range return max(value_range[0], min(value_range[1], value + error)) diff --git a/simulator/protos/arena/Arena.proto b/simulator/protos/arena/Arena.proto index 01ebf22..0754203 100755 --- a/simulator/protos/arena/Arena.proto +++ b/simulator/protos/arena/Arena.proto @@ -59,6 +59,7 @@ PROTO Arena [ children [ Solid { # Floor translation 0 -0.002 0 + rotation 0 0 1 3.1416 children [ DEF FLOOR Shape { appearance Appearance { diff --git a/simulator/protos/props/BoxToken.proto b/simulator/protos/props/BoxToken.proto index f84f25c..461d7fa 100755 --- a/simulator/protos/props/BoxToken.proto +++ b/simulator/protos/props/BoxToken.proto @@ -7,13 +7,15 @@ EXTERNPROTO "./Marker.proto" PROTO BoxToken [ field SFVec3f translation 0 0 0 field SFRotation rotation 0 1 0 0 - field SFVec3f size 0.12 0.12 0.12 + field SFVec3f size 0.13 0.13 0.13 field SFVec2f {0.08 0.08, 0.15 0.15, 0.2 0.2} marker_size 0.08 0.08 field SFColor colour 0.7 0.55 0.35 field SFString marker "0" field SFString model "" - field SFFloat mass 0.100 + field SFFloat mass 0.080 field MFString texture_url [] + field SFFloat connectorStrength 35 + field SFFloat connectorShear 20 ] { Solid { @@ -78,6 +80,39 @@ PROTO BoxToken [ model IS marker texture_url IS texture_url } + # Shape { + # appearance PBRAppearance { + # transparency 0.4 + # baseColor 1 0 0 + # } + # geometry Sphere { + # radius %<= fields.size.value.x / 2 * 1.4 >% + # subdivision 5 + # } + # } + Connector { + type "passive" + distanceTolerance %<= fields.size.value.x / 2 * 1.4 >% + axisTolerance 3.1415 + rotationTolerance 0 + numberOfRotations 0 + tensileStrength IS connectorStrength + shearStrength IS connectorShear + snap FALSE + name "Front Connector" + } + Connector { + rotation 0 0 1 3.1416 + type "passive" + distanceTolerance %<= fields.size.value.x / 2 * 1.4 >% + axisTolerance 3.1415 + rotationTolerance 0 + numberOfRotations 0 + tensileStrength IS connectorStrength + shearStrength IS connectorShear + snap FALSE + name "Rear Connector" + } ] name IS model model IS model diff --git a/simulator/worlds/arena.wbt b/simulator/worlds/arena.wbt index 17e3fc0..54814c0 100755 --- a/simulator/worlds/arena.wbt +++ b/simulator/worlds/arena.wbt @@ -23,16 +23,32 @@ DEF AMBIENT Background { TexturedBackgroundLight { } -SRObot { - name "robot" +DEF ROBOT0 SRObot { + name "robot0" translation 0.45 1.95 0 rotation 0 0 1 3.1415 - flagColour 1 0 0 + flagColour 0 1 0 controllerArgs ["0"] controller "usercode_runner" customData "start" } +DEF ROBOT1 SRObot { + name "robot1" + translation -0.45 -1.95 0 + rotation 0 0 1 0 + flagColour 1 0.4 0 + controllerArgs ["1"] + controller "usercode_runner" + customData "start" +} + +Robot { + name "competition_supervisor" + controller "competition_supervisor" + supervisor TRUE +} + Arena { size 5.4 5.4 locked TRUE @@ -81,11 +97,11 @@ DEF CANS Pose { children [ Can { name "can1" - translation -0.3 0.44 0 + translation -0.46 0.60 0 } Can { name "can2" - translation -1.5 1.2 0 + translation -1.48 1.1 0 } Can { name "can3" @@ -97,16 +113,16 @@ DEF CANS Pose { } Can { name "can5" - translation -1.5 -1.5 0 + translation -1.48 -1.95 0 } Can { name "can6" - translation 0.3 -0.44 0 + translation 0.46 -0.6 0 } Can { name "can7" - translation 1.5 -1.2 0 + translation 1.48 -1.1 0 } Can { name "can8" @@ -118,7 +134,7 @@ DEF CANS Pose { } Can { name "can10" - translation 1.5 1.5 0 + translation 1.48 1.95 0 } ] } @@ -127,7 +143,7 @@ Marker { name "A0" model "0" size 0.1 0.1 - translation -1.4798 2.29 0.07 + translation -1.4798 2.165 0.07 rotation 0 0 1 1.5708 texture_url ["sim_markers/0.png"] upright TRUE @@ -136,7 +152,7 @@ Marker { name "A1" model "1" size 0.1 0.1 - translation -1.4798 1.99 0.07 + translation -1.4798 2.015 0.07 rotation 0 0 1 1.5708 texture_url ["sim_markers/1.png"] upright TRUE @@ -145,7 +161,7 @@ Marker { name "A2" model "2" size 0.1 0.1 - translation -0.4192 0.001 0.07 + translation -0.535 0.001 0.07 rotation 0 0 1 3.1415 texture_url ["sim_markers/2.png"] upright TRUE @@ -154,7 +170,7 @@ Marker { name "A3" model "3" size 0.1 0.1 - translation -0.7192 0.001 0.07 + translation -0.685 0.001 0.07 rotation 0 0 1 3.1415 texture_url ["sim_markers/3.png"] upright TRUE @@ -163,7 +179,7 @@ Marker { name "A4" model "4" size 0.1 0.1 - translation -2.699 0.91 0.07 + translation -2.699 0.815 0.07 rotation 0 0 1 1.5708 texture_url ["sim_markers/4.png"] upright TRUE @@ -172,7 +188,7 @@ Marker { name "A5" model "5" size 0.1 0.1 - translation -2.699 0.61 0.07 + translation -2.699 0.665 0.07 rotation 0 0 1 1.5708 texture_url ["sim_markers/5.png"] upright TRUE @@ -181,7 +197,7 @@ Marker { name "A6" model "6" size 0.1 0.1 - translation -2.19545 -1.98335 0.07 + translation -2.14243 -2.03637 0.07 rotation 0 0 1 2.3561 texture_url ["sim_markers/6.png"] upright TRUE @@ -190,7 +206,7 @@ Marker { name "A7" model "7" size 0.1 0.1 - translation -1.98335 -2.19545 0.07 + translation -2.03637 -2.14243 0.07 rotation 0 0 1 2.3561 texture_url ["sim_markers/7.png"] upright TRUE @@ -200,7 +216,7 @@ Marker { name "B0" model "0" size 0.1 0.1 - translation 1.4798 -2.29 0.07 + translation 1.4798 -2.165 0.07 rotation 0 0 1 -1.5708 texture_url ["sim_markers/0.png"] upright TRUE @@ -209,7 +225,7 @@ Marker { name "B1" model "1" size 0.1 0.1 - translation 1.4798 -1.99 0.07 + translation 1.4798 -2.015 0.07 rotation 0 0 1 -1.5708 texture_url ["sim_markers/1.png"] upright TRUE @@ -218,7 +234,7 @@ Marker { name "B2" model "2" size 0.1 0.1 - translation 0.4192 -0.001 0.07 + translation 0.535 -0.001 0.07 rotation 0 0 1 0 texture_url ["sim_markers/2.png"] upright TRUE @@ -227,7 +243,7 @@ Marker { name "B3" model "3" size 0.1 0.1 - translation 0.7192 -0.001 0.07 + translation 0.685 -0.001 0.07 rotation 0 0 1 0 texture_url ["sim_markers/3.png"] upright TRUE @@ -236,7 +252,7 @@ Marker { name "B4" model "4" size 0.1 0.1 - translation 2.699 -0.81 0.07 + translation 2.699 -0.815 0.07 rotation 0 0 1 -1.5708 texture_url ["sim_markers/4.png"] upright TRUE @@ -245,7 +261,7 @@ Marker { name "B5" model "5" size 0.1 0.1 - translation 2.699 -0.51 0.07 + translation 2.699 -0.665 0.07 rotation 0 0 1 -1.5708 texture_url ["sim_markers/5.png"] upright TRUE @@ -254,7 +270,7 @@ Marker { name "B6" model "6" size 0.1 0.1 - translation 2.19545 1.98335 0.07 + translation 2.14243 2.03637 0.07 rotation 0 0 1 -0.7853 texture_url ["sim_markers/6.png"] upright TRUE @@ -263,8 +279,11 @@ Marker { name "B7" model "7" size 0.1 0.1 - translation 1.98335 2.19545 0.07 + translation 2.03637 2.14243 0.07 rotation 0 0 1 -0.7853 texture_url ["sim_markers/7.png"] upright TRUE } + +# 5400/2 - 1219.2/2 ± 150/2/sqrt(2) +# 2.14343, 2.03737 diff --git a/simulator/worlds/arena_floor.png b/simulator/worlds/arena_floor.png old mode 100755 new mode 100644 index 73809dc..d33cbfb Binary files a/simulator/worlds/arena_floor.png and b/simulator/worlds/arena_floor.png differ diff --git a/simulator/worlds/sim_markers/0.png b/simulator/worlds/sim_markers/0.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/1.png b/simulator/worlds/sim_markers/1.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/10.png b/simulator/worlds/sim_markers/10.png new file mode 100644 index 0000000..9f9d020 Binary files /dev/null and b/simulator/worlds/sim_markers/10.png differ diff --git a/simulator/worlds/sim_markers/100.png b/simulator/worlds/sim_markers/100.png new file mode 100644 index 0000000..9dfba3d Binary files /dev/null and b/simulator/worlds/sim_markers/100.png differ diff --git a/simulator/worlds/sim_markers/101.png b/simulator/worlds/sim_markers/101.png new file mode 100644 index 0000000..8ca01f1 Binary files /dev/null and b/simulator/worlds/sim_markers/101.png differ diff --git a/simulator/worlds/sim_markers/102.png b/simulator/worlds/sim_markers/102.png new file mode 100644 index 0000000..5d367e4 Binary files /dev/null and b/simulator/worlds/sim_markers/102.png differ diff --git a/simulator/worlds/sim_markers/103.png b/simulator/worlds/sim_markers/103.png new file mode 100644 index 0000000..85fe7a4 Binary files /dev/null and b/simulator/worlds/sim_markers/103.png differ diff --git a/simulator/worlds/sim_markers/104.png b/simulator/worlds/sim_markers/104.png new file mode 100644 index 0000000..78404ef Binary files /dev/null and b/simulator/worlds/sim_markers/104.png differ diff --git a/simulator/worlds/sim_markers/105.png b/simulator/worlds/sim_markers/105.png new file mode 100644 index 0000000..b3d7cdc Binary files /dev/null and b/simulator/worlds/sim_markers/105.png differ diff --git a/simulator/worlds/sim_markers/106.png b/simulator/worlds/sim_markers/106.png new file mode 100644 index 0000000..2f026ee Binary files /dev/null and b/simulator/worlds/sim_markers/106.png differ diff --git a/simulator/worlds/sim_markers/107.png b/simulator/worlds/sim_markers/107.png new file mode 100644 index 0000000..b0eb3af Binary files /dev/null and b/simulator/worlds/sim_markers/107.png differ diff --git a/simulator/worlds/sim_markers/108.png b/simulator/worlds/sim_markers/108.png new file mode 100644 index 0000000..407106f Binary files /dev/null and b/simulator/worlds/sim_markers/108.png differ diff --git a/simulator/worlds/sim_markers/109.png b/simulator/worlds/sim_markers/109.png new file mode 100644 index 0000000..459ca10 Binary files /dev/null and b/simulator/worlds/sim_markers/109.png differ diff --git a/simulator/worlds/sim_markers/11.png b/simulator/worlds/sim_markers/11.png new file mode 100644 index 0000000..4f8a22a Binary files /dev/null and b/simulator/worlds/sim_markers/11.png differ diff --git a/simulator/worlds/sim_markers/110.png b/simulator/worlds/sim_markers/110.png new file mode 100644 index 0000000..0c8d3a7 Binary files /dev/null and b/simulator/worlds/sim_markers/110.png differ diff --git a/simulator/worlds/sim_markers/111.png b/simulator/worlds/sim_markers/111.png new file mode 100644 index 0000000..3238107 Binary files /dev/null and b/simulator/worlds/sim_markers/111.png differ diff --git a/simulator/worlds/sim_markers/112.png b/simulator/worlds/sim_markers/112.png new file mode 100644 index 0000000..31af548 Binary files /dev/null and b/simulator/worlds/sim_markers/112.png differ diff --git a/simulator/worlds/sim_markers/113.png b/simulator/worlds/sim_markers/113.png new file mode 100644 index 0000000..b5e02a4 Binary files /dev/null and b/simulator/worlds/sim_markers/113.png differ diff --git a/simulator/worlds/sim_markers/114.png b/simulator/worlds/sim_markers/114.png new file mode 100644 index 0000000..e1c415e Binary files /dev/null and b/simulator/worlds/sim_markers/114.png differ diff --git a/simulator/worlds/sim_markers/115.png b/simulator/worlds/sim_markers/115.png new file mode 100644 index 0000000..4bafc9e Binary files /dev/null and b/simulator/worlds/sim_markers/115.png differ diff --git a/simulator/worlds/sim_markers/116.png b/simulator/worlds/sim_markers/116.png new file mode 100644 index 0000000..cb1d23c Binary files /dev/null and b/simulator/worlds/sim_markers/116.png differ diff --git a/simulator/worlds/sim_markers/117.png b/simulator/worlds/sim_markers/117.png new file mode 100644 index 0000000..2436087 Binary files /dev/null and b/simulator/worlds/sim_markers/117.png differ diff --git a/simulator/worlds/sim_markers/118.png b/simulator/worlds/sim_markers/118.png new file mode 100644 index 0000000..d2eef38 Binary files /dev/null and b/simulator/worlds/sim_markers/118.png differ diff --git a/simulator/worlds/sim_markers/119.png b/simulator/worlds/sim_markers/119.png new file mode 100644 index 0000000..ccd303d Binary files /dev/null and b/simulator/worlds/sim_markers/119.png differ diff --git a/simulator/worlds/sim_markers/12.png b/simulator/worlds/sim_markers/12.png new file mode 100644 index 0000000..433bf3c Binary files /dev/null and b/simulator/worlds/sim_markers/12.png differ diff --git a/simulator/worlds/sim_markers/120.png b/simulator/worlds/sim_markers/120.png new file mode 100644 index 0000000..8484786 Binary files /dev/null and b/simulator/worlds/sim_markers/120.png differ diff --git a/simulator/worlds/sim_markers/121.png b/simulator/worlds/sim_markers/121.png new file mode 100644 index 0000000..469560b Binary files /dev/null and b/simulator/worlds/sim_markers/121.png differ diff --git a/simulator/worlds/sim_markers/122.png b/simulator/worlds/sim_markers/122.png new file mode 100644 index 0000000..752dece Binary files /dev/null and b/simulator/worlds/sim_markers/122.png differ diff --git a/simulator/worlds/sim_markers/123.png b/simulator/worlds/sim_markers/123.png new file mode 100644 index 0000000..597e62c Binary files /dev/null and b/simulator/worlds/sim_markers/123.png differ diff --git a/simulator/worlds/sim_markers/124.png b/simulator/worlds/sim_markers/124.png new file mode 100644 index 0000000..98564d6 Binary files /dev/null and b/simulator/worlds/sim_markers/124.png differ diff --git a/simulator/worlds/sim_markers/125.png b/simulator/worlds/sim_markers/125.png new file mode 100644 index 0000000..89e07f9 Binary files /dev/null and b/simulator/worlds/sim_markers/125.png differ diff --git a/simulator/worlds/sim_markers/126.png b/simulator/worlds/sim_markers/126.png new file mode 100644 index 0000000..d20ba90 Binary files /dev/null and b/simulator/worlds/sim_markers/126.png differ diff --git a/simulator/worlds/sim_markers/127.png b/simulator/worlds/sim_markers/127.png new file mode 100644 index 0000000..dd211ad Binary files /dev/null and b/simulator/worlds/sim_markers/127.png differ diff --git a/simulator/worlds/sim_markers/128.png b/simulator/worlds/sim_markers/128.png new file mode 100644 index 0000000..d59304d Binary files /dev/null and b/simulator/worlds/sim_markers/128.png differ diff --git a/simulator/worlds/sim_markers/129.png b/simulator/worlds/sim_markers/129.png new file mode 100644 index 0000000..9ead7fa Binary files /dev/null and b/simulator/worlds/sim_markers/129.png differ diff --git a/simulator/worlds/sim_markers/13.png b/simulator/worlds/sim_markers/13.png new file mode 100644 index 0000000..be27c39 Binary files /dev/null and b/simulator/worlds/sim_markers/13.png differ diff --git a/simulator/worlds/sim_markers/130.png b/simulator/worlds/sim_markers/130.png new file mode 100644 index 0000000..a2b6b51 Binary files /dev/null and b/simulator/worlds/sim_markers/130.png differ diff --git a/simulator/worlds/sim_markers/131.png b/simulator/worlds/sim_markers/131.png new file mode 100644 index 0000000..75d111e Binary files /dev/null and b/simulator/worlds/sim_markers/131.png differ diff --git a/simulator/worlds/sim_markers/132.png b/simulator/worlds/sim_markers/132.png new file mode 100644 index 0000000..a6954be Binary files /dev/null and b/simulator/worlds/sim_markers/132.png differ diff --git a/simulator/worlds/sim_markers/133.png b/simulator/worlds/sim_markers/133.png new file mode 100644 index 0000000..1c3d619 Binary files /dev/null and b/simulator/worlds/sim_markers/133.png differ diff --git a/simulator/worlds/sim_markers/134.png b/simulator/worlds/sim_markers/134.png new file mode 100644 index 0000000..0021c42 Binary files /dev/null and b/simulator/worlds/sim_markers/134.png differ diff --git a/simulator/worlds/sim_markers/135.png b/simulator/worlds/sim_markers/135.png new file mode 100644 index 0000000..672b70f Binary files /dev/null and b/simulator/worlds/sim_markers/135.png differ diff --git a/simulator/worlds/sim_markers/136.png b/simulator/worlds/sim_markers/136.png new file mode 100644 index 0000000..02fbd0a Binary files /dev/null and b/simulator/worlds/sim_markers/136.png differ diff --git a/simulator/worlds/sim_markers/137.png b/simulator/worlds/sim_markers/137.png new file mode 100644 index 0000000..93bcf70 Binary files /dev/null and b/simulator/worlds/sim_markers/137.png differ diff --git a/simulator/worlds/sim_markers/138.png b/simulator/worlds/sim_markers/138.png new file mode 100644 index 0000000..a1a16b4 Binary files /dev/null and b/simulator/worlds/sim_markers/138.png differ diff --git a/simulator/worlds/sim_markers/139.png b/simulator/worlds/sim_markers/139.png new file mode 100644 index 0000000..8220cdb Binary files /dev/null and b/simulator/worlds/sim_markers/139.png differ diff --git a/simulator/worlds/sim_markers/14.png b/simulator/worlds/sim_markers/14.png new file mode 100644 index 0000000..d836c56 Binary files /dev/null and b/simulator/worlds/sim_markers/14.png differ diff --git a/simulator/worlds/sim_markers/140.png b/simulator/worlds/sim_markers/140.png new file mode 100644 index 0000000..3623c01 Binary files /dev/null and b/simulator/worlds/sim_markers/140.png differ diff --git a/simulator/worlds/sim_markers/141.png b/simulator/worlds/sim_markers/141.png new file mode 100644 index 0000000..1da9cc9 Binary files /dev/null and b/simulator/worlds/sim_markers/141.png differ diff --git a/simulator/worlds/sim_markers/142.png b/simulator/worlds/sim_markers/142.png new file mode 100644 index 0000000..7b808b5 Binary files /dev/null and b/simulator/worlds/sim_markers/142.png differ diff --git a/simulator/worlds/sim_markers/143.png b/simulator/worlds/sim_markers/143.png new file mode 100644 index 0000000..2229155 Binary files /dev/null and b/simulator/worlds/sim_markers/143.png differ diff --git a/simulator/worlds/sim_markers/144.png b/simulator/worlds/sim_markers/144.png new file mode 100644 index 0000000..a1d2ed2 Binary files /dev/null and b/simulator/worlds/sim_markers/144.png differ diff --git a/simulator/worlds/sim_markers/145.png b/simulator/worlds/sim_markers/145.png new file mode 100644 index 0000000..fdb0828 Binary files /dev/null and b/simulator/worlds/sim_markers/145.png differ diff --git a/simulator/worlds/sim_markers/146.png b/simulator/worlds/sim_markers/146.png new file mode 100644 index 0000000..a0c4787 Binary files /dev/null and b/simulator/worlds/sim_markers/146.png differ diff --git a/simulator/worlds/sim_markers/147.png b/simulator/worlds/sim_markers/147.png new file mode 100644 index 0000000..452915a Binary files /dev/null and b/simulator/worlds/sim_markers/147.png differ diff --git a/simulator/worlds/sim_markers/148.png b/simulator/worlds/sim_markers/148.png new file mode 100644 index 0000000..d07d022 Binary files /dev/null and b/simulator/worlds/sim_markers/148.png differ diff --git a/simulator/worlds/sim_markers/149.png b/simulator/worlds/sim_markers/149.png new file mode 100644 index 0000000..3a3ef5b Binary files /dev/null and b/simulator/worlds/sim_markers/149.png differ diff --git a/simulator/worlds/sim_markers/15.png b/simulator/worlds/sim_markers/15.png new file mode 100644 index 0000000..016e11f Binary files /dev/null and b/simulator/worlds/sim_markers/15.png differ diff --git a/simulator/worlds/sim_markers/150.png b/simulator/worlds/sim_markers/150.png new file mode 100644 index 0000000..50a3c73 Binary files /dev/null and b/simulator/worlds/sim_markers/150.png differ diff --git a/simulator/worlds/sim_markers/151.png b/simulator/worlds/sim_markers/151.png new file mode 100644 index 0000000..2d17931 Binary files /dev/null and b/simulator/worlds/sim_markers/151.png differ diff --git a/simulator/worlds/sim_markers/152.png b/simulator/worlds/sim_markers/152.png new file mode 100644 index 0000000..23d8aa1 Binary files /dev/null and b/simulator/worlds/sim_markers/152.png differ diff --git a/simulator/worlds/sim_markers/153.png b/simulator/worlds/sim_markers/153.png new file mode 100644 index 0000000..53c1cdb Binary files /dev/null and b/simulator/worlds/sim_markers/153.png differ diff --git a/simulator/worlds/sim_markers/154.png b/simulator/worlds/sim_markers/154.png new file mode 100644 index 0000000..e174461 Binary files /dev/null and b/simulator/worlds/sim_markers/154.png differ diff --git a/simulator/worlds/sim_markers/155.png b/simulator/worlds/sim_markers/155.png new file mode 100644 index 0000000..bd83574 Binary files /dev/null and b/simulator/worlds/sim_markers/155.png differ diff --git a/simulator/worlds/sim_markers/156.png b/simulator/worlds/sim_markers/156.png new file mode 100644 index 0000000..5565ad0 Binary files /dev/null and b/simulator/worlds/sim_markers/156.png differ diff --git a/simulator/worlds/sim_markers/157.png b/simulator/worlds/sim_markers/157.png new file mode 100644 index 0000000..9aa7041 Binary files /dev/null and b/simulator/worlds/sim_markers/157.png differ diff --git a/simulator/worlds/sim_markers/158.png b/simulator/worlds/sim_markers/158.png new file mode 100644 index 0000000..30cf7c4 Binary files /dev/null and b/simulator/worlds/sim_markers/158.png differ diff --git a/simulator/worlds/sim_markers/159.png b/simulator/worlds/sim_markers/159.png new file mode 100644 index 0000000..27da7fb Binary files /dev/null and b/simulator/worlds/sim_markers/159.png differ diff --git a/simulator/worlds/sim_markers/16.png b/simulator/worlds/sim_markers/16.png new file mode 100644 index 0000000..150574d Binary files /dev/null and b/simulator/worlds/sim_markers/16.png differ diff --git a/simulator/worlds/sim_markers/160.png b/simulator/worlds/sim_markers/160.png new file mode 100644 index 0000000..23cbe1f Binary files /dev/null and b/simulator/worlds/sim_markers/160.png differ diff --git a/simulator/worlds/sim_markers/161.png b/simulator/worlds/sim_markers/161.png new file mode 100644 index 0000000..37da960 Binary files /dev/null and b/simulator/worlds/sim_markers/161.png differ diff --git a/simulator/worlds/sim_markers/162.png b/simulator/worlds/sim_markers/162.png new file mode 100644 index 0000000..2411703 Binary files /dev/null and b/simulator/worlds/sim_markers/162.png differ diff --git a/simulator/worlds/sim_markers/163.png b/simulator/worlds/sim_markers/163.png new file mode 100644 index 0000000..aa9761d Binary files /dev/null and b/simulator/worlds/sim_markers/163.png differ diff --git a/simulator/worlds/sim_markers/164.png b/simulator/worlds/sim_markers/164.png new file mode 100644 index 0000000..c3cd252 Binary files /dev/null and b/simulator/worlds/sim_markers/164.png differ diff --git a/simulator/worlds/sim_markers/165.png b/simulator/worlds/sim_markers/165.png new file mode 100644 index 0000000..72bab1d Binary files /dev/null and b/simulator/worlds/sim_markers/165.png differ diff --git a/simulator/worlds/sim_markers/166.png b/simulator/worlds/sim_markers/166.png new file mode 100644 index 0000000..94147a1 Binary files /dev/null and b/simulator/worlds/sim_markers/166.png differ diff --git a/simulator/worlds/sim_markers/167.png b/simulator/worlds/sim_markers/167.png new file mode 100644 index 0000000..e20aaa7 Binary files /dev/null and b/simulator/worlds/sim_markers/167.png differ diff --git a/simulator/worlds/sim_markers/168.png b/simulator/worlds/sim_markers/168.png new file mode 100644 index 0000000..b5f06d2 Binary files /dev/null and b/simulator/worlds/sim_markers/168.png differ diff --git a/simulator/worlds/sim_markers/169.png b/simulator/worlds/sim_markers/169.png new file mode 100644 index 0000000..3c909b3 Binary files /dev/null and b/simulator/worlds/sim_markers/169.png differ diff --git a/simulator/worlds/sim_markers/17.png b/simulator/worlds/sim_markers/17.png new file mode 100644 index 0000000..fd85f29 Binary files /dev/null and b/simulator/worlds/sim_markers/17.png differ diff --git a/simulator/worlds/sim_markers/170.png b/simulator/worlds/sim_markers/170.png new file mode 100644 index 0000000..eb79a5b Binary files /dev/null and b/simulator/worlds/sim_markers/170.png differ diff --git a/simulator/worlds/sim_markers/171.png b/simulator/worlds/sim_markers/171.png new file mode 100644 index 0000000..6196162 Binary files /dev/null and b/simulator/worlds/sim_markers/171.png differ diff --git a/simulator/worlds/sim_markers/172.png b/simulator/worlds/sim_markers/172.png new file mode 100644 index 0000000..70f25c3 Binary files /dev/null and b/simulator/worlds/sim_markers/172.png differ diff --git a/simulator/worlds/sim_markers/173.png b/simulator/worlds/sim_markers/173.png new file mode 100644 index 0000000..83a0ab9 Binary files /dev/null and b/simulator/worlds/sim_markers/173.png differ diff --git a/simulator/worlds/sim_markers/174.png b/simulator/worlds/sim_markers/174.png new file mode 100644 index 0000000..0931ea7 Binary files /dev/null and b/simulator/worlds/sim_markers/174.png differ diff --git a/simulator/worlds/sim_markers/175.png b/simulator/worlds/sim_markers/175.png new file mode 100644 index 0000000..e6e478b Binary files /dev/null and b/simulator/worlds/sim_markers/175.png differ diff --git a/simulator/worlds/sim_markers/176.png b/simulator/worlds/sim_markers/176.png new file mode 100644 index 0000000..4c4825a Binary files /dev/null and b/simulator/worlds/sim_markers/176.png differ diff --git a/simulator/worlds/sim_markers/177.png b/simulator/worlds/sim_markers/177.png new file mode 100644 index 0000000..4aaf781 Binary files /dev/null and b/simulator/worlds/sim_markers/177.png differ diff --git a/simulator/worlds/sim_markers/178.png b/simulator/worlds/sim_markers/178.png new file mode 100644 index 0000000..743bb6c Binary files /dev/null and b/simulator/worlds/sim_markers/178.png differ diff --git a/simulator/worlds/sim_markers/179.png b/simulator/worlds/sim_markers/179.png new file mode 100644 index 0000000..9597777 Binary files /dev/null and b/simulator/worlds/sim_markers/179.png differ diff --git a/simulator/worlds/sim_markers/18.png b/simulator/worlds/sim_markers/18.png new file mode 100644 index 0000000..1770cba Binary files /dev/null and b/simulator/worlds/sim_markers/18.png differ diff --git a/simulator/worlds/sim_markers/180.png b/simulator/worlds/sim_markers/180.png new file mode 100644 index 0000000..f54d18a Binary files /dev/null and b/simulator/worlds/sim_markers/180.png differ diff --git a/simulator/worlds/sim_markers/181.png b/simulator/worlds/sim_markers/181.png new file mode 100644 index 0000000..b0929ec Binary files /dev/null and b/simulator/worlds/sim_markers/181.png differ diff --git a/simulator/worlds/sim_markers/182.png b/simulator/worlds/sim_markers/182.png new file mode 100644 index 0000000..a1374ad Binary files /dev/null and b/simulator/worlds/sim_markers/182.png differ diff --git a/simulator/worlds/sim_markers/183.png b/simulator/worlds/sim_markers/183.png new file mode 100644 index 0000000..406ed24 Binary files /dev/null and b/simulator/worlds/sim_markers/183.png differ diff --git a/simulator/worlds/sim_markers/184.png b/simulator/worlds/sim_markers/184.png new file mode 100644 index 0000000..b2847f4 Binary files /dev/null and b/simulator/worlds/sim_markers/184.png differ diff --git a/simulator/worlds/sim_markers/185.png b/simulator/worlds/sim_markers/185.png new file mode 100644 index 0000000..ad876e6 Binary files /dev/null and b/simulator/worlds/sim_markers/185.png differ diff --git a/simulator/worlds/sim_markers/186.png b/simulator/worlds/sim_markers/186.png new file mode 100644 index 0000000..cab4721 Binary files /dev/null and b/simulator/worlds/sim_markers/186.png differ diff --git a/simulator/worlds/sim_markers/187.png b/simulator/worlds/sim_markers/187.png new file mode 100644 index 0000000..640f08d Binary files /dev/null and b/simulator/worlds/sim_markers/187.png differ diff --git a/simulator/worlds/sim_markers/188.png b/simulator/worlds/sim_markers/188.png new file mode 100644 index 0000000..c8aab3f Binary files /dev/null and b/simulator/worlds/sim_markers/188.png differ diff --git a/simulator/worlds/sim_markers/189.png b/simulator/worlds/sim_markers/189.png new file mode 100644 index 0000000..b028e4e Binary files /dev/null and b/simulator/worlds/sim_markers/189.png differ diff --git a/simulator/worlds/sim_markers/19.png b/simulator/worlds/sim_markers/19.png new file mode 100644 index 0000000..21a9b25 Binary files /dev/null and b/simulator/worlds/sim_markers/19.png differ diff --git a/simulator/worlds/sim_markers/190.png b/simulator/worlds/sim_markers/190.png new file mode 100644 index 0000000..db9b2e6 Binary files /dev/null and b/simulator/worlds/sim_markers/190.png differ diff --git a/simulator/worlds/sim_markers/191.png b/simulator/worlds/sim_markers/191.png new file mode 100644 index 0000000..5749c45 Binary files /dev/null and b/simulator/worlds/sim_markers/191.png differ diff --git a/simulator/worlds/sim_markers/192.png b/simulator/worlds/sim_markers/192.png new file mode 100644 index 0000000..93b9dea Binary files /dev/null and b/simulator/worlds/sim_markers/192.png differ diff --git a/simulator/worlds/sim_markers/193.png b/simulator/worlds/sim_markers/193.png new file mode 100644 index 0000000..80ef0ac Binary files /dev/null and b/simulator/worlds/sim_markers/193.png differ diff --git a/simulator/worlds/sim_markers/194.png b/simulator/worlds/sim_markers/194.png new file mode 100644 index 0000000..d59fa48 Binary files /dev/null and b/simulator/worlds/sim_markers/194.png differ diff --git a/simulator/worlds/sim_markers/195.png b/simulator/worlds/sim_markers/195.png new file mode 100644 index 0000000..7c4bc55 Binary files /dev/null and b/simulator/worlds/sim_markers/195.png differ diff --git a/simulator/worlds/sim_markers/196.png b/simulator/worlds/sim_markers/196.png new file mode 100644 index 0000000..c767a64 Binary files /dev/null and b/simulator/worlds/sim_markers/196.png differ diff --git a/simulator/worlds/sim_markers/197.png b/simulator/worlds/sim_markers/197.png new file mode 100644 index 0000000..fe82602 Binary files /dev/null and b/simulator/worlds/sim_markers/197.png differ diff --git a/simulator/worlds/sim_markers/198.png b/simulator/worlds/sim_markers/198.png new file mode 100644 index 0000000..8c80b6f Binary files /dev/null and b/simulator/worlds/sim_markers/198.png differ diff --git a/simulator/worlds/sim_markers/199.png b/simulator/worlds/sim_markers/199.png new file mode 100644 index 0000000..7f836f7 Binary files /dev/null and b/simulator/worlds/sim_markers/199.png differ diff --git a/simulator/worlds/sim_markers/2.png b/simulator/worlds/sim_markers/2.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/20.png b/simulator/worlds/sim_markers/20.png new file mode 100644 index 0000000..43afd2d Binary files /dev/null and b/simulator/worlds/sim_markers/20.png differ diff --git a/simulator/worlds/sim_markers/21.png b/simulator/worlds/sim_markers/21.png new file mode 100644 index 0000000..9821a95 Binary files /dev/null and b/simulator/worlds/sim_markers/21.png differ diff --git a/simulator/worlds/sim_markers/22.png b/simulator/worlds/sim_markers/22.png new file mode 100644 index 0000000..f7a1ee6 Binary files /dev/null and b/simulator/worlds/sim_markers/22.png differ diff --git a/simulator/worlds/sim_markers/23.png b/simulator/worlds/sim_markers/23.png new file mode 100644 index 0000000..0219121 Binary files /dev/null and b/simulator/worlds/sim_markers/23.png differ diff --git a/simulator/worlds/sim_markers/24.png b/simulator/worlds/sim_markers/24.png new file mode 100644 index 0000000..ecc7bc8 Binary files /dev/null and b/simulator/worlds/sim_markers/24.png differ diff --git a/simulator/worlds/sim_markers/25.png b/simulator/worlds/sim_markers/25.png new file mode 100644 index 0000000..2bbe12c Binary files /dev/null and b/simulator/worlds/sim_markers/25.png differ diff --git a/simulator/worlds/sim_markers/26.png b/simulator/worlds/sim_markers/26.png new file mode 100644 index 0000000..e7588af Binary files /dev/null and b/simulator/worlds/sim_markers/26.png differ diff --git a/simulator/worlds/sim_markers/27.png b/simulator/worlds/sim_markers/27.png new file mode 100644 index 0000000..4f78b69 Binary files /dev/null and b/simulator/worlds/sim_markers/27.png differ diff --git a/simulator/worlds/sim_markers/28.png b/simulator/worlds/sim_markers/28.png new file mode 100644 index 0000000..c0c75c4 Binary files /dev/null and b/simulator/worlds/sim_markers/28.png differ diff --git a/simulator/worlds/sim_markers/29.png b/simulator/worlds/sim_markers/29.png new file mode 100644 index 0000000..1a47104 Binary files /dev/null and b/simulator/worlds/sim_markers/29.png differ diff --git a/simulator/worlds/sim_markers/3.png b/simulator/worlds/sim_markers/3.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/30.png b/simulator/worlds/sim_markers/30.png new file mode 100644 index 0000000..15272df Binary files /dev/null and b/simulator/worlds/sim_markers/30.png differ diff --git a/simulator/worlds/sim_markers/31.png b/simulator/worlds/sim_markers/31.png new file mode 100644 index 0000000..39d6615 Binary files /dev/null and b/simulator/worlds/sim_markers/31.png differ diff --git a/simulator/worlds/sim_markers/32.png b/simulator/worlds/sim_markers/32.png new file mode 100644 index 0000000..dcf5af2 Binary files /dev/null and b/simulator/worlds/sim_markers/32.png differ diff --git a/simulator/worlds/sim_markers/33.png b/simulator/worlds/sim_markers/33.png new file mode 100644 index 0000000..ad84316 Binary files /dev/null and b/simulator/worlds/sim_markers/33.png differ diff --git a/simulator/worlds/sim_markers/34.png b/simulator/worlds/sim_markers/34.png new file mode 100644 index 0000000..c7189c8 Binary files /dev/null and b/simulator/worlds/sim_markers/34.png differ diff --git a/simulator/worlds/sim_markers/35.png b/simulator/worlds/sim_markers/35.png new file mode 100644 index 0000000..02bcf56 Binary files /dev/null and b/simulator/worlds/sim_markers/35.png differ diff --git a/simulator/worlds/sim_markers/36.png b/simulator/worlds/sim_markers/36.png new file mode 100644 index 0000000..3644bbc Binary files /dev/null and b/simulator/worlds/sim_markers/36.png differ diff --git a/simulator/worlds/sim_markers/37.png b/simulator/worlds/sim_markers/37.png new file mode 100644 index 0000000..168d819 Binary files /dev/null and b/simulator/worlds/sim_markers/37.png differ diff --git a/simulator/worlds/sim_markers/38.png b/simulator/worlds/sim_markers/38.png new file mode 100644 index 0000000..50c18e9 Binary files /dev/null and b/simulator/worlds/sim_markers/38.png differ diff --git a/simulator/worlds/sim_markers/39.png b/simulator/worlds/sim_markers/39.png new file mode 100644 index 0000000..069b1ba Binary files /dev/null and b/simulator/worlds/sim_markers/39.png differ diff --git a/simulator/worlds/sim_markers/4.png b/simulator/worlds/sim_markers/4.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/40.png b/simulator/worlds/sim_markers/40.png new file mode 100644 index 0000000..38582e4 Binary files /dev/null and b/simulator/worlds/sim_markers/40.png differ diff --git a/simulator/worlds/sim_markers/41.png b/simulator/worlds/sim_markers/41.png new file mode 100644 index 0000000..6c5b405 Binary files /dev/null and b/simulator/worlds/sim_markers/41.png differ diff --git a/simulator/worlds/sim_markers/42.png b/simulator/worlds/sim_markers/42.png new file mode 100644 index 0000000..9a8959d Binary files /dev/null and b/simulator/worlds/sim_markers/42.png differ diff --git a/simulator/worlds/sim_markers/43.png b/simulator/worlds/sim_markers/43.png new file mode 100644 index 0000000..c4f9127 Binary files /dev/null and b/simulator/worlds/sim_markers/43.png differ diff --git a/simulator/worlds/sim_markers/44.png b/simulator/worlds/sim_markers/44.png new file mode 100644 index 0000000..eecf1da Binary files /dev/null and b/simulator/worlds/sim_markers/44.png differ diff --git a/simulator/worlds/sim_markers/45.png b/simulator/worlds/sim_markers/45.png new file mode 100644 index 0000000..f4d2a10 Binary files /dev/null and b/simulator/worlds/sim_markers/45.png differ diff --git a/simulator/worlds/sim_markers/46.png b/simulator/worlds/sim_markers/46.png new file mode 100644 index 0000000..36bb7e4 Binary files /dev/null and b/simulator/worlds/sim_markers/46.png differ diff --git a/simulator/worlds/sim_markers/47.png b/simulator/worlds/sim_markers/47.png new file mode 100644 index 0000000..1fde55b Binary files /dev/null and b/simulator/worlds/sim_markers/47.png differ diff --git a/simulator/worlds/sim_markers/48.png b/simulator/worlds/sim_markers/48.png new file mode 100644 index 0000000..160e6c8 Binary files /dev/null and b/simulator/worlds/sim_markers/48.png differ diff --git a/simulator/worlds/sim_markers/49.png b/simulator/worlds/sim_markers/49.png new file mode 100644 index 0000000..a4242fb Binary files /dev/null and b/simulator/worlds/sim_markers/49.png differ diff --git a/simulator/worlds/sim_markers/5.png b/simulator/worlds/sim_markers/5.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/50.png b/simulator/worlds/sim_markers/50.png new file mode 100644 index 0000000..8e39247 Binary files /dev/null and b/simulator/worlds/sim_markers/50.png differ diff --git a/simulator/worlds/sim_markers/51.png b/simulator/worlds/sim_markers/51.png new file mode 100644 index 0000000..d568e2b Binary files /dev/null and b/simulator/worlds/sim_markers/51.png differ diff --git a/simulator/worlds/sim_markers/52.png b/simulator/worlds/sim_markers/52.png new file mode 100644 index 0000000..0c1ee41 Binary files /dev/null and b/simulator/worlds/sim_markers/52.png differ diff --git a/simulator/worlds/sim_markers/53.png b/simulator/worlds/sim_markers/53.png new file mode 100644 index 0000000..73380a8 Binary files /dev/null and b/simulator/worlds/sim_markers/53.png differ diff --git a/simulator/worlds/sim_markers/54.png b/simulator/worlds/sim_markers/54.png new file mode 100644 index 0000000..b5460c2 Binary files /dev/null and b/simulator/worlds/sim_markers/54.png differ diff --git a/simulator/worlds/sim_markers/55.png b/simulator/worlds/sim_markers/55.png new file mode 100644 index 0000000..728a1c4 Binary files /dev/null and b/simulator/worlds/sim_markers/55.png differ diff --git a/simulator/worlds/sim_markers/56.png b/simulator/worlds/sim_markers/56.png new file mode 100644 index 0000000..002528d Binary files /dev/null and b/simulator/worlds/sim_markers/56.png differ diff --git a/simulator/worlds/sim_markers/57.png b/simulator/worlds/sim_markers/57.png new file mode 100644 index 0000000..2bf0341 Binary files /dev/null and b/simulator/worlds/sim_markers/57.png differ diff --git a/simulator/worlds/sim_markers/58.png b/simulator/worlds/sim_markers/58.png new file mode 100644 index 0000000..e357a90 Binary files /dev/null and b/simulator/worlds/sim_markers/58.png differ diff --git a/simulator/worlds/sim_markers/59.png b/simulator/worlds/sim_markers/59.png new file mode 100644 index 0000000..2e068fb Binary files /dev/null and b/simulator/worlds/sim_markers/59.png differ diff --git a/simulator/worlds/sim_markers/6.png b/simulator/worlds/sim_markers/6.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/60.png b/simulator/worlds/sim_markers/60.png new file mode 100644 index 0000000..b5a1c25 Binary files /dev/null and b/simulator/worlds/sim_markers/60.png differ diff --git a/simulator/worlds/sim_markers/61.png b/simulator/worlds/sim_markers/61.png new file mode 100644 index 0000000..0b1ddec Binary files /dev/null and b/simulator/worlds/sim_markers/61.png differ diff --git a/simulator/worlds/sim_markers/62.png b/simulator/worlds/sim_markers/62.png new file mode 100644 index 0000000..a3d6857 Binary files /dev/null and b/simulator/worlds/sim_markers/62.png differ diff --git a/simulator/worlds/sim_markers/63.png b/simulator/worlds/sim_markers/63.png new file mode 100644 index 0000000..49305f7 Binary files /dev/null and b/simulator/worlds/sim_markers/63.png differ diff --git a/simulator/worlds/sim_markers/64.png b/simulator/worlds/sim_markers/64.png new file mode 100644 index 0000000..ce48abf Binary files /dev/null and b/simulator/worlds/sim_markers/64.png differ diff --git a/simulator/worlds/sim_markers/65.png b/simulator/worlds/sim_markers/65.png new file mode 100644 index 0000000..d274f4a Binary files /dev/null and b/simulator/worlds/sim_markers/65.png differ diff --git a/simulator/worlds/sim_markers/66.png b/simulator/worlds/sim_markers/66.png new file mode 100644 index 0000000..920b781 Binary files /dev/null and b/simulator/worlds/sim_markers/66.png differ diff --git a/simulator/worlds/sim_markers/67.png b/simulator/worlds/sim_markers/67.png new file mode 100644 index 0000000..ad63088 Binary files /dev/null and b/simulator/worlds/sim_markers/67.png differ diff --git a/simulator/worlds/sim_markers/68.png b/simulator/worlds/sim_markers/68.png new file mode 100644 index 0000000..5ae63ff Binary files /dev/null and b/simulator/worlds/sim_markers/68.png differ diff --git a/simulator/worlds/sim_markers/69.png b/simulator/worlds/sim_markers/69.png new file mode 100644 index 0000000..3e88a2d Binary files /dev/null and b/simulator/worlds/sim_markers/69.png differ diff --git a/simulator/worlds/sim_markers/7.png b/simulator/worlds/sim_markers/7.png old mode 100755 new mode 100644 diff --git a/simulator/worlds/sim_markers/70.png b/simulator/worlds/sim_markers/70.png new file mode 100644 index 0000000..256af9a Binary files /dev/null and b/simulator/worlds/sim_markers/70.png differ diff --git a/simulator/worlds/sim_markers/71.png b/simulator/worlds/sim_markers/71.png new file mode 100644 index 0000000..132b709 Binary files /dev/null and b/simulator/worlds/sim_markers/71.png differ diff --git a/simulator/worlds/sim_markers/72.png b/simulator/worlds/sim_markers/72.png new file mode 100644 index 0000000..681707b Binary files /dev/null and b/simulator/worlds/sim_markers/72.png differ diff --git a/simulator/worlds/sim_markers/73.png b/simulator/worlds/sim_markers/73.png new file mode 100644 index 0000000..8a90fe7 Binary files /dev/null and b/simulator/worlds/sim_markers/73.png differ diff --git a/simulator/worlds/sim_markers/74.png b/simulator/worlds/sim_markers/74.png new file mode 100644 index 0000000..535aeb5 Binary files /dev/null and b/simulator/worlds/sim_markers/74.png differ diff --git a/simulator/worlds/sim_markers/75.png b/simulator/worlds/sim_markers/75.png new file mode 100644 index 0000000..414088e Binary files /dev/null and b/simulator/worlds/sim_markers/75.png differ diff --git a/simulator/worlds/sim_markers/76.png b/simulator/worlds/sim_markers/76.png new file mode 100644 index 0000000..10f9564 Binary files /dev/null and b/simulator/worlds/sim_markers/76.png differ diff --git a/simulator/worlds/sim_markers/77.png b/simulator/worlds/sim_markers/77.png new file mode 100644 index 0000000..2ce1a55 Binary files /dev/null and b/simulator/worlds/sim_markers/77.png differ diff --git a/simulator/worlds/sim_markers/78.png b/simulator/worlds/sim_markers/78.png new file mode 100644 index 0000000..64712f3 Binary files /dev/null and b/simulator/worlds/sim_markers/78.png differ diff --git a/simulator/worlds/sim_markers/79.png b/simulator/worlds/sim_markers/79.png new file mode 100644 index 0000000..31016f3 Binary files /dev/null and b/simulator/worlds/sim_markers/79.png differ diff --git a/simulator/worlds/sim_markers/8.png b/simulator/worlds/sim_markers/8.png new file mode 100644 index 0000000..620b70c Binary files /dev/null and b/simulator/worlds/sim_markers/8.png differ diff --git a/simulator/worlds/sim_markers/80.png b/simulator/worlds/sim_markers/80.png new file mode 100644 index 0000000..d24c254 Binary files /dev/null and b/simulator/worlds/sim_markers/80.png differ diff --git a/simulator/worlds/sim_markers/81.png b/simulator/worlds/sim_markers/81.png new file mode 100644 index 0000000..0d926a5 Binary files /dev/null and b/simulator/worlds/sim_markers/81.png differ diff --git a/simulator/worlds/sim_markers/82.png b/simulator/worlds/sim_markers/82.png new file mode 100644 index 0000000..062e181 Binary files /dev/null and b/simulator/worlds/sim_markers/82.png differ diff --git a/simulator/worlds/sim_markers/83.png b/simulator/worlds/sim_markers/83.png new file mode 100644 index 0000000..4aee9c6 Binary files /dev/null and b/simulator/worlds/sim_markers/83.png differ diff --git a/simulator/worlds/sim_markers/84.png b/simulator/worlds/sim_markers/84.png new file mode 100644 index 0000000..98d817d Binary files /dev/null and b/simulator/worlds/sim_markers/84.png differ diff --git a/simulator/worlds/sim_markers/85.png b/simulator/worlds/sim_markers/85.png new file mode 100644 index 0000000..bf8e6d0 Binary files /dev/null and b/simulator/worlds/sim_markers/85.png differ diff --git a/simulator/worlds/sim_markers/86.png b/simulator/worlds/sim_markers/86.png new file mode 100644 index 0000000..07647b9 Binary files /dev/null and b/simulator/worlds/sim_markers/86.png differ diff --git a/simulator/worlds/sim_markers/87.png b/simulator/worlds/sim_markers/87.png new file mode 100644 index 0000000..6135815 Binary files /dev/null and b/simulator/worlds/sim_markers/87.png differ diff --git a/simulator/worlds/sim_markers/88.png b/simulator/worlds/sim_markers/88.png new file mode 100644 index 0000000..08db45e Binary files /dev/null and b/simulator/worlds/sim_markers/88.png differ diff --git a/simulator/worlds/sim_markers/89.png b/simulator/worlds/sim_markers/89.png new file mode 100644 index 0000000..8c3a4b3 Binary files /dev/null and b/simulator/worlds/sim_markers/89.png differ diff --git a/simulator/worlds/sim_markers/9.png b/simulator/worlds/sim_markers/9.png new file mode 100644 index 0000000..c8f5c56 Binary files /dev/null and b/simulator/worlds/sim_markers/9.png differ diff --git a/simulator/worlds/sim_markers/90.png b/simulator/worlds/sim_markers/90.png new file mode 100644 index 0000000..2c9a456 Binary files /dev/null and b/simulator/worlds/sim_markers/90.png differ diff --git a/simulator/worlds/sim_markers/91.png b/simulator/worlds/sim_markers/91.png new file mode 100644 index 0000000..ce51aa1 Binary files /dev/null and b/simulator/worlds/sim_markers/91.png differ diff --git a/simulator/worlds/sim_markers/92.png b/simulator/worlds/sim_markers/92.png new file mode 100644 index 0000000..ac0bd57 Binary files /dev/null and b/simulator/worlds/sim_markers/92.png differ diff --git a/simulator/worlds/sim_markers/93.png b/simulator/worlds/sim_markers/93.png new file mode 100644 index 0000000..7db9d98 Binary files /dev/null and b/simulator/worlds/sim_markers/93.png differ diff --git a/simulator/worlds/sim_markers/94.png b/simulator/worlds/sim_markers/94.png new file mode 100644 index 0000000..331cb70 Binary files /dev/null and b/simulator/worlds/sim_markers/94.png differ diff --git a/simulator/worlds/sim_markers/95.png b/simulator/worlds/sim_markers/95.png new file mode 100644 index 0000000..5a26028 Binary files /dev/null and b/simulator/worlds/sim_markers/95.png differ diff --git a/simulator/worlds/sim_markers/96.png b/simulator/worlds/sim_markers/96.png new file mode 100644 index 0000000..75b4988 Binary files /dev/null and b/simulator/worlds/sim_markers/96.png differ diff --git a/simulator/worlds/sim_markers/97.png b/simulator/worlds/sim_markers/97.png new file mode 100644 index 0000000..dd8f5cc Binary files /dev/null and b/simulator/worlds/sim_markers/97.png differ diff --git a/simulator/worlds/sim_markers/98.png b/simulator/worlds/sim_markers/98.png new file mode 100644 index 0000000..2e7bc85 Binary files /dev/null and b/simulator/worlds/sim_markers/98.png differ diff --git a/simulator/worlds/sim_markers/99.png b/simulator/worlds/sim_markers/99.png new file mode 100644 index 0000000..ca417e6 Binary files /dev/null and b/simulator/worlds/sim_markers/99.png differ