From 34838454d633b38ba241183d6a91620e1256720e Mon Sep 17 00:00:00 2001 From: Luigi Berducci Date: Thu, 25 Jan 2024 16:49:38 +0100 Subject: [PATCH 1/5] add choice of reference line in automatic reset, adapt reset modes to be "__" and update tests/examples accordingly, use None as defaults in reset and observation such that we have the choice of default in factory methods. --- examples/waypoint_follow.py | 2 +- gym/f110_gym/envs/f110_env.py | 4 ++-- gym/f110_gym/envs/observation.py | 8 +++---- gym/f110_gym/envs/reset/__init__.py | 31 +++++++++++++------------ gym/f110_gym/envs/reset/masked_reset.py | 24 ++++++++++--------- gym/f110_gym/envs/reset/utils.py | 20 ++++++++-------- tests/test_f110_env.py | 2 +- 7 files changed, 47 insertions(+), 44 deletions(-) diff --git a/examples/waypoint_follow.py b/examples/waypoint_follow.py index 1cda9966..596ac28b 100644 --- a/examples/waypoint_follow.py +++ b/examples/waypoint_follow.py @@ -310,7 +310,7 @@ def main(): "model": "st", "observation_config": {"type": "kinematic_state"}, "params": {"mu": 1.0}, - "reset_config": {"type": "random_static"}, + "reset_config": {"type": "rl_random_static"}, }, render_mode="human", ) diff --git a/gym/f110_gym/envs/f110_env.py b/gym/f110_gym/envs/f110_env.py index 5cb1ad41..bb14d753 100644 --- a/gym/f110_gym/envs/f110_env.py +++ b/gym/f110_gym/envs/f110_env.py @@ -226,8 +226,8 @@ def default_config(cls) -> dict: "integrator": "rk4", "model": "st", "control_input": ["speed", "steering_angle"], - "observation_config": {"type": "original"}, - "reset_config": {"type": "grid_static"}, + "observation_config": {"type": None}, + "reset_config": {"type": None}, } def configure(self, config: dict) -> None: diff --git a/gym/f110_gym/envs/observation.py b/gym/f110_gym/envs/observation.py index 855a5838..263f8260 100644 --- a/gym/f110_gym/envs/observation.py +++ b/gym/f110_gym/envs/observation.py @@ -1,6 +1,4 @@ -""" -Author: Luigi Berducci -""" +from __future__ import annotations from abc import abstractmethod from typing import List @@ -265,7 +263,9 @@ def observe(self): return obs -def observation_factory(env, type: str, **kwargs) -> Observation: +def observation_factory(env, type: str | None, **kwargs) -> Observation: + type = type or "original" + if type == "original": return OriginalObservation(env) elif type == "features": diff --git a/gym/f110_gym/envs/reset/__init__.py b/gym/f110_gym/envs/reset/__init__.py index c6e05ba8..d5f56ea1 100644 --- a/gym/f110_gym/envs/reset/__init__.py +++ b/gym/f110_gym/envs/reset/__init__.py @@ -1,20 +1,21 @@ +from __future__ import annotations from f110_gym.envs.reset.masked_reset import GridResetFn, AllTrackResetFn from f110_gym.envs.reset.reset_fn import ResetFn from f110_gym.envs.track import Track -def make_reset_fn(type: str, track: Track, num_agents: int, **kwargs) -> ResetFn: - if type == "grid_static": - return GridResetFn(track=track, num_agents=num_agents, shuffle=False, **kwargs) - elif type == "grid_random": - return GridResetFn(track=track, num_agents=num_agents, shuffle=True, **kwargs) - elif type == "random_static": - return AllTrackResetFn( - track=track, num_agents=num_agents, shuffle=False, **kwargs - ) - elif type == "random_random": - return AllTrackResetFn( - track=track, num_agents=num_agents, shuffle=True, **kwargs - ) - else: - raise ValueError(f"invalid reset type {type}") +def make_reset_fn(type: str | None, track: Track, num_agents: int, **kwargs) -> ResetFn: + type = type or "rl_grid_static" + + try: + refline_token, reset_token, shuffle_token = type.split("_") + + refline = {"cl": track.centerline, "rl": track.raceline}[refline_token] + reset_fn = {"grid": GridResetFn, "random": AllTrackResetFn}[reset_token] + shuffle = {"static": False, "random": True}[shuffle_token] + options = {"cl": {"move_laterally": True}, "rl": {"move_laterally": False}}[refline_token] + + except Exception as ex: + raise ValueError(f"Invalid reset function type: {type}. Expected format: __") from ex + + return reset_fn(reference_line=refline, num_agents=num_agents, shuffle=shuffle, **options, **kwargs) diff --git a/gym/f110_gym/envs/reset/masked_reset.py b/gym/f110_gym/envs/reset/masked_reset.py index cac879cd..1f4e6983 100644 --- a/gym/f110_gym/envs/reset/masked_reset.py +++ b/gym/f110_gym/envs/reset/masked_reset.py @@ -4,7 +4,7 @@ from f110_gym.envs.reset.reset_fn import ResetFn from f110_gym.envs.reset.utils import sample_around_waypoint -from f110_gym.envs.track import Track +from f110_gym.envs.track import Track, Raceline class MaskedResetFn(ResetFn): @@ -14,23 +14,24 @@ def get_mask(self) -> np.ndarray: def __init__( self, - track: Track, + reference_line: Raceline, num_agents: int, move_laterally: bool, min_dist: float, max_dist: float, ): - self.track = track + self.reference_line = reference_line self.n_agents = num_agents self.min_dist = min_dist self.max_dist = max_dist self.move_laterally = move_laterally self.mask = self.get_mask() + self.reference_line = reference_line def sample(self) -> np.ndarray: waypoint_id = np.random.choice(np.where(self.mask)[0]) poses = sample_around_waypoint( - track=self.track, + reference_line=self.reference_line, waypoint_id=waypoint_id, n_agents=self.n_agents, min_dist=self.min_dist, @@ -43,9 +44,10 @@ def sample(self) -> np.ndarray: class GridResetFn(MaskedResetFn): def __init__( self, - track: Track, + reference_line: Raceline, num_agents: int, move_laterally: bool = True, + use_centerline: bool = True, shuffle: bool = True, start_width: float = 1.0, min_dist: float = 1.5, @@ -55,7 +57,7 @@ def __init__( self.shuffle = shuffle super().__init__( - track=track, + reference_line=reference_line, num_agents=num_agents, move_laterally=move_laterally, min_dist=min_dist, @@ -64,10 +66,10 @@ def __init__( def get_mask(self) -> np.ndarray: # approximate the nr waypoints in the starting line - step_size = self.track.centerline.length / self.track.centerline.n + step_size = self.reference_line.length / self.reference_line.n n_wps = int(self.start_width / step_size) - mask = np.zeros(self.track.centerline.n) + mask = np.zeros(self.reference_line.n) mask[:n_wps] = 1 return mask.astype(bool) @@ -83,7 +85,7 @@ def sample(self) -> np.ndarray: class AllTrackResetFn(MaskedResetFn): def __init__( self, - track: Track, + reference_line: Raceline, num_agents: int, move_laterally: bool = True, shuffle: bool = True, @@ -91,7 +93,7 @@ def __init__( max_dist: float = 2.5, ): super().__init__( - track=track, + reference_line=reference_line, num_agents=num_agents, move_laterally=move_laterally, min_dist=min_dist, @@ -100,7 +102,7 @@ def __init__( self.shuffle = shuffle def get_mask(self) -> np.ndarray: - return np.ones(self.track.centerline.n).astype(bool) + return np.ones(self.reference_line.n).astype(bool) def sample(self) -> np.ndarray: poses = super().sample() diff --git a/gym/f110_gym/envs/reset/utils.py b/gym/f110_gym/envs/reset/utils.py index 40ce9a73..f345276c 100644 --- a/gym/f110_gym/envs/reset/utils.py +++ b/gym/f110_gym/envs/reset/utils.py @@ -2,11 +2,11 @@ import numpy as np -from f110_gym.envs.track import Track +from f110_gym.envs.track import Track, Raceline def sample_around_waypoint( - track: Track, + reference_line: Raceline, waypoint_id: int, n_agents: int, min_dist: float, @@ -26,22 +26,22 @@ def sample_around_waypoint( - move_laterally: if True, the agents are sampled on the left/right of the track centerline """ current_wp_id = waypoint_id - n_waypoints = track.centerline.n + n_waypoints = reference_line.n poses = [] rnd_sign = ( - np.random.choice([-1, 1]) if move_laterally else 1 + np.random.choice([-1.0, 1.0]) if move_laterally else 0.0 ) # random sign to sample lateral position (left/right) for i in range(n_agents): # compute pose from current wp_id wp = [ - track.centerline.xs[current_wp_id], - track.centerline.ys[current_wp_id], + reference_line.xs[current_wp_id], + reference_line.ys[current_wp_id], ] next_wp_id = (current_wp_id + 1) % n_waypoints next_wp = [ - track.centerline.xs[next_wp_id], - track.centerline.ys[next_wp_id], + reference_line.xs[next_wp_id], + reference_line.ys[next_wp_id], ] theta = np.arctan2(next_wp[1] - wp[1], next_wp[0] - wp[0]) @@ -65,8 +65,8 @@ def sample_around_waypoint( if pnt_id > n_waypoints - 1: pnt_id = 0 # increment distance - x_diff = track.centerline.xs[pnt_id] - track.centerline.xs[pnt_id - 1] - y_diff = track.centerline.ys[pnt_id] - track.centerline.ys[pnt_id - 1] + x_diff = reference_line.xs[pnt_id] - reference_line.xs[pnt_id - 1] + y_diff = reference_line.ys[pnt_id] - reference_line.ys[pnt_id - 1] dist = dist + np.linalg.norm( [y_diff, x_diff] ) # approx distance by summing linear segments diff --git a/tests/test_f110_env.py b/tests/test_f110_env.py index 545b9ea3..053a2b20 100644 --- a/tests/test_f110_env.py +++ b/tests/test_f110_env.py @@ -217,7 +217,7 @@ def test_auto_reset_options_in_synch_vec_env(self): config = { "num_agents": num_agents, "observation_config": {"type": "kinematic_state"}, - "reset_config": {"type": "random_random"}, + "reset_config": {"type": "rl_random_random"}, } vec_env = gym.vector.make( "f110_gym:f110-v0", asynchronous=False, config=config, num_envs=num_envs From ff7a3a16233bbc8753840d9a9fc53bee373e74e5 Mon Sep 17 00:00:00 2001 From: Luigi Berducci Date: Thu, 25 Jan 2024 16:49:58 +0100 Subject: [PATCH 2/5] linting --- examples/video_recording.py | 8 +--- examples/waypoint_follow.py | 2 +- gym/f110_gym/__init__.py | 3 +- gym/f110_gym/envs/action.py | 64 ++++++++++++++----------- gym/f110_gym/envs/cubic_spline.py | 6 +-- gym/f110_gym/envs/f110_env.py | 9 ++-- gym/f110_gym/envs/f110_env_backup.py | 4 +- gym/f110_gym/envs/reset/__init__.py | 16 +++++-- gym/f110_gym/test/benchmark_renderer.py | 6 +-- gym/f110_gym/test/test_renderer.py | 6 +-- tests/legacy_scan_gen.py | 6 +-- tests/test_f110_env.py | 5 +- tests/test_scan_sim.py | 3 +- 13 files changed, 67 insertions(+), 71 deletions(-) diff --git a/examples/video_recording.py b/examples/video_recording.py index 3c593fbe..7ab83de6 100644 --- a/examples/video_recording.py +++ b/examples/video_recording.py @@ -34,13 +34,7 @@ def main(): planner = PurePursuitPlanner(track=track, wb=0.17145 + 0.15875) poses = np.array( - [ - [ - track.raceline.xs[0], - track.raceline.ys[0], - track.raceline.yaws[0], - ] - ] + [[track.raceline.xs[0], track.raceline.ys[0], track.raceline.yaws[0],]] ) obs, info = env.reset(options={"poses": poses}) diff --git a/examples/waypoint_follow.py b/examples/waypoint_follow.py index 596ac28b..46d7a950 100644 --- a/examples/waypoint_follow.py +++ b/examples/waypoint_follow.py @@ -166,7 +166,7 @@ def get_actuation(pose_theta, lookahead_point, position, lookahead_distance, whe speed = lookahead_point[2] if np.abs(waypoint_y) < 1e-6: return speed, 0.0 - radius = 1 / (2.0 * waypoint_y / lookahead_distance**2) + radius = 1 / (2.0 * waypoint_y / lookahead_distance ** 2) steering_angle = np.arctan(wheelbase / radius) return speed, steering_angle diff --git a/gym/f110_gym/__init__.py b/gym/f110_gym/__init__.py index 20052799..a993eb05 100644 --- a/gym/f110_gym/__init__.py +++ b/gym/f110_gym/__init__.py @@ -1,6 +1,5 @@ import gymnasium as gym gym.register( - id="f110-v0", - entry_point="f110_gym.envs:F110Env", + id="f110-v0", entry_point="f110_gym.envs:F110Env", ) diff --git a/gym/f110_gym/envs/action.py b/gym/f110_gym/envs/action.py index fcdbc817..080348e4 100644 --- a/gym/f110_gym/envs/action.py +++ b/gym/f110_gym/envs/action.py @@ -21,7 +21,8 @@ def from_string(action: str): return SpeedAction else: raise ValueError(f"Unknown action type {action}") - + + class LongitudinalAction: def __init__(self) -> None: self._type = None @@ -39,7 +40,10 @@ def type(self) -> str: @property def space(self) -> gym.Space: - return gym.spaces.Box(low=self.lower_limit, high=self.upper_limit, dtype=np.float32) + return gym.spaces.Box( + low=self.lower_limit, high=self.upper_limit, dtype=np.float32 + ) + class AcclAction(LongitudinalAction): def __init__(self, params: Dict) -> None: @@ -50,6 +54,7 @@ def __init__(self, params: Dict) -> None: def act(self, action: Tuple[float, float], state, params) -> float: return action + class SpeedAction(LongitudinalAction): def __init__(self, params: Dict) -> None: super().__init__() @@ -60,15 +65,12 @@ def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict ) -> float: accl = pid_accl( - action, - state[3], - params["a_max"], - params["v_max"], - params["v_min"], + action, state[3], params["a_max"], params["v_max"], params["v_min"], ) return accl + class SteerAction: def __init__(self) -> None: self._type = None @@ -83,10 +85,13 @@ def act(self, steer_action: Any, **kwargs) -> float: @property def type(self) -> str: return self._type - + @property def space(self) -> gym.Space: - return gym.spaces.Box(low=self.lower_limit, high=self.upper_limit, dtype=np.float32) + return gym.spaces.Box( + low=self.lower_limit, high=self.upper_limit, dtype=np.float32 + ) + class SteeringAngleAction(SteerAction): def __init__(self, params: Dict) -> None: @@ -96,14 +101,11 @@ def __init__(self, params: Dict) -> None: def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict - ) -> float: - sv = pid_steer( - action, - state[2], - params["sv_max"], - ) + ) -> float: + sv = pid_steer(action, state[2], params["sv_max"],) return sv - + + class SteeringSpeedAction(SteerAction): def __init__(self, params: Dict) -> None: super().__init__() @@ -112,9 +114,10 @@ def __init__(self, params: Dict) -> None: def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict - ) -> float: + ) -> float: return action + class SteerActionEnum(Enum): Steering_Angle = 1 Steering_Speed = 2 @@ -128,11 +131,12 @@ def from_string(action: str): else: raise ValueError(f"Unknown action type {action}") + class CarAction: - def __init__(self, control_mode : list[str, str], params: Dict) -> None: + def __init__(self, control_mode: list[str, str], params: Dict) -> None: long_act_type_fn = None steer_act_type_fn = None - if type(control_mode) == str: # only one control mode specified + if type(control_mode) == str: # only one control mode specified try: long_act_type_fn = LongitudinalActionEnum.from_string(control_mode) except ValueError: @@ -142,24 +146,24 @@ def __init__(self, control_mode : list[str, str], params: Dict) -> None: raise ValueError(f"Unknown control mode {control_mode}") if control_mode == "steering_speed": warnings.warn( - f'Only one control mode specified, using {control_mode} for steering and defaulting to acceleration for longitudinal control' + f"Only one control mode specified, using {control_mode} for steering and defaulting to acceleration for longitudinal control" ) long_act_type_fn = LongitudinalActionEnum.from_string("accl") else: warnings.warn( - f'Only one control mode specified, using {control_mode} for steering and defaulting to speed for longitudinal control' + f"Only one control mode specified, using {control_mode} for steering and defaulting to speed for longitudinal control" ) long_act_type_fn = LongitudinalActionEnum.from_string("speed") else: if control_mode == "accl": warnings.warn( - f'Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering speed for steering' + f"Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering speed for steering" ) steer_act_type_fn = SteerActionEnum.from_string("steering_speed") else: warnings.warn( - f'Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering angle for steering' + f"Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering angle for steering" ) steer_act_type_fn = SteerActionEnum.from_string("steering_angle") @@ -168,9 +172,9 @@ def __init__(self, control_mode : list[str, str], params: Dict) -> None: steer_act_type_fn = SteerActionEnum.from_string(control_mode[1]) else: raise ValueError(f"Unknown control mode {control_mode}") - - self._longitudinal_action : LongitudinalAction = long_act_type_fn(params) - self._steer_action : SteerAction = steer_act_type_fn(params) + + self._longitudinal_action: LongitudinalAction = long_act_type_fn(params) + self._steer_action: SteerAction = steer_act_type_fn(params) @abstractmethod def act(self, action: Any, **kwargs) -> Tuple[float, float]: @@ -184,8 +188,12 @@ def type(self) -> Tuple[str, str]: @property def space(self) -> gym.Space: - low = np.array([self._steer_action.lower_limit, self._longitudinal_action.lower_limit]).astype(np.float32) - high = np.array([self._steer_action.upper_limit, self._longitudinal_action.upper_limit]).astype(np.float32) + low = np.array( + [self._steer_action.lower_limit, self._longitudinal_action.lower_limit] + ).astype(np.float32) + high = np.array( + [self._steer_action.upper_limit, self._longitudinal_action.upper_limit] + ).astype(np.float32) return gym.spaces.Box(low=low, high=high, shape=(2,), dtype=np.float32) diff --git a/gym/f110_gym/envs/cubic_spline.py b/gym/f110_gym/envs/cubic_spline.py index 8b1a0fab..5ed193d6 100644 --- a/gym/f110_gym/envs/cubic_spline.py +++ b/gym/f110_gym/envs/cubic_spline.py @@ -64,7 +64,7 @@ def calc_position(self, x): i = self.__search_index(x) dx = x - self.x[i] position = ( - self.a[i] + self.b[i] * dx + self.c[i] * dx**2.0 + self.d[i] * dx**3.0 + self.a[i] + self.b[i] * dx + self.c[i] * dx ** 2.0 + self.d[i] * dx ** 3.0 ) return position @@ -86,7 +86,7 @@ def calc_first_derivative(self, x): i = self.__search_index(x) dx = x - self.x[i] - dy = self.b[i] + 2.0 * self.c[i] * dx + 3.0 * self.d[i] * dx**2.0 + dy = self.b[i] + 2.0 * self.c[i] * dx + 3.0 * self.d[i] * dx ** 2.0 return dy def calc_second_derivative(self, x): @@ -205,7 +205,7 @@ def calc_curvature(self, s): ddx = self.sx.calc_second_derivative(s) dy = self.sy.calc_first_derivative(s) ddy = self.sy.calc_second_derivative(s) - k = (ddy * dx - ddx * dy) / ((dx**2 + dy**2) ** (3 / 2)) + k = (ddy * dx - ddx * dy) / ((dx ** 2 + dy ** 2) ** (3 / 2)) return k def calc_yaw(self, s): diff --git a/gym/f110_gym/envs/f110_env.py b/gym/f110_gym/envs/f110_env.py index bb14d753..b021d326 100644 --- a/gym/f110_gym/envs/f110_env.py +++ b/gym/f110_gym/envs/f110_env.py @@ -27,8 +27,7 @@ # gym imports import gymnasium as gym -from f110_gym.envs.action import (CarAction, - from_single_to_multi_action_space) +from f110_gym.envs.action import CarAction, from_single_to_multi_action_space from f110_gym.envs.integrator import IntegratorType from f110_gym.envs.rendering import make_renderer @@ -240,7 +239,9 @@ def configure(self, config: dict) -> None: if hasattr(self, "action_space"): # if some parameters changed, recompute action space - self.action_type = CarAction(self.config["control_input"], params=self.params) + self.action_type = CarAction( + self.config["control_input"], params=self.params + ) self.action_space = from_single_to_multi_action_space( self.action_type.space, self.num_agents ) @@ -272,7 +273,7 @@ def _check_done(self): temp_y[idx2] = -right_t - temp_y[idx2] temp_y[np.invert(np.logical_or(idx1, idx2))] = 0 - dist2 = delta_pt[0, :] ** 2 + temp_y**2 + dist2 = delta_pt[0, :] ** 2 + temp_y ** 2 closes = dist2 <= 0.1 for i in range(self.num_agents): if closes[i] and not self.near_starts[i]: diff --git a/gym/f110_gym/envs/f110_env_backup.py b/gym/f110_gym/envs/f110_env_backup.py index b488492d..62644e62 100644 --- a/gym/f110_gym/envs/f110_env_backup.py +++ b/gym/f110_gym/envs/f110_env_backup.py @@ -263,7 +263,7 @@ def _check_done(self): temp_y[idx2] = -right_t - temp_y[idx2] temp_y[np.invert(np.logical_or(idx1, idx2))] = 0 - dist2 = delta_pt[0, :] ** 2 + temp_y**2 + dist2 = delta_pt[0, :] ** 2 + temp_y ** 2 closes = dist2 <= 0.1 for i in range(self.num_agents): if closes[i] and not self.near_starts[i]: @@ -291,7 +291,7 @@ def _check_done(self): temp_y = -right_t - delta_pt[1] else: temp_y = 0 - dist2 = delta_pt[0] ** 2 + temp_y**2 + dist2 = delta_pt[0] ** 2 + temp_y ** 2 close = dist2 <= 0.1 # close = dist_to_start <= self.start_thresh if close and not self.near_start: diff --git a/gym/f110_gym/envs/reset/__init__.py b/gym/f110_gym/envs/reset/__init__.py index d5f56ea1..d15f0379 100644 --- a/gym/f110_gym/envs/reset/__init__.py +++ b/gym/f110_gym/envs/reset/__init__.py @@ -13,9 +13,19 @@ def make_reset_fn(type: str | None, track: Track, num_agents: int, **kwargs) -> refline = {"cl": track.centerline, "rl": track.raceline}[refline_token] reset_fn = {"grid": GridResetFn, "random": AllTrackResetFn}[reset_token] shuffle = {"static": False, "random": True}[shuffle_token] - options = {"cl": {"move_laterally": True}, "rl": {"move_laterally": False}}[refline_token] + options = {"cl": {"move_laterally": True}, "rl": {"move_laterally": False}}[ + refline_token + ] except Exception as ex: - raise ValueError(f"Invalid reset function type: {type}. Expected format: __") from ex + raise ValueError( + f"Invalid reset function type: {type}. Expected format: __" + ) from ex - return reset_fn(reference_line=refline, num_agents=num_agents, shuffle=shuffle, **options, **kwargs) + return reset_fn( + reference_line=refline, + num_agents=num_agents, + shuffle=shuffle, + **options, + **kwargs, + ) diff --git a/gym/f110_gym/test/benchmark_renderer.py b/gym/f110_gym/test/benchmark_renderer.py index 4cfc4277..645907f1 100644 --- a/gym/f110_gym/test/benchmark_renderer.py +++ b/gym/f110_gym/test/benchmark_renderer.py @@ -55,11 +55,7 @@ def _make_env(config={}, render_mode=None) -> F110Env: } config = deep_update(base_config, config) - env = gym.make( - "f110_gym:f110-v0", - config=config, - render_mode=render_mode, - ) + env = gym.make("f110_gym:f110-v0", config=config, render_mode=render_mode,) return env diff --git a/gym/f110_gym/test/test_renderer.py b/gym/f110_gym/test/test_renderer.py index b0eda58a..80f98600 100644 --- a/gym/f110_gym/test/test_renderer.py +++ b/gym/f110_gym/test/test_renderer.py @@ -24,11 +24,7 @@ def _make_env(config={}, render_mode=None) -> F110Env: } config = deep_update(base_config, config) - env = gym.make( - "f110_gym:f110-v0", - config=config, - render_mode=render_mode, - ) + env = gym.make("f110_gym:f110-v0", config=config, render_mode=render_mode,) return env diff --git a/tests/legacy_scan_gen.py b/tests/legacy_scan_gen.py index 0fe7d58b..62e24a55 100644 --- a/tests/legacy_scan_gen.py +++ b/tests/legacy_scan_gen.py @@ -25,11 +25,7 @@ env = gym.make( "f110_gym:f110-v0", - config={ - "map": map_name, - "num_agents": 1, - "params": params, - }, + config={"map": map_name, "num_agents": 1, "params": params,}, ) scan = np.empty((num_test, 1080)) diff --git a/tests/test_f110_env.py b/tests/test_f110_env.py index 053a2b20..fdc8513f 100644 --- a/tests/test_f110_env.py +++ b/tests/test_f110_env.py @@ -17,10 +17,7 @@ def _make_env(self, config={}): } conf = deep_update(conf, config) - env = gym.make( - "f110_gym:f110-v0", - config=conf, - ) + env = gym.make("f110_gym:f110-v0", config=conf,) return env def test_gymnasium_api(self): diff --git a/tests/test_scan_sim.py b/tests/test_scan_sim.py index 3dc859ed..d943f458 100644 --- a/tests/test_scan_sim.py +++ b/tests/test_scan_sim.py @@ -56,7 +56,7 @@ def _test_map_scan(self, map_name: str, debug=False): test_pose = self.test_poses[i] new_scan[i, :] = scan_sim.scan(pose=test_pose, rng=scan_rng) diff = self.sample_scans[map_name] - new_scan - mse = np.mean(diff**2) + mse = np.mean(diff ** 2) if debug: # plotting @@ -69,7 +69,6 @@ def _test_map_scan(self, map_name: str, debug=False): self.assertLess(mse, 2.0) - def test_map_spielberg(self, debug=False): self._test_map_scan("Spielberg", debug=debug) From 0f58edab77603f41407fd3f570104ed19e1c9aec Mon Sep 17 00:00:00 2001 From: Luigi Berducci Date: Thu, 25 Jan 2024 16:53:00 +0100 Subject: [PATCH 3/5] move tests to tests/ and remove empty/unused scripts --- gym/f110_gym/test/benchmark_renderer.py | 218 ------------------ gym/f110_gym/test/test_scan_sim.py | 0 {gym/f110_gym/test => tests}/test_renderer.py | 0 3 files changed, 218 deletions(-) delete mode 100644 gym/f110_gym/test/benchmark_renderer.py delete mode 100644 gym/f110_gym/test/test_scan_sim.py rename {gym/f110_gym/test => tests}/test_renderer.py (100%) diff --git a/gym/f110_gym/test/benchmark_renderer.py b/gym/f110_gym/test/benchmark_renderer.py deleted file mode 100644 index 645907f1..00000000 --- a/gym/f110_gym/test/benchmark_renderer.py +++ /dev/null @@ -1,218 +0,0 @@ -import numpy as np - -from f110_gym.envs import F110Env -from f110_gym.envs.utils import deep_update - - -def pretty_print(dict: dict, col_width=15): - keys = list(dict.keys()) - columns = ["key"] + [str(k) for k in dict[keys[0]]] - - # opening line - for _ in columns: - print("|" + "-" * col_width, end="") - print("|") - # header - for col in columns: - padding = max(0, col_width - len(col)) - print("|" + col[:col_width] + " " * padding, end="") - print("|") - # separator line - for _ in columns: - print("|" + "-" * col_width, end="") - print("|") - - # table - for key in keys: - padding = max(0, col_width - len(str(key))) - print("|" + str(key)[:col_width] + " " * padding, end="") - for col in columns[1:]: - padding = max(0, col_width - len(str(dict[key][col]))) - print("|" + str(dict[key][col])[:col_width] + " " * padding, end="") - print("|") - - # footer - for col in columns: - print("|" + "-" * col_width, end="") - print("|") - - -class BenchmarkRenderer: - @staticmethod - def _make_env(config={}, render_mode=None) -> F110Env: - import gymnasium as gym - import f110_gym - - base_config = { - "map": "Spielberg", - "num_agents": 1, - "timestep": 0.01, - "integrator": "rk4", - "control_input": ["speed", "steering_angle"], - "model": "st", - "observation_config": {"type": "kinematic_state"}, - "params": {"mu": 1.0}, - } - config = deep_update(base_config, config) - - env = gym.make("f110_gym:f110-v0", config=config, render_mode=render_mode,) - - return env - - def benchmark_single_agent_rendering(self): - import time - - sim_time = 15.0 # seconds - results = {} - - for render_mode in [None, "human", "human_fast", "rgb_array", "rgb_array_list"]: - env = self._make_env(render_mode=render_mode) - env.reset() - frame = env.render() - - print( - f"Running simulation of {sim_time}s for render mode: {render_mode}..." - ) - - max_steps = int(sim_time / env.timestep) - t0 = time.time() - for _ in range(max_steps): - action = env.action_space.sample() - env.step(action) - frame = env.render() - tf = time.time() - env.close() - - results[render_mode] = { - "sim_time": sim_time, - "elapsed_time": tf - t0, - "fps": max_steps / (tf - t0), - } - - pretty_print(results) - - def benchmark_n_agents_human_rendering(self): - """ - This is meant to benchmark the human rendering mode, for increasing nr of agents. - """ - import time - - sim_time = 15.0 # seconds - render_mode = "human" - - results = {} - - for num_agents in [1, 2, 3, 4, 5, 10]: - env = self._make_env( - config={"num_agents": num_agents}, render_mode=render_mode - ) - env.reset() - frame = env.render() - - print( - f"Running simulation of {num_agents} agents for render mode: {render_mode}..." - ) - - max_steps = int(sim_time / env.timestep) - t0 = time.time() - for _ in range(max_steps): - action = env.action_space.sample() - env.step(action) - frame = env.render() - tf = time.time() - env.close() - - results[num_agents] = { - "sim_time": sim_time, - "elapsed_time": tf - t0, - "fps": max_steps / (tf - t0), - } - - pretty_print(results) - - def benchmark_callbacks_human_rendering(self): - import time - - sim_time = 15.0 # seconds - render_mode = "human" - - results = {} - - class GoStraightPlanner: - def __init__(self, env, agent_id: str = "agent_0"): - self.waypoints = np.stack( - [env.track.raceline.xs, env.track.raceline.ys] - ).T - self.pos = None - self.agent_id = agent_id - - def plan(self, obs): - state = obs[self.agent_id] - self.pos = np.array([state["pose_x"], state["pose_y"]]) - return np.array([0.0, 2.5]) - - def render_waypoints(self, e): - e.render_closed_lines(points=self.waypoints, size=1) - - def render_position(self, e): - if self.pos is not None: - points = self.pos[None] - e.render_points(points, size=1) - - for render_config in [[False, False], [True, False], [True, True]]: - env = self._make_env(render_mode=render_mode) - planner = GoStraightPlanner(env) - - show_path, show_point = render_config - config_str = f"show_path={show_path}, show_point={show_point}" - - if show_path: - env.add_render_callback(callback_func=planner.render_waypoints) - - if show_point: - env.add_render_callback(callback_func=planner.render_position) - - rnd_idx = np.random.randint(0, len(env.track.raceline.xs)) - obs, _ = env.reset( - options={ - "poses": np.array( - [ - [ - env.track.raceline.xs[rnd_idx], - env.track.raceline.ys[rnd_idx], - env.track.raceline.yaws[rnd_idx], - ] - ] - ) - } - ) - frame = env.render() - - print( - f"Running simulation of {config_str} for render mode: {render_mode}..." - ) - - max_steps = int(sim_time / env.timestep) - t0 = time.time() - for _ in range(max_steps): - action = planner.plan(obs=obs) - obs, _, _, _, _ = env.step(np.array([action])) - frame = env.render() - tf = time.time() - env.close() - - results[config_str] = { - "sim_time": sim_time, - "elapsed_time": tf - t0, - "fps": max_steps / (tf - t0), - } - - pretty_print(results) - - -if __name__ == "__main__": - benchmark = BenchmarkRenderer() - - benchmark.benchmark_single_agent_rendering() - benchmark.benchmark_n_agents_human_rendering() - benchmark.benchmark_callbacks_human_rendering() diff --git a/gym/f110_gym/test/test_scan_sim.py b/gym/f110_gym/test/test_scan_sim.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gym/f110_gym/test/test_renderer.py b/tests/test_renderer.py similarity index 100% rename from gym/f110_gym/test/test_renderer.py rename to tests/test_renderer.py From 511ff02d505117bdc03a9df64d7a2603e9ce1dba Mon Sep 17 00:00:00 2001 From: Luigi Berducci Date: Thu, 1 Feb 2024 19:16:43 +0100 Subject: [PATCH 4/5] Revert "linting" This reverts commit ff7a3a16 --- examples/video_recording.py | 8 +++- examples/waypoint_follow.py | 2 +- gym/f110_gym/__init__.py | 3 +- gym/f110_gym/envs/action.py | 64 +++++++++++-------------- gym/f110_gym/envs/cubic_spline.py | 6 +-- gym/f110_gym/envs/f110_env.py | 9 ++-- gym/f110_gym/envs/f110_env_backup.py | 4 +- gym/f110_gym/envs/reset/__init__.py | 16 ++----- gym/f110_gym/test/benchmark_renderer.py | 0 tests/legacy_scan_gen.py | 6 ++- tests/test_f110_env.py | 5 +- tests/test_renderer.py | 6 ++- tests/test_scan_sim.py | 3 +- 13 files changed, 66 insertions(+), 66 deletions(-) create mode 100644 gym/f110_gym/test/benchmark_renderer.py diff --git a/examples/video_recording.py b/examples/video_recording.py index 7ab83de6..3c593fbe 100644 --- a/examples/video_recording.py +++ b/examples/video_recording.py @@ -34,7 +34,13 @@ def main(): planner = PurePursuitPlanner(track=track, wb=0.17145 + 0.15875) poses = np.array( - [[track.raceline.xs[0], track.raceline.ys[0], track.raceline.yaws[0],]] + [ + [ + track.raceline.xs[0], + track.raceline.ys[0], + track.raceline.yaws[0], + ] + ] ) obs, info = env.reset(options={"poses": poses}) diff --git a/examples/waypoint_follow.py b/examples/waypoint_follow.py index 46d7a950..596ac28b 100644 --- a/examples/waypoint_follow.py +++ b/examples/waypoint_follow.py @@ -166,7 +166,7 @@ def get_actuation(pose_theta, lookahead_point, position, lookahead_distance, whe speed = lookahead_point[2] if np.abs(waypoint_y) < 1e-6: return speed, 0.0 - radius = 1 / (2.0 * waypoint_y / lookahead_distance ** 2) + radius = 1 / (2.0 * waypoint_y / lookahead_distance**2) steering_angle = np.arctan(wheelbase / radius) return speed, steering_angle diff --git a/gym/f110_gym/__init__.py b/gym/f110_gym/__init__.py index a993eb05..20052799 100644 --- a/gym/f110_gym/__init__.py +++ b/gym/f110_gym/__init__.py @@ -1,5 +1,6 @@ import gymnasium as gym gym.register( - id="f110-v0", entry_point="f110_gym.envs:F110Env", + id="f110-v0", + entry_point="f110_gym.envs:F110Env", ) diff --git a/gym/f110_gym/envs/action.py b/gym/f110_gym/envs/action.py index 080348e4..fcdbc817 100644 --- a/gym/f110_gym/envs/action.py +++ b/gym/f110_gym/envs/action.py @@ -21,8 +21,7 @@ def from_string(action: str): return SpeedAction else: raise ValueError(f"Unknown action type {action}") - - + class LongitudinalAction: def __init__(self) -> None: self._type = None @@ -40,10 +39,7 @@ def type(self) -> str: @property def space(self) -> gym.Space: - return gym.spaces.Box( - low=self.lower_limit, high=self.upper_limit, dtype=np.float32 - ) - + return gym.spaces.Box(low=self.lower_limit, high=self.upper_limit, dtype=np.float32) class AcclAction(LongitudinalAction): def __init__(self, params: Dict) -> None: @@ -54,7 +50,6 @@ def __init__(self, params: Dict) -> None: def act(self, action: Tuple[float, float], state, params) -> float: return action - class SpeedAction(LongitudinalAction): def __init__(self, params: Dict) -> None: super().__init__() @@ -65,12 +60,15 @@ def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict ) -> float: accl = pid_accl( - action, state[3], params["a_max"], params["v_max"], params["v_min"], + action, + state[3], + params["a_max"], + params["v_max"], + params["v_min"], ) return accl - class SteerAction: def __init__(self) -> None: self._type = None @@ -85,13 +83,10 @@ def act(self, steer_action: Any, **kwargs) -> float: @property def type(self) -> str: return self._type - + @property def space(self) -> gym.Space: - return gym.spaces.Box( - low=self.lower_limit, high=self.upper_limit, dtype=np.float32 - ) - + return gym.spaces.Box(low=self.lower_limit, high=self.upper_limit, dtype=np.float32) class SteeringAngleAction(SteerAction): def __init__(self, params: Dict) -> None: @@ -101,11 +96,14 @@ def __init__(self, params: Dict) -> None: def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict - ) -> float: - sv = pid_steer(action, state[2], params["sv_max"],) + ) -> float: + sv = pid_steer( + action, + state[2], + params["sv_max"], + ) return sv - - + class SteeringSpeedAction(SteerAction): def __init__(self, params: Dict) -> None: super().__init__() @@ -114,10 +112,9 @@ def __init__(self, params: Dict) -> None: def act( self, action: Tuple[float, float], state: np.ndarray, params: Dict - ) -> float: + ) -> float: return action - class SteerActionEnum(Enum): Steering_Angle = 1 Steering_Speed = 2 @@ -131,12 +128,11 @@ def from_string(action: str): else: raise ValueError(f"Unknown action type {action}") - class CarAction: - def __init__(self, control_mode: list[str, str], params: Dict) -> None: + def __init__(self, control_mode : list[str, str], params: Dict) -> None: long_act_type_fn = None steer_act_type_fn = None - if type(control_mode) == str: # only one control mode specified + if type(control_mode) == str: # only one control mode specified try: long_act_type_fn = LongitudinalActionEnum.from_string(control_mode) except ValueError: @@ -146,24 +142,24 @@ def __init__(self, control_mode: list[str, str], params: Dict) -> None: raise ValueError(f"Unknown control mode {control_mode}") if control_mode == "steering_speed": warnings.warn( - f"Only one control mode specified, using {control_mode} for steering and defaulting to acceleration for longitudinal control" + f'Only one control mode specified, using {control_mode} for steering and defaulting to acceleration for longitudinal control' ) long_act_type_fn = LongitudinalActionEnum.from_string("accl") else: warnings.warn( - f"Only one control mode specified, using {control_mode} for steering and defaulting to speed for longitudinal control" + f'Only one control mode specified, using {control_mode} for steering and defaulting to speed for longitudinal control' ) long_act_type_fn = LongitudinalActionEnum.from_string("speed") else: if control_mode == "accl": warnings.warn( - f"Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering speed for steering" + f'Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering speed for steering' ) steer_act_type_fn = SteerActionEnum.from_string("steering_speed") else: warnings.warn( - f"Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering angle for steering" + f'Only one control mode specified, using {control_mode} for longitudinal control and defaulting to steering angle for steering' ) steer_act_type_fn = SteerActionEnum.from_string("steering_angle") @@ -172,9 +168,9 @@ def __init__(self, control_mode: list[str, str], params: Dict) -> None: steer_act_type_fn = SteerActionEnum.from_string(control_mode[1]) else: raise ValueError(f"Unknown control mode {control_mode}") - - self._longitudinal_action: LongitudinalAction = long_act_type_fn(params) - self._steer_action: SteerAction = steer_act_type_fn(params) + + self._longitudinal_action : LongitudinalAction = long_act_type_fn(params) + self._steer_action : SteerAction = steer_act_type_fn(params) @abstractmethod def act(self, action: Any, **kwargs) -> Tuple[float, float]: @@ -188,12 +184,8 @@ def type(self) -> Tuple[str, str]: @property def space(self) -> gym.Space: - low = np.array( - [self._steer_action.lower_limit, self._longitudinal_action.lower_limit] - ).astype(np.float32) - high = np.array( - [self._steer_action.upper_limit, self._longitudinal_action.upper_limit] - ).astype(np.float32) + low = np.array([self._steer_action.lower_limit, self._longitudinal_action.lower_limit]).astype(np.float32) + high = np.array([self._steer_action.upper_limit, self._longitudinal_action.upper_limit]).astype(np.float32) return gym.spaces.Box(low=low, high=high, shape=(2,), dtype=np.float32) diff --git a/gym/f110_gym/envs/cubic_spline.py b/gym/f110_gym/envs/cubic_spline.py index 5ed193d6..8b1a0fab 100644 --- a/gym/f110_gym/envs/cubic_spline.py +++ b/gym/f110_gym/envs/cubic_spline.py @@ -64,7 +64,7 @@ def calc_position(self, x): i = self.__search_index(x) dx = x - self.x[i] position = ( - self.a[i] + self.b[i] * dx + self.c[i] * dx ** 2.0 + self.d[i] * dx ** 3.0 + self.a[i] + self.b[i] * dx + self.c[i] * dx**2.0 + self.d[i] * dx**3.0 ) return position @@ -86,7 +86,7 @@ def calc_first_derivative(self, x): i = self.__search_index(x) dx = x - self.x[i] - dy = self.b[i] + 2.0 * self.c[i] * dx + 3.0 * self.d[i] * dx ** 2.0 + dy = self.b[i] + 2.0 * self.c[i] * dx + 3.0 * self.d[i] * dx**2.0 return dy def calc_second_derivative(self, x): @@ -205,7 +205,7 @@ def calc_curvature(self, s): ddx = self.sx.calc_second_derivative(s) dy = self.sy.calc_first_derivative(s) ddy = self.sy.calc_second_derivative(s) - k = (ddy * dx - ddx * dy) / ((dx ** 2 + dy ** 2) ** (3 / 2)) + k = (ddy * dx - ddx * dy) / ((dx**2 + dy**2) ** (3 / 2)) return k def calc_yaw(self, s): diff --git a/gym/f110_gym/envs/f110_env.py b/gym/f110_gym/envs/f110_env.py index b021d326..bb14d753 100644 --- a/gym/f110_gym/envs/f110_env.py +++ b/gym/f110_gym/envs/f110_env.py @@ -27,7 +27,8 @@ # gym imports import gymnasium as gym -from f110_gym.envs.action import CarAction, from_single_to_multi_action_space +from f110_gym.envs.action import (CarAction, + from_single_to_multi_action_space) from f110_gym.envs.integrator import IntegratorType from f110_gym.envs.rendering import make_renderer @@ -239,9 +240,7 @@ def configure(self, config: dict) -> None: if hasattr(self, "action_space"): # if some parameters changed, recompute action space - self.action_type = CarAction( - self.config["control_input"], params=self.params - ) + self.action_type = CarAction(self.config["control_input"], params=self.params) self.action_space = from_single_to_multi_action_space( self.action_type.space, self.num_agents ) @@ -273,7 +272,7 @@ def _check_done(self): temp_y[idx2] = -right_t - temp_y[idx2] temp_y[np.invert(np.logical_or(idx1, idx2))] = 0 - dist2 = delta_pt[0, :] ** 2 + temp_y ** 2 + dist2 = delta_pt[0, :] ** 2 + temp_y**2 closes = dist2 <= 0.1 for i in range(self.num_agents): if closes[i] and not self.near_starts[i]: diff --git a/gym/f110_gym/envs/f110_env_backup.py b/gym/f110_gym/envs/f110_env_backup.py index 62644e62..b488492d 100644 --- a/gym/f110_gym/envs/f110_env_backup.py +++ b/gym/f110_gym/envs/f110_env_backup.py @@ -263,7 +263,7 @@ def _check_done(self): temp_y[idx2] = -right_t - temp_y[idx2] temp_y[np.invert(np.logical_or(idx1, idx2))] = 0 - dist2 = delta_pt[0, :] ** 2 + temp_y ** 2 + dist2 = delta_pt[0, :] ** 2 + temp_y**2 closes = dist2 <= 0.1 for i in range(self.num_agents): if closes[i] and not self.near_starts[i]: @@ -291,7 +291,7 @@ def _check_done(self): temp_y = -right_t - delta_pt[1] else: temp_y = 0 - dist2 = delta_pt[0] ** 2 + temp_y ** 2 + dist2 = delta_pt[0] ** 2 + temp_y**2 close = dist2 <= 0.1 # close = dist_to_start <= self.start_thresh if close and not self.near_start: diff --git a/gym/f110_gym/envs/reset/__init__.py b/gym/f110_gym/envs/reset/__init__.py index d15f0379..d5f56ea1 100644 --- a/gym/f110_gym/envs/reset/__init__.py +++ b/gym/f110_gym/envs/reset/__init__.py @@ -13,19 +13,9 @@ def make_reset_fn(type: str | None, track: Track, num_agents: int, **kwargs) -> refline = {"cl": track.centerline, "rl": track.raceline}[refline_token] reset_fn = {"grid": GridResetFn, "random": AllTrackResetFn}[reset_token] shuffle = {"static": False, "random": True}[shuffle_token] - options = {"cl": {"move_laterally": True}, "rl": {"move_laterally": False}}[ - refline_token - ] + options = {"cl": {"move_laterally": True}, "rl": {"move_laterally": False}}[refline_token] except Exception as ex: - raise ValueError( - f"Invalid reset function type: {type}. Expected format: __" - ) from ex + raise ValueError(f"Invalid reset function type: {type}. Expected format: __") from ex - return reset_fn( - reference_line=refline, - num_agents=num_agents, - shuffle=shuffle, - **options, - **kwargs, - ) + return reset_fn(reference_line=refline, num_agents=num_agents, shuffle=shuffle, **options, **kwargs) diff --git a/gym/f110_gym/test/benchmark_renderer.py b/gym/f110_gym/test/benchmark_renderer.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/legacy_scan_gen.py b/tests/legacy_scan_gen.py index 62e24a55..0fe7d58b 100644 --- a/tests/legacy_scan_gen.py +++ b/tests/legacy_scan_gen.py @@ -25,7 +25,11 @@ env = gym.make( "f110_gym:f110-v0", - config={"map": map_name, "num_agents": 1, "params": params,}, + config={ + "map": map_name, + "num_agents": 1, + "params": params, + }, ) scan = np.empty((num_test, 1080)) diff --git a/tests/test_f110_env.py b/tests/test_f110_env.py index fdc8513f..053a2b20 100644 --- a/tests/test_f110_env.py +++ b/tests/test_f110_env.py @@ -17,7 +17,10 @@ def _make_env(self, config={}): } conf = deep_update(conf, config) - env = gym.make("f110_gym:f110-v0", config=conf,) + env = gym.make( + "f110_gym:f110-v0", + config=conf, + ) return env def test_gymnasium_api(self): diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 80f98600..b0eda58a 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -24,7 +24,11 @@ def _make_env(config={}, render_mode=None) -> F110Env: } config = deep_update(base_config, config) - env = gym.make("f110_gym:f110-v0", config=config, render_mode=render_mode,) + env = gym.make( + "f110_gym:f110-v0", + config=config, + render_mode=render_mode, + ) return env diff --git a/tests/test_scan_sim.py b/tests/test_scan_sim.py index d943f458..3dc859ed 100644 --- a/tests/test_scan_sim.py +++ b/tests/test_scan_sim.py @@ -56,7 +56,7 @@ def _test_map_scan(self, map_name: str, debug=False): test_pose = self.test_poses[i] new_scan[i, :] = scan_sim.scan(pose=test_pose, rng=scan_rng) diff = self.sample_scans[map_name] - new_scan - mse = np.mean(diff ** 2) + mse = np.mean(diff**2) if debug: # plotting @@ -69,6 +69,7 @@ def _test_map_scan(self, map_name: str, debug=False): self.assertLess(mse, 2.0) + def test_map_spielberg(self, debug=False): self._test_map_scan("Spielberg", debug=debug) From fdd01e5396569d62bce94ac08e2ffd1ada8a782d Mon Sep 17 00:00:00 2001 From: Luigi Berducci Date: Thu, 1 Feb 2024 19:20:32 +0100 Subject: [PATCH 5/5] removed pending file after rever --- gym/f110_gym/test/benchmark_renderer.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 gym/f110_gym/test/benchmark_renderer.py diff --git a/gym/f110_gym/test/benchmark_renderer.py b/gym/f110_gym/test/benchmark_renderer.py deleted file mode 100644 index e69de29b..00000000