diff --git a/docs/batched_commands.rst b/docs/batched_commands.rst deleted file mode 100644 index a32fe1ee..00000000 --- a/docs/batched_commands.rst +++ /dev/null @@ -1,67 +0,0 @@ -Simulation Presets -================== - -What is a simulation preset? ----------------------------- - -When running a simulation with EV3Sim, you need two things: - -* A world to simulate and interact with, and -* Robots to interact with the simulated world. - -A simulation preset specifies which world to simulate, the bots that will be placed in the simulation, and any settings specific to that world. - -As an example, one simulation preset provided by default is the ``soccer_competition`` preset. This specifies the world (preset type) as Soccer, and then specifies which bots are on which team. -It also specifies soccer specific settings, such as the Team Names, rulings for out on white, and halftime length. - -Changing the robots in a simulation ------------------------------------ - -While selecting a simulation preset the following icon should light up: - -.. image:: images/robot_selection.png - :width: 600 - :alt: The simulation select screen, highlighting the robot select button. - -From here, you can select a bot from those you have defined, and select them for Team 1 or Team 2. After selecting the bot for Team 1, Bot 1, you then select the bot for Team 2, Bot 1, and so on. -At any point if you have enough bots in the simulation, you can click "Done" to finish. - -Changing simulation settings ----------------------------- - -Clicking the settings cog instead of the robot button will take you to the settings page for you simulation preset: - -.. image:: images/settings_cog.png - :width: 600 - :alt: The simulation select screen, highlighting the settings button. - -.. image:: images/settings.png - :width: 600 - :alt: The simulation preset settings page, for the soccer preset. - -Creating a simulation preset ----------------------------- - -Rather than editing an existing preset you can also create your own by clicking the plus button on the list view for simulation presets. -This will prompt you to select a world type (Such as Soccer or Rescue). - -.. image:: images/add_sim.png - :width: 600 - :alt: The simulation select screen, highlighting the new sim button. - -Running the simulation preset ------------------------------ - -To run your simulation presets, you can press the big green play button to begin. - -.. image:: images/play_button.png - :width: 600 - :alt: The simulation select screen, highlighting the sim start button. - -However, if you installed with the windows one-click executable, you can also run the simulation simply by double clicking a file! -Navigate to your workspace folder, and open the ``sims`` directory. This should contain all of the sims you have created in the form of ``.sim`` files. - -Double clicking should run the sim by default. Otherwise, you can right click and select one of two actions: - -* Open: Run the simulation. -* Edit: Open the settings page for the simulation. diff --git a/docs/bot_editing.rst b/docs/bot_editing.rst index d3fc0527..4e952225 100644 --- a/docs/bot_editing.rst +++ b/docs/bot_editing.rst @@ -13,8 +13,6 @@ If you want to change the design of an existing bot, you can select that bot and :width: 600 :alt: The bot select screen highlighting the new and edit buttons. -If you have the windows one click install, you can also find your bot in ``workspace/robots`` and right click, select ``Open`` to edit the bot. - If you are creating a new bot, you'll be prompted to pick a baseplate for the bot. The baseplate is the object that all other components of your robot will rest on. This can be a circle, a regular polygon, or a rectangle. @@ -36,7 +34,7 @@ There are 4 types of elements: * Devices (Motors, Sensors, Buttons) Click the respective icon on the left sidebar to select that element. -If you instead click the cursor icon, you will be return to select mode, where you can select elements already on the bot, and change/remove them. +If you instead click the cursor icon, you will be returned to select mode, where you can select elements already on the bot, and change/remove them. .. image:: images/bot_edit_holding_elements.png :width: 600 @@ -51,7 +49,7 @@ Modifying elements ^^^^^^^^^^^^^^^^^^ To modify an element on the robot, we first need to enter the selecting mode, by clicking the cursor icon on the left sidebar. -Then, click on the element to select it. After this, the bottom bar should populate with properties to edit: +Then, click and drag to move an element, or click on the element to select it. After this, the bottom bar should populate with properties to edit: * Rotation * Fill and Stroke colour @@ -63,9 +61,7 @@ And many others. You can edit these properties and see them change in real time Any numerical property can be edited simply by typing out the value you want, after clicking in the box. You can also scroll while hovering over the value to increase/decrease it with ease. -The fill and stroke properties can be change by clicking the colour swatch next to it. This should open a colour picker. - -The device port entry can be whatever you want it to be, but this property tends to be ``in1,in2,in3...`` for sensors, and ``outA,outB,outC...`` for motors. +The fill and stroke properties can be changed by clicking the colour swatch next to it. This should open a colour picker. .. image:: images/bot_edit_properties.png :width: 600 @@ -81,17 +77,12 @@ Additionally, the backspace key should also remove the element. Adding code to a bot -------------------- -Designing a good bot also includes designing code to run! You can specify the code location for a specific bot by selecting it in the bot menu and pressing the settings cog. +Designing a good bot also includes designing code to run! -If you have the windows one click install, you can also find your bot in ``workspace/robots`` and right click, select ``Edit`` to go to the same window. +You can design this code by selecting the Folder icon when the bot is selected. This should open up a window with a folder containing three items: -.. image:: images/bot_menu_settings.png - :width: 600 - :alt: The bot menu screen, showing the bot properties cog. +* ``code.py`` - The python file your program will run. +* ``config.bot`` - Your robot information stored in a file. +* ``preview.png`` - A preview of your bot. -Then press the button next to 'Bot script' to open the file selector. -All code you want to run on your bot should be located in the ``code`` folder of your workspace! - -.. image:: images/bot_edit_code.png - :width: 600 - :alt: The bot property editing screen, showing the code location button. +To design code for your robot, simply edit the contents of ``code.py``. \ No newline at end of file diff --git a/docs/custom_presets.rst b/docs/custom_presets.rst index a8353b60..a84e7828 100644 --- a/docs/custom_presets.rst +++ b/docs/custom_presets.rst @@ -3,4 +3,6 @@ Custom Preset Types You can actually define your own preset types such as soccer and rescue, and run them through EV3Sim! -I haven't documented this because I'm not sure anyone will read this far. If you do want some information on this however, let me know with an issue on github and I can give you some help as well as populate this page! +I haven't documented this because I'm not sure anyone will read this far. If you do want some information on this however, let me know with an `issue on github`_ and I can give you some help as well as populate this page! + +.. _issue on github: https://github.com/MelbourneHighSchoolRobotics/ev3sim/issues \ No newline at end of file diff --git a/docs/ev3_extensions.rst b/docs/ev3_extensions.rst index 335f5f67..de75ba64 100644 --- a/docs/ev3_extensions.rst +++ b/docs/ev3_extensions.rst @@ -5,12 +5,12 @@ While your robots still run python-ev3dev2 code in the simulation, you also have Almost all of the below functionality is available in the package ``ev3sim.code_helpers``. In order for this code to work on your physical robot, there also needs to be a package on the physical bot filesystem called ``ev3sim.code_helpers``, containing `this file`_. -For a demo of most of these features, see ``demo.bot`` in the simulator. The code it runs is available `here`_. +For a demo of most of these features, see the ``demo`` bot in the simulator. The code it runs is available `here`_. Waiting for simulation ticks ---------------------------- -As most ev3 programs tend to have a single loop which handles all of the robot's logic, in the interest of efficiency on simulator we highly recommend you attempt to sync this program loop up with each tick of the simulator. +As most ev3 programs tend to have a single loop which handles all of the robot's logic, in the interest of efficiency on simulator it is essentially required that you attempt to sync this program loop up with each tick of the simulator. This is because running multiple program loops per simulation tick is useless (as sensor values won't change) and it can degrade the reliability of sensor values in future, if this program is spending a lot of CPU time running these pointless loops. You can achieve such a sync with the ``wait_for_tick`` method from the code helpers: @@ -21,9 +21,10 @@ You can achieve such a sync with the ``wait_for_tick`` method from the code help while True: # Program logic... + # Wait for the next simulation tick before I continue... wait_for_tick() -Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). +Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run on a physical bot (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). Robot ID -------- @@ -38,7 +39,7 @@ Since you might be running multiple instances of the same code on different robo This will also work on the brick, it should print "Robot-0". -Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). +Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run on a physical bot (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). Printing to console ------------------- @@ -81,7 +82,7 @@ Example: # This message will stay on the console for 3 seconds format_print("Hello world!") # This message will stay on the console for 5 seconds - format_print("Hello world!", life=3) + format_print("Hello world!", life=5) # This message will stay on the console for 1 second. format_print("Hello world!", life=1) @@ -107,7 +108,7 @@ This message will stay open in the console, and its message contents will change Logs ---- -All prints made to the console will also be stored in log files. These log files are available in your workspace if the workspace is defined. Otherwise they will be stored in your EV3Sim install location. +All prints made to the console will also be stored in log files (As well as error messages). These log files are available in your workspace if the workspace is defined. Otherwise they will be stored in your EV3Sim install location. Simulation testing ------------------ @@ -126,7 +127,7 @@ As an example, the simulator currently does not implement the ``Led`` functional if is_sim: print("Hello from the sim! Sadly I can't do lights at the moment :(") -Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). +Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run on a physical bot (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). Handling simulation events -------------------------- @@ -149,12 +150,12 @@ To handle such events you can use the code helpers EventSystem: EventSystem.on_goal_scored = handle_scored while True: - EventSystem.handle_events() wait_for_tick() + EventSystem.handle_events() ``EventSystem.handle_events`` must be called often (ie in every loop iteration, simply add this line after every occurrence of ``wait_for_tick``) to allow such events to fire the related code. Any event in the system returns a data object, which will contain any useful information about the event. -Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). +Importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run on a physical bot (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). The full list of events is: @@ -169,7 +170,7 @@ Fires whenever a goal is scored by either team. Fires whenever the game is reset manually. ``on_penalty_start`` -^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^ Fires whenever you are placed in the penalty box. ``on_penalty_end`` @@ -188,7 +189,7 @@ Here is the list of supported commands: ``CommandSystem.TYPE_DRAW`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Draws an object to the screen using the same syntax as the simulator. The data passed in must be a dictionary with the following keys: +Draws an object to the screen using the same syntax as the simulator source code. The data passed in must be a dictionary with the following keys: - ``obj``: The visual representation of the object. - ``key``: The key the visual object will be referenced by (This means you can update the object position by sending the same key). @@ -198,7 +199,7 @@ Draws an object to the screen using the same syntax as the simulator. The data p ``CommandSystem.TYPE_CUSTOM`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A custom event that can be caught by any custom presets you want to define. +A custom event that can be caught by any custom simulations you want to define. Example: @@ -247,14 +248,14 @@ As bluetooth communications are a popular option for complicated strategies with The communications are written in a client/server architecture, as with normal use of bluetooth comms. -This should also work on the physical robots over bluetooth, provided that the MAC Address and port are correct (Follow the instructions for normal bluetooth connectivity). As with above importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). +This should also work on the physical robots over bluetooth, provided that the MAC Address and port are correct (Follow the instructions for normal bluetooth connectivity). As with above importing this means you need to transfer ``ev3sim/code_helpers.py`` onto the brick for this to run on a physical bot (Just create a folder named ``ev3sim`` and place `code_helpers.py`_ in there). For an example of robots communicating device data to each other (in this case through a server, but client/server messaging could also simply work between two robots) try this example (place all 4 commands in separate terminals), you can run the simulation preset ``ev3sim/examples/sims/communications_demo.yaml`` Sources: `communication_client.py`_, `communication_server.py`_ -.. _here: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/examples/robots/demo.py +.. _here: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/examples/robots/demo/code.py .. _this file: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/code_helpers.py .. _code_helpers.py: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/code_helpers.py -.. _communication_client.py: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/robots/communication_client.py -.. _communication_server.py: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/robots/communication_server.py \ No newline at end of file +.. _communication_client.py: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/examples/robots/communication_client/code.py +.. _communication_server.py: https://github.com/MelbourneHighSchoolRobotics/ev3sim/tree/main/ev3sim/examples/robots/communication_server/code.py \ No newline at end of file diff --git a/docs/images/bot_menu_edit.png b/docs/images/bot_menu_edit.png index 76613364..42251504 100644 Binary files a/docs/images/bot_menu_edit.png and b/docs/images/bot_menu_edit.png differ diff --git a/docs/images/randomisation_settings.png b/docs/images/randomisation_settings.png new file mode 100644 index 00000000..e8250909 Binary files /dev/null and b/docs/images/randomisation_settings.png differ diff --git a/docs/images/randomisation_settings2.png b/docs/images/randomisation_settings2.png new file mode 100644 index 00000000..b6061b81 Binary files /dev/null and b/docs/images/randomisation_settings2.png differ diff --git a/docs/index.rst b/docs/index.rst index 603576c1..6bf31fa3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,11 +27,10 @@ A full video on what EV3Sim is and how you can install it can be found here: :caption: Contents: setup - batched_commands + simulation_settings bot_editing ev3_extensions custom_presets + randomisation contributing system - -.. TODO: Support randomisation through settings. diff --git a/docs/randomisation.rst b/docs/randomisation.rst index 19666ccc..e84af6ce 100644 --- a/docs/randomisation.rst +++ b/docs/randomisation.rst @@ -1,50 +1,19 @@ Randomisation ============= -TODO: Change this to gui docs +While disabled by default, you can enable some randomisation for device data (to simulate real life issues) By changing the settings of ev3sim: -When executing ``ev3sim`` you may notice that the following is printed: +.. image:: images/randomisation_settings.png + :width: 600 + :alt: The settings screen, highlighting randomisation settings. -.. code-block:: bash +You can also configure these values to your liking / realism by pressing the button on the right: - Simulating with seed 0000000000 +.. image:: images/randomisation_settings2.png + :width: 600 + :alt: The settings screen, highlighting randomisation settings. -But with a different number to the one above. This number is the 'seed' and essentially defines all randomness that will occur within the system. - -Despite being mostly the same on every run, some elements of the simulation require randomness, for realism, and to ensure that every run is slightly different: - -* The spawn positions of bots and balls is slightly randomised. -* The way a colour sensor detects colours requires randomness. - -As such in order to redo a simulation exactly as was done before, we want to be able to use the same seed, to ensure all random numbers are also the same. - -You can do this with the ``--seed`` or ``-s`` flag in ``ev3sim``. As an example, to simulate with seed 123456789, you can do the following: - -.. code-block:: bash - - ev3sim bot.yaml --seed 123456789 - -Note that the ``Simulating with seed`` line will respect this change. The seed can be any integer from 0 to 2^32 - 1, inclusive. - -To make simulation of devices a bit more realistic, there is also support for the randomisation of device characteristics, in similar ways to what you might expect in real life. Examples include: - -* Motors having a theoretical maximum speed, but also a physical one which differs slightly -* Sensors having slight biases towards certain directions - -And you can enable this randomisation by using the ``soccer_random.yaml`` preset rather than ``soccer.yaml``: - -.. code-block:: bash - - ev3sim bot.yaml --seed 123456789 -p soccer_random.yaml - -To add randomisation to your particular preset, you only need to add the following: - -.. code-block:: yaml - - settings: - ev3sim.simulation.loader.ScriptLoader.RANDOMISE_SENSORS: true - -That being said, some of this randomisation is not done based on the seed, but rather the port and robot the device is connected to (This is to simulate you working with the same device with the same bias between runs). As a rule of thumb: +In general, the following rules occur to device randomness: * Internal biases of devices will be static on the same port / robot filename. -* Randomness which is introduced over time or every game tick is tied to the seed. +* Randomness which is introduced over time or every game tick is tied to the seed, and so different every time. diff --git a/docs/setup.rst b/docs/setup.rst index fb4e8c58..21678ab5 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -9,22 +9,16 @@ Windows Executable By far the easiest way to install and use EV3Sim if you have a windows computer is using the one-click installer available on the `releases page on github`_. -.. image:: images/releases.jpg +.. image:: images/releases.png :width: 600 :alt: An image of the releases page on github. Simply download the asset file named ``one_click.exe``, and follow the prompts to get the executable installed. -Windows Bundle -^^^^^^^^^^^^^^ - -Another way to get EV3Sim is by downloading the package from the same releases page (``windows_package``). Simply unzip and place this folder in a program directory such as ``Program Files`` or ``Applications``. -In future we aim to also support this method for Mac/Linux, but currently there's not much point to. Let us now if you'd prefer this! - Pip install ^^^^^^^^^^^ -If installing via this method, EV3sim requires Python 3.7+ to be installed on your system. If you don't already have Python installed, you can download it from https://www.python.org/ . +If installing via this method, EV3sim requires Python 3.7+ to be installed on your system. If you don't already have Python installed, you can download it from https://www.python.org/ (Make sure to tick "Add Python to PATH"!). You can install this package using pip as follows: @@ -40,7 +34,7 @@ Updating Windows Executable ^^^^^^^^^^^^^^^^^^ -If a new one-click installer comes out, you can simply run this and it will update your existing installation of EV3Sim. Your workspace and any settings will remain the same, unless some breaking changes are required. +If a new one-click installer comes out, you can simply download and run this new version and it will update your existing installation of EV3Sim. Your workspace and any settings will remain the same, unless some breaking changes are required. Pip install ^^^^^^^^^^^ @@ -57,11 +51,10 @@ Starting EV3Sim Depending on you installation method, you might start EV3Sim differently: * If you installed on windows with the one click install, EV3Sim should be in your start menu. -* If using the bundle installation, you can go into the folder and run ``ev3sim`` or ``ev3sim.exe``. * If installed via pip, then run ``ev3sim`` in the command line. The first time you run EV3Sim, you will be prompted with a dialog, asking you to specify a *workspace folder*. -A workspace folder is where all of your local bots, code and simulation presets are stored. +A workspace folder is where all of your local bots and code are stored. We'd recommend creating a new folder on your Desktop to be your workspace folder, for easy access. @@ -70,9 +63,11 @@ Running EV3Sim Once your workspace folder has been set, you can start using the application. -* The ``Simulate`` tab allows you to run simulations, and select simulations to edit the bots or settings. -* The ``Bots`` tab allows you to edit and create bots to use in the simulation. +* The ``Soccer`` tab allows you to run soccer simulations, and the two buttons to the right let you change the settings for this simulation, and what bots will be simulated. +* The ``Rescue`` tab allows you to run rescue simulations, and the two buttons to the right let you change the settings for this simulation, and what bots will be simulated. +* The ``Bots`` tab allows you to edit and create bots to use in the simulations. * The ``Settings`` tab allows you to change a few configurations when running EV3Sim. +* (If shown) The ``Custom`` tab allows you to simulate custom environments, if they are installed. Further Information on installing @@ -82,8 +77,8 @@ Windows ^^^^^^^ -Command not recognised -"""""""""""""""""""""" +Command not recognised - Python / Pip installation +"""""""""""""""""""""""""""""""""""""""""""""""""" .. code-block:: batch diff --git a/docs/simulation_settings.rst b/docs/simulation_settings.rst new file mode 100644 index 00000000..a43906ab --- /dev/null +++ b/docs/simulation_settings.rst @@ -0,0 +1,34 @@ +Simulation Settings +=================== + +Why do we need settings? +---------------------------- + +When running a simulation with EV3Sim, you need two things: + +* A world to simulate and interact with, and +* Robots to interact with the simulated world. + +We can specify both of these things using the two buttons to the right of the ``Soccer`` and ``Rescue`` tabs. + +Changing the robots in a simulation +----------------------------------- + +Pressing the icon of a robot on the main menu allows you to select the robots present in a simulation. + +From here, you can select a bot from those you have defined, and select them for Team 1 or Team 2 for Soccer, or just the individual bot for rescue. For soccer, after selecting the bot for Team 1, Bot 1, you then select the bot for Team 2, Bot 1, and so on. +At any point if you have enough bots in the simulation, you can click "Done" to finish. + +Changing simulation settings +---------------------------- + +Clicking the settings cog instead of the robot button will take you to the settings page for you simulation preset: + +.. image:: images/settings.png + :width: 600 + :alt: The simulation preset settings page, for the soccer preset. + +Running the simulation preset +----------------------------- + +To run your simulation with these changes, just click the ``Soccer`` or ``Rescue`` buttons. diff --git a/docs/system.rst b/docs/system.rst index 699d12b5..7e476f94 100644 --- a/docs/system.rst +++ b/docs/system.rst @@ -1,5 +1,5 @@ Simulation Objects -=============================== +================== .. toctree:: :maxdepth: 1 diff --git a/ev3sim/assets/default_theme.json b/ev3sim/assets/default_theme.json index d8004c57..f683c01a 100644 --- a/ev3sim/assets/default_theme.json +++ b/ev3sim/assets/default_theme.json @@ -326,6 +326,16 @@ "size": "24" } }, + "settings-title": { + "colours": { + "normal_text": "#f7ede2", + "dark_bg": "#00000000" + }, + "font": { + "name": "Roboto", + "size": "24" + } + }, "checkbox-button": { "colours": { "normal_bg": "#ffffff00", diff --git a/ev3sim/simulation/loader.py b/ev3sim/simulation/loader.py index a722ac21..88f61db4 100644 --- a/ev3sim/simulation/loader.py +++ b/ev3sim/simulation/loader.py @@ -328,11 +328,37 @@ def __init__(self): "FPS": ObjectSetting(ScriptLoader, "VISUAL_TICK_RATE"), "tick_rate": ObjectSetting(ScriptLoader, "GAME_TICK_RATE"), "timescale": ObjectSetting(ScriptLoader, "TIME_SCALE"), + "randomise_sensors": ObjectSetting(ScriptLoader, "RANDOMISE_SENSORS"), "console_log": ObjectSetting(Logger, "LOG_CONSOLE"), "workspace_folder": ObjectSetting(StateHandler, "WORKSPACE_FOLDER"), } + from ev3sim.devices.colour.base import ColourSensorMixin + from ev3sim.devices.colour.ev3 import ColorSensor + from ev3sim.devices.compass.ev3 import CompassSensor + from ev3sim.devices.infrared.base import InfraredSensorMixin + from ev3sim.devices.motor.base import MotorMixin + from ev3sim.devices.ultrasonic.base import UltrasonicSensorMixin + + randomisation_settings = { + "COLOUR_SENSOR_RADIUS": ObjectSetting(ColourSensorMixin, "SENSOR_RADIUS"), + "COLOUR_SENSOR_SAMPLING_POINTS": ObjectSetting(ColourSensorMixin, "SENSOR_POINTS"), + "COLOUR_MAX_RGB_BIAS": ObjectSetting(ColorSensor, "MAX_RGB_BIAS"), + "COLOUR_MIN_RGB_BIAS": ObjectSetting(ColorSensor, "MIN_RGB_BIAS"), + "COMPASS_N_POINTS": ObjectSetting(CompassSensor, "NEAREST_POINTS_NUMBER"), + "COMPASS_POINT_VARIANCE": ObjectSetting(CompassSensor, "NEAREST_POINTS_VARIANCE"), + "COMPASS_NOISE_RATE": ObjectSetting(CompassSensor, "NOISE_WIDTH_PER_TICK"), + "COMPASS_NOISE_AMP": ObjectSetting(CompassSensor, "NOISE_AMPLIFIER"), + "COMPASS_MAXIMUM_NOISE_EFFECT": ObjectSetting(CompassSensor, "NOISE_EFFECT_MAX"), + "INFRARED_BIAS_AMP": ObjectSetting(InfraredSensorMixin, "SUBSENSOR_BIAS_MAGNITUDE"), + "MOTOR_MIN_MULT": ObjectSetting(MotorMixin, "MIN_FORCE_PCT"), + "MOTOR_MAX_MULT": ObjectSetting(MotorMixin, "MAX_FORCE_PCT"), + "MOTOR_N_SPEEDS": ObjectSetting(MotorMixin, "FIXED_SPEED_POINTS"), + "ULTRASONIC_NOISE_ANGLE_AMPLITUDE": ObjectSetting(UltrasonicSensorMixin, "ANGLE_RANDOM_AMPLITUDE"), + "ULTRASONIC_OFFSET_AMP": ObjectSetting(UltrasonicSensorMixin, "OFFSET_MAX"), + } settings.addSettingGroup("app", loader_settings) settings.addSettingGroup("screen", screen_settings) + settings.addSettingGroup("randomisation", randomisation_settings) self.shared_info = {} def closeProcesses(self): diff --git a/ev3sim/visual/manager.py b/ev3sim/visual/manager.py index 24b6f6ad..7b54e874 100644 --- a/ev3sim/visual/manager.py +++ b/ev3sim/visual/manager.py @@ -19,6 +19,7 @@ class ScreenObjectManager: SCREEN_SIM = "SIMULATOR" SCREEN_BOTS = "BOT_SELECT" SCREEN_SETTINGS = "SETTINGS" + SCREEN_RANDOM_SETTINGS = "RANDOM_SETTINGS" SCREEN_WORKSPACE = "WORKSPACE" SCREEN_UPDATE = "UPDATE" SCREEN_BOT_EDIT = "BOT_EDIT" @@ -106,6 +107,7 @@ def initScreens(self): from ev3sim.visual.settings.menu import SettingsMenu self.screens[self.SCREEN_SETTINGS] = SettingsMenu((self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) + self.screens[self.SCREEN_RANDOM_SETTINGS] = SettingsMenu((self.SCREEN_WIDTH, self.SCREEN_HEIGHT)) # Rescue edit screen from ev3sim.visual.menus.rescue_edit import RescueMapEditMenu diff --git a/ev3sim/visual/settings/elements.py b/ev3sim/visual/settings/elements.py index 3d2ae671..1007c247 100644 --- a/ev3sim/visual/settings/elements.py +++ b/ev3sim/visual/settings/elements.py @@ -41,6 +41,37 @@ def generateVisual(self, size, container, manager, idx): raise NotImplementedError() +class Title(SettingsVisualElement): + + num_objs = 1 + + def __init__(self, title, offset): + self.title = title + self.offset = offset + self.menu = None + self.json_keys = "__filename__" + + def getFromJson(self, json_obj): + pass + + def setToJson(self, json_obj): + pass + + def generateVisual(self, size, container, manager, idx): + self.container = container + off = self.offset(size) + label_size = ((size[0] - 40), 40) + label_pos = (off[0] + 20, off[1]) + self.button = pygame_gui.elements.UILabel( + relative_rect=pygame.Rect(*label_pos, *label_size), + manager=manager, + object_id=pygame_gui.core.ObjectID(f"{idx}-title-label", "settings-title"), + container=container, + text=self.title, + ) + return [self.button] + + class Button(SettingsVisualElement): num_objs = 1 diff --git a/ev3sim/visual/settings/main_settings.py b/ev3sim/visual/settings/main_settings.py index c5d4acd1..2371f44a 100644 --- a/ev3sim/visual/settings/main_settings.py +++ b/ev3sim/visual/settings/main_settings.py @@ -1,4 +1,19 @@ -from ev3sim.visual.settings.elements import NumberEntry, FileEntry, Checkbox +from ev3sim.file_helper import find_abs +from ev3sim.search_locations import config_locations +from ev3sim.visual.settings.elements import NumberEntry, FileEntry, Checkbox, Button +from ev3sim.visual.settings.randomisation_settings import randomisation_settings + + +def onClickConfigEditor(filename): + from ev3sim.visual.manager import ScreenObjectManager + + ScreenObjectManager.instance.pushScreen( + ScreenObjectManager.SCREEN_RANDOM_SETTINGS, + file=find_abs("user_config.yaml", config_locations()), + settings=randomisation_settings, + ) + ScreenObjectManager.instance.screens[ScreenObjectManager.SCREEN_RANDOM_SETTINGS].clearEvents() + main_settings = [ { @@ -16,6 +31,13 @@ Checkbox(["app", "console_log"], True, "Console", (lambda s: (0, 170) if s[0] < 540 else (s[0] / 2, 70))), ], }, + { + "height": (lambda s: 90), + "objects": [ + Checkbox(["app", "randomise_sensors"], False, "Random Noise", (lambda s: (0, 20))), + Button("Randomisation Config", (lambda s: (0, 70) if s[0] < 540 else (s[0] / 2, 20)), onClickConfigEditor), + ], + }, { "height": (lambda s: 90), "objects": [ diff --git a/ev3sim/visual/settings/menu.py b/ev3sim/visual/settings/menu.py index 9e9ac437..9021dae6 100644 --- a/ev3sim/visual/settings/menu.py +++ b/ev3sim/visual/settings/menu.py @@ -1,3 +1,4 @@ +from ev3sim.visual.menus.utils import CustomScroll from ev3sim.settings import SettingsManager from ev3sim.visual.settings.elements import TextEntry import os @@ -21,6 +22,25 @@ def clearEvents(self): self.onCancel = None def generateObjects(self): + # Scrolling container + old_y = 0 + self.scrolling_container = CustomScroll( + relative_rect=pygame.Rect(0, 0, *self._size), + manager=self, + object_id=pygame_gui.core.ObjectID("scroll_container"), + ) + self.scrolling_container.num_elems = 1 + self.scrolling_container.elems_size = 1 + self.scrolling_container.span_elems = 1 + scroll_height = self._size[1] - 90 + scrolling_size = (self._size[0], scroll_height) + # Setting dimensions and positions on a UIScrollingContainer seems buggy. This works. + self.scrolling_container.set_dimensions(scrolling_size) + self.scrolling_container.set_position(scrolling_size) + self.scrolling_container.cur_y = old_y + self.scrolling_container.set_scroll(old_y) + self._all_objs.append(self.scrolling_container) + yPadding = 20 yOffset = 0 index = 0 @@ -30,6 +50,7 @@ def generateObjects(self): relative_rect=pygame.Rect(0, 0, *self._size), starting_layer_height=-1, manager=self, + container=self.scrolling_container, object_id=pygame_gui.core.ObjectID(f"{index}-bg", "settings-background"), ) self._all_objs.append(container) @@ -49,6 +70,10 @@ def generateObjects(self): yOffset += group["height"](self._size) yOffset += yPadding + self.scrolling_container.elems_size = yOffset + self.scrolling_container.span_elems = min(1, scroll_height / yOffset) + self.scrolling_container.set_scrollable_area_dimensions((self._size[0], yOffset)) + self.bg = pygame_gui.elements.UIPanel( relative_rect=pygame.Rect(0, 0, *self._size), starting_layer_height=-2, @@ -58,7 +83,7 @@ def generateObjects(self): self._all_objs.append(self.bg) container = pygame_gui.elements.UIPanel( - relative_rect=pygame.Rect(20, yOffset, self._size[0] - 40, 80), + relative_rect=pygame.Rect(20, min(yOffset, self._size[1] - 80), self._size[0] - 40, 80), starting_layer_height=-1, manager=self, object_id=pygame_gui.core.ObjectID(f"{index}-bg", "settings-background"), @@ -66,7 +91,7 @@ def generateObjects(self): self._all_objs.append(container) self.save = pygame_gui.elements.UIButton( - relative_rect=pygame.Rect(self._size[0] - 300, yOffset + 10, 120, 60), + relative_rect=pygame.Rect(self._size[0] - 300, min(yOffset + 10, self._size[1] - 70), 120, 60), manager=self, object_id=pygame_gui.core.ObjectID("save-changes", "action_button"), text="Create" if self.creating else "Save", @@ -75,7 +100,7 @@ def generateObjects(self): self._all_objs.append(self.save) self.cancel = pygame_gui.elements.UIButton( - relative_rect=pygame.Rect(self._size[0] - 160, yOffset + 10, 120, 60), + relative_rect=pygame.Rect(self._size[0] - 160, min(yOffset + 10, self._size[1] - 70), 120, 60), manager=self, object_id=pygame_gui.core.ObjectID("cancel-changes", "action_button"), text="Cancel", diff --git a/ev3sim/visual/settings/randomisation_settings.py b/ev3sim/visual/settings/randomisation_settings.py new file mode 100644 index 00000000..58f63e64 --- /dev/null +++ b/ev3sim/visual/settings/randomisation_settings.py @@ -0,0 +1,115 @@ +from ev3sim.visual.settings.elements import NumberEntry, Title + +randomisation_settings = [ + { + "height": (lambda s: 290 if s[0] < 580 else 190), + "objects": [ + Title("Colour Sensor", (lambda s: (0, 20))), + NumberEntry(["randomisation", "COLOUR_SENSOR_RADIUS"], 1, "Sampling Radius", (lambda s: (0, 70)), float), + NumberEntry( + ["randomisation", "COLOUR_SENSOR_SAMPLING_POINTS"], + 100, + "Sampling Points", + (lambda s: (0, 120) if s[0] < 540 else (s[0] / 2, 70)), + int, + ), + NumberEntry( + ["randomisation", "COLOUR_MAX_RGB_BIAS"], + 400, + "Max RGB Bias", + (lambda s: (0, 170) if s[0] < 540 else (0, 120)), + float, + ), + NumberEntry( + ["randomisation", "COLOUR_MIN_RGB_BIAS"], + 230, + "Min RGB Bias", + (lambda s: (0, 220) if s[0] < 540 else (s[0] / 2, 120)), + float, + ), + ], + }, + { + "height": (lambda s: 340 if s[0] < 580 else 240), + "objects": [ + Title("Compass Sensor", (lambda s: (0, 20))), + NumberEntry(["randomisation", "COMPASS_N_POINTS"], 51, "Static Points", (lambda s: (0, 70)), int), + NumberEntry( + ["randomisation", "COMPASS_POINT_VARIANCE"], + 16, + "Static Variance", + (lambda s: (0, 120) if s[0] < 540 else (s[0] / 2, 70)), + float, + ), + NumberEntry( + ["randomisation", "COMPASS_NOISE_RATE"], + 0.03, + "Noise rate of change", + (lambda s: (0, 170) if s[0] < 540 else (0, 120)), + float, + ), + NumberEntry( + ["randomisation", "COMPASS_NOISE_AMP"], + 0.2, + "Noise amplitude", + (lambda s: (0, 220) if s[0] < 540 else (s[0] / 2, 120)), + float, + ), + NumberEntry( + ["randomisation", "COMPASS_MAXIMUM_NOISE_EFFECT"], + 15, + "Max Noise effect", + (lambda s: (0, 270) if s[0] < 540 else (0, 170)), + float, + ), + ], + }, + { + "height": (lambda s: 140), + "objects": [ + Title("Infrared Sensor", (lambda s: (0, 20))), + NumberEntry(["randomisation", "INFRARED_BIAS_AMP"], 5, "Bias Amplitude", (lambda s: (0, 70)), float), + ], + }, + { + "height": (lambda s: 190 if s[0] < 580 else 140), + "objects": [ + Title("Ultrasonic Sensor", (lambda s: (0, 20))), + NumberEntry( + ["randomisation", "ULTRASONIC_NOISE_ANGLE_AMPLITUDE"], + 40, + "Angle change effect", + (lambda s: (0, 70)), + float, + ), + NumberEntry( + ["randomisation", "ULTRASONIC_OFFSET_AMP"], + 5, + "Static noise", + (lambda s: (0, 120) if s[0] < 540 else (s[0] / 2, 70)), + float, + ), + ], + }, + { + "height": (lambda s: 240 if s[0] < 580 else 190), + "objects": [ + Title("Motors", (lambda s: (0, 20))), + NumberEntry(["randomisation", "MOTOR_MIN_MULT"], 0.9, "Min speed mult", (lambda s: (0, 70)), float), + NumberEntry( + ["randomisation", "MOTOR_MAX_MULT"], + 1.05, + "Max speed mult", + (lambda s: (0, 120) if s[0] < 540 else (s[0] / 2, 70)), + float, + ), + NumberEntry( + ["randomisation", "MOTOR_N_SPEEDS"], + 71, + "Static Points", + (lambda s: (0, 170) if s[0] < 540 else (0, 120)), + int, + ), + ], + }, +]