From c1a123b16e7c63c5509467a27d12956fd37f7a1c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Aug 2023 13:41:15 -0700 Subject: [PATCH 1/3] Adapt environment to allow changes to timescale and framerates for more control --- animalai/animalai/envs/environment.py | 40 +++++++++++++++------------ examples/play.py | 3 ++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/animalai/animalai/envs/environment.py b/animalai/animalai/envs/environment.py index 2b05d5999..6dd57c49c 100644 --- a/animalai/animalai/envs/environment.py +++ b/animalai/animalai/envs/environment.py @@ -14,9 +14,7 @@ class PlayTrain(NamedTuple): train: int class AnimalAIEnvironment(UnityEnvironment): - """Extends UnityEnvironment with options specific for AnimalAI - see https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API.md for documentation - and the animalai observations doc for explanation of the AnimalAI-specific parameters.""" + """Extends UnityEnvironment with options specific for AnimalAI""" # Default values for configuration parameters of the environment, can be changed if needed # Increasing the timescale value for training might speed up the process on powerfull machines @@ -24,9 +22,9 @@ class AnimalAIEnvironment(UnityEnvironment): WINDOW_WIDTH = PlayTrain(play=1200, train=32) WINDOW_HEIGHT = PlayTrain(play=800, train=32) QUALITY_LEVEL = PlayTrain(play=1, train=1) - TIMESCALE = PlayTrain(play=1, train=300) - TARGET_FRAME_RATE = PlayTrain(play=60, train=-1) - CAPTURE_FRAME_RATE = PlayTrain(play=60, train=0) + #TIMESCALE = PlayTrain(play=1, train=300) + #TARGET_FRAME_RATE = PlayTrain(play=60, train=-1) + #CAPTURE_FRAME_RATE = PlayTrain(play=60, train=0) ARENA_CONFIG_SC_UUID = "9c36c837-cad5-498a-b675-bc19c9370072" YAML_SC_UUID = "20b62eb2-cde3-4f5f-a8e5-af8d9677971d" @@ -51,8 +49,9 @@ def __init__( side_channels: Optional[List[SideChannel]] = None, no_graphics: bool = False, use_YAML: bool = True, - # captureFrameRate: int = 0, - # targetFrameRate: int = 60, + timescale: int = 1, + targetFrameRate: int = 60, + captureFrameRate: int = 0, ): self.obsdict = { @@ -79,8 +78,9 @@ def __init__( self.side_channels = side_channels if side_channels else [] self.arenas_parameters_side_channel = None self.use_YAML = use_YAML - # self.captureFrameRate = captureFrameRate - # self.targetFrameRate = targetFrameRate + self.timescale = timescale + self.captureFrameRate = captureFrameRate + self.targetFrameRate = targetFrameRate self.configure_side_channels(self.side_channels) @@ -119,18 +119,24 @@ def create_engine_config_side_channel(self) -> EngineConfigurationChannel: width=self.WINDOW_WIDTH.play, height=self.WINDOW_HEIGHT.play, quality_level=self.QUALITY_LEVEL.play, - time_scale=self.TIMESCALE.play, - target_frame_rate=self.TARGET_FRAME_RATE.play, - capture_frame_rate=self.CAPTURE_FRAME_RATE.play, + # time_scale=self.TIMESCALE.play, + # target_frame_rate=self.TARGET_FRAME_RATE.play, + # capture_frame_rate=self.CAPTURE_FRAME_RATE.play, + time_scale = self.timescale, + target_frame_rate = self.targetFrameRate, + capture_frame_rate = self.captureFrameRate ) else: engine_configuration = EngineConfig( width=self.WINDOW_WIDTH.train, height=self.WINDOW_HEIGHT.train, quality_level=self.QUALITY_LEVEL.train, - time_scale=self.TIMESCALE.train, - target_frame_rate=self.TARGET_FRAME_RATE.train, - capture_frame_rate=self.CAPTURE_FRAME_RATE.train, + # time_scale=self.TIMESCALE.train, + # target_frame_rate=self.TARGET_FRAME_RATE.train, + # capture_frame_rate=self.CAPTURE_FRAME_RATE.train, + time_scale = self.timescale, + target_frame_rate = self.targetFrameRate, + capture_frame_rate = self.captureFrameRate ) engine_configuration_channel = EngineConfigurationChannel() engine_configuration_channel.set_configuration(engine_configuration) @@ -201,4 +207,4 @@ def executable_args( args.append(str(rayMaxDegrees)) args.append("--decisionPeriod") args.append(str(decisionPeriod)) - return args + return args \ No newline at end of file diff --git a/examples/play.py b/examples/play.py index a0fece209..c834b41fb 100644 --- a/examples/play.py +++ b/examples/play.py @@ -21,6 +21,9 @@ def load_config_and_play(configuration_file: str) -> None: base_port=port, arenas_configurations=configuration_file, play=True, + timescale = 1, + targetFrameRate = 60, + captureFrameRate = 0 ) # Run the environment until signal to it is lost From b3c40b7569a925cfb55a5445106ee0d3fa9ce76c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Aug 2023 13:46:17 -0700 Subject: [PATCH 2/3] [Minor] Add useful comment --- animalai/animalai/envs/environment.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/animalai/animalai/envs/environment.py b/animalai/animalai/envs/environment.py index 6dd57c49c..191fd4b20 100644 --- a/animalai/animalai/envs/environment.py +++ b/animalai/animalai/envs/environment.py @@ -14,10 +14,12 @@ class PlayTrain(NamedTuple): train: int class AnimalAIEnvironment(UnityEnvironment): - """Extends UnityEnvironment with options specific for AnimalAI""" + """Extends UnityEnvironment with options specific for AnimalAI + see https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API.md for documentation + and the animalai observations doc for explanation of the AnimalAI-specific parameters.""" # Default values for configuration parameters of the environment, can be changed if needed - # Increasing the timescale value for training might speed up the process on powerfull machines + # Increasing the timescale value for training might speed up the process on powerful machines # but take care as the higher the timescale the more likely the physics might break WINDOW_WIDTH = PlayTrain(play=1200, train=32) WINDOW_HEIGHT = PlayTrain(play=800, train=32) From 1a25d473e2049c028875f0c1bfb1d029702f0e69 Mon Sep 17 00:00:00 2001 From: Wout Schellaert Date: Fri, 25 Aug 2023 16:30:49 +0200 Subject: [PATCH 3/3] Add documentation --- animalai/animalai/envs/environment.py | 104 +++++++++++++++++++------- 1 file changed, 78 insertions(+), 26 deletions(-) diff --git a/animalai/animalai/envs/environment.py b/animalai/animalai/envs/environment.py index 191fd4b20..0c474cdc7 100644 --- a/animalai/animalai/envs/environment.py +++ b/animalai/animalai/envs/environment.py @@ -18,15 +18,10 @@ class AnimalAIEnvironment(UnityEnvironment): see https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API.md for documentation and the animalai observations doc for explanation of the AnimalAI-specific parameters.""" - # Default values for configuration parameters of the environment, can be changed if needed - # Increasing the timescale value for training might speed up the process on powerful machines - # but take care as the higher the timescale the more likely the physics might break + # Default values for configuration parameters of the environment, can be changed if needed. WINDOW_WIDTH = PlayTrain(play=1200, train=32) WINDOW_HEIGHT = PlayTrain(play=800, train=32) QUALITY_LEVEL = PlayTrain(play=1, train=1) - #TIMESCALE = PlayTrain(play=1, train=300) - #TARGET_FRAME_RATE = PlayTrain(play=60, train=-1) - #CAPTURE_FRAME_RATE = PlayTrain(play=60, train=0) ARENA_CONFIG_SC_UUID = "9c36c837-cad5-498a-b675-bc19c9370072" YAML_SC_UUID = "20b62eb2-cde3-4f5f-a8e5-af8d9677971d" @@ -55,6 +50,67 @@ def __init__( targetFrameRate: int = 60, captureFrameRate: int = 0, ): + """ + Parameters + ---------- + additional_args : List[str] + Currently not supported anymore. TODO. + log_folder : str + Optional folder to write the Unity Player log file into. Requires absolute path. + file_name : Optional[str] + Path to the Unity environment binary. + worker_id : int + Offset from base_port. Used for training multiple environments simultaneously. + base_port : int + Base port to connect to Unity environment over. worker_id increments over this. + If no environment is specified (i.e. file_name is None), the DEFAULT_EDITOR_PORT will be used. + seed : int + Random seed used for the environment. + play : bool + Whether to run the Unity simulator in play mode. + arenas_configurations : str + Path to the YAML file containing the arena configurations. + inference : bool + Sets the window size to the same as play mode to allow observing the agent. + useCamera : bool + Whether to use the camera observations. + resolution : int + Resolution of the camera observations. + grayscale : bool + Whether to use grayscale camera observations. + useRayCasts : bool + Whether to use the raycast observations. + raysPerSide : int + Number of rays per side. + rayMaxDegrees : int + Maximum degrees of the raycast observations. + decisionPeriod : int + [DEPRECATED] Number of steps to take before the agent gets a decision. TODO. + side_channels : Optional[List[SideChannel]] + Additional side channel for no-rl communication with Unity. + no_graphics : bool + Whether to run the Unity simulator in no-graphics mode. + Not compatible with useCamera, as all observations will empty. + use_YAML : + [DEPRECATED]. TODO. + timescale : int + Defines the multiplier for the deltatime in the simulation. Default is 1. + If set to a higher value, time will pass faster in the simulation + and might speed of training but the physics might break. + A value of 1 is real time, 2 is double speed, 0.5 is half speed. + WARNING: Make sure that the observations your agent can receive + per second is adequate for the set timescale. + For example, with an average observations per second 60, a timescale + of 60 will cause your agent to only observe 1 frame per in-simulation second. + Especially important with time-sensitive environments, + e.g. decaying or growing goals, falling or rolling objects... + targetFrameRate : int + Instructs simulation to try to render at a specified frame rate. + A value of -1 will attempt to render as fast as possible, recommended + when timescale is set to a value higher than 1. + captureFrameRate : int + Instructs the simulation to consider time between updates to always be constant, regardless of the actual frame rate. + """ self.obsdict = { "camera": [], @@ -117,29 +173,25 @@ def configure_side_channels(self, side_channels: List[SideChannel]) -> None: def create_engine_config_side_channel(self) -> EngineConfigurationChannel: if self.play or self.inference: - engine_configuration = EngineConfig( - width=self.WINDOW_WIDTH.play, - height=self.WINDOW_HEIGHT.play, - quality_level=self.QUALITY_LEVEL.play, - # time_scale=self.TIMESCALE.play, - # target_frame_rate=self.TARGET_FRAME_RATE.play, - # capture_frame_rate=self.CAPTURE_FRAME_RATE.play, - time_scale = self.timescale, - target_frame_rate = self.targetFrameRate, - capture_frame_rate = self.captureFrameRate + width, height, quality_level = ( + self.WINDOW_WIDTH.play, + self.WINDOW_HEIGHT.play, + self.QUALITY_LEVEL.play, ) else: - engine_configuration = EngineConfig( - width=self.WINDOW_WIDTH.train, - height=self.WINDOW_HEIGHT.train, - quality_level=self.QUALITY_LEVEL.train, - # time_scale=self.TIMESCALE.train, - # target_frame_rate=self.TARGET_FRAME_RATE.train, - # capture_frame_rate=self.CAPTURE_FRAME_RATE.train, - time_scale = self.timescale, - target_frame_rate = self.targetFrameRate, - capture_frame_rate = self.captureFrameRate + width, height, quality_level = ( + self.WINDOW_WIDTH.train, + self.WINDOW_HEIGHT.train, + self.QUALITY_LEVEL.train, ) + engine_configuration = EngineConfig( + width=width, + height=height, + quality_level=quality_level, + time_scale = self.timescale, + target_frame_rate = self.targetFrameRate, + capture_frame_rate = self.captureFrameRate + ) engine_configuration_channel = EngineConfigurationChannel() engine_configuration_channel.set_configuration(engine_configuration) return engine_configuration_channel