diff --git a/gym/f110_gym/envs/base_classes.py b/gym/f110_gym/envs/base_classes.py index 9b5ec94f..baae814b 100644 --- a/gym/f110_gym/envs/base_classes.py +++ b/gym/f110_gym/envs/base_classes.py @@ -46,17 +46,26 @@ class RaceCar(object): """ Base level race car class, handles the physics and laser scan of a single vehicle - Data Members: - params (dict): vehicle parameters dictionary - is_ego (bool): ego identifier - time_step (float): physics timestep - num_beams (int): number of beams in laser - fov (float): field of view of laser + Attributes + ---------- + params : dict + vehicle parameters dictionary + is_ego : bool + ego identifier + time_step : float + physics timestep + num_beams : int + number of beams in laser + fov : float + field of view of laser state (np.ndarray (7, )): state vector [x, y, theta, vel, steer_angle, ang_vel, slip_angle] odom (np.ndarray(13, )): odometry vector [x, y, z, qx, qy, qz, qw, linear_x, linear_y, linear_z, angular_x, angular_y, angular_z] - accel (float): current acceleration input - steer_angle_vel (float): current steering velocity input - in_collision (bool): collision indicator + accel : float + current acceleration input + steer_angle_vel : float + current steering velocity input + in_collision : bool + collision indicator """ @@ -70,16 +79,21 @@ def __init__(self, params, seed, is_ego=False, time_step=0.01, num_beams=1080, f """ Init function - Args: - params (dict): vehicle parameter dictionary, includes {'mu', 'C_Sf', 'C_Sr', 'lf', 'lr', 'h', 'm', 'I', 's_min', 's_max', 'sv_min', 'sv_max', 'v_switch', 'a_max': 9.51, 'v_min', 'v_max', 'length', 'width'} - is_ego (bool, default=False): ego identifier - time_step (float, default=0.01): physics sim time step - num_beams (int, default=1080): number of beams in the laser scan - fov (float, default=4.7): field of view of the laser - lidar_dist (float, default=0): vertical distance between LiDAR and backshaft + Parameters + ---------- + params : dict + vehicle parameter dictionary, includes {'mu', 'C_Sf', 'C_Sr', 'lf', 'lr', 'h', 'm', 'I', 's_min', 's_max', 'sv_min', 'sv_max', 'v_switch', 'a_max': 9.51, 'v_min', 'v_max', 'length', 'width'} + is_ego : bool, default False + ego identifier + time_step : float, default 0.01 + physics sim time step + num_beams : int, default 1080 + number of beams in the laser scan + fov : float, default 4.7 + field of view of the laser + lidar_dist : float, default 0 + vertical distance between LiDAR and backshaft - Returns: - None """ # initialization @@ -162,33 +176,37 @@ def update_params(self, params): Updates the physical parameters of the vehicle Note that does not need to be called at initialization of class anymore - Args: - params (dict): new parameters for the vehicle + Parameters + ---------- + params : dict + new parameters for the vehicle - Returns: - None """ self.params = params def set_map(self, map_path, map_ext): """ Sets the map for scan simulator - - Args: - map_path (str): absolute path to the map yaml file - map_ext (str): extension of the map image file + + Parameters + ---------- + map_path : str + absolute path to the map yaml file + map_ext : str + extension of the map image file + """ RaceCar.scan_simulator.set_map(map_path, map_ext) def reset(self, pose): """ Resets the vehicle to a pose - - Args: - pose (np.ndarray (3, )): pose to reset the vehicle to - Returns: - None + Parameters + ---------- + pose : np.ndarray (3,) + Pose to reset the vehicle to [x, y, theta]. + """ # clear control inputs self.accel = 0.0 @@ -207,11 +225,14 @@ def ray_cast_agents(self, scan): """ Ray cast onto other agents in the env, modify original scan - Args: - scan (np.ndarray, (n, )): original scan range array + Parameters + ---------- + scan : np.ndarray (n,) + Original scan range array. + + Returns + ------- - Returns: - new_scan (np.ndarray, (n, )): modified scan """ # starting from original scan @@ -233,11 +254,10 @@ def check_ttc(self, current_scan): state is [x, y, steer_angle, vel, yaw_angle, yaw_rate, slip_angle] - Args: - current_scan + Parameters + ---------- + current_scan - Returns: - None """ in_collision = check_ttc_jit(current_scan, self.state[3], self.scan_angles, self.cosines, self.side_distances, self.ttc_thresh) @@ -257,12 +277,17 @@ def update_pose(self, raw_steer, vel): """ Steps the vehicle's physical simulation - Args: - steer (float): desired steering angle - vel (float): desired longitudinal velocity + Parameters + ---------- + steer : float + desired steering angle + vel : float + desired longitudinal velocity + + Returns + ------- + current_scan - Returns: - current_scan """ # state is [x, y, steer_angle, vel, yaw_angle, yaw_rate, slip_angle] @@ -416,11 +441,11 @@ def update_opp_poses(self, opp_poses): """ Updates the vehicle's information on other vehicles - Args: - opp_poses (np.ndarray(num_other_agents, 3)): updated poses of other agents + Parameters + ---------- + opp_poses : np.ndarray (num_other_agents, 3) + Updated poses of other agents. - Returns: - None """ self.opp_poses = opp_poses @@ -430,12 +455,11 @@ def update_scan(self, agent_scans, agent_index): Steps the vehicle's laser scan simulation Separated from update_pose because needs to update scan based on NEW poses of agents in the environment - Args: - agent scans list (modified in-place), - agent index (int) + Parameters + ---------- + agent_scans_list : modified in-place + agent index : int - Returns: - None """ current_scan = agent_scans[agent_index] @@ -452,11 +476,15 @@ class Simulator(object): """ Simulator class, handles the interaction and update of all vehicles in the environment - Data Members: - num_agents (int): number of agents in the environment - time_step (float): physics time step + Attributes + ---------- + num_agents : int + number of agents in the environment + time_step : float + physics time step agent_poses (np.ndarray(num_agents, 3)): all poses of all agents - agents (list[RaceCar]): container for RaceCar objects + agents : list[RaceCar] + container for RaceCar objects collisions (np.ndarray(num_agents, )): array of collision indicator for each agent collision_idx (np.ndarray(num_agents, )): which agent is each agent in collision with @@ -466,16 +494,21 @@ def __init__(self, params, num_agents, seed, time_step=0.01, ego_idx=0, integrat """ Init function - Args: - params (dict): vehicle parameter dictionary, includes {'mu', 'C_Sf', 'C_Sr', 'lf', 'lr', 'h', 'm', 'I', 's_min', 's_max', 'sv_min', 'sv_max', 'v_switch', 'a_max', 'v_min', 'v_max', 'length', 'width'} - num_agents (int): number of agents in the environment - seed (int): seed of the rng in scan simulation - time_step (float, default=0.01): physics time step - ego_idx (int, default=0): ego vehicle's index in list of agents - lidar_dist (float, default=0): vertical distance between LiDAR and backshaft + Parameters + ---------- + params : dict + vehicle parameter dictionary, includes {'mu', 'C_Sf', 'C_Sr', 'lf', 'lr', 'h', 'm', 'I', 's_min', 's_max', 'sv_min', 'sv_max', 'v_switch', 'a_max', 'v_min', 'v_max', 'length', 'width'} + num_agents : int + number of agents in the environment + seed : int + seed of the rng in scan simulation + time_step : float, default 0.01 + physics time step + ego_idx : int, default 0 + ego vehicle's index in list of agents + lidar_dist : float, default 0 + vertical distance between LiDAR and backshaft - Returns: - None """ self.num_agents = num_agents self.seed = seed @@ -500,12 +533,13 @@ def set_map(self, map_path, map_ext): """ Sets the map of the environment and sets the map for scan simulator of each agent - Args: - map_path (str): path to the map yaml file - map_ext (str): extension for the map image file + Parameters + ---------- + map_path : str + path to the map yaml file + map_ext : str + extension for the map image file - Returns: - None """ for agent in self.agents: agent.set_map(map_path, map_ext) @@ -515,12 +549,13 @@ def update_params(self, params, agent_idx=-1): """ Updates the params of agents, if an index of an agent is given, update only that agent's params - Args: - params (dict): dictionary of params, see details in docstring of __init__ - agent_idx (int, default=-1): index for agent that needs param update, if negative, update all agents + Parameters + ---------- + params : dict + dictionary of params, see details in docstring of __init__ + agent_idx : int, default -1 + index for agent that needs param update, if negative, update all agents - Returns: - None """ if agent_idx < 0: # update params for all @@ -537,11 +572,6 @@ def check_collision(self): """ Checks for collision between agents using GJK and agents' body vertices - Args: - None - - Returns: - None """ # get vertices of all agents all_vertices = np.empty((self.num_agents, 4, 2)) @@ -554,11 +584,17 @@ def step(self, control_inputs): """ Steps the simulation environment - Args: - control_inputs (np.ndarray (num_agents, 2)): control inputs of all agents, first column is desired steering angle, second column is desired velocity - - Returns: - observations (dict): dictionary for observations: poses of agents, current laser scan of each agent, collision indicators, etc. + Parameters + ---------- + control_inputs : np.ndarray (num_agents, 2) + Control inputs of all agents, first column is desired steering + angle, second column is desired velocity. + + Returns + ------- + observations : dict + dictionary for observations: poses of agents, current laser scan of each agent, collision indicators, etc. + """ @@ -615,11 +651,11 @@ def reset(self, poses): """ Resets the simulation environment by given poses - Arges: - poses (np.ndarray (num_agents, 3)): poses to reset agents to + Parameters + ---------- + poses : np.ndarray (num_agents, 3) + Poses to reset agents to. Each row is [x, y, theta]. - Returns: - None """ if poses.shape[0] != self.num_agents: diff --git a/gym/f110_gym/envs/collision_models.py b/gym/f110_gym/envs/collision_models.py index 45885e7c..4b06f00b 100644 --- a/gym/f110_gym/envs/collision_models.py +++ b/gym/f110_gym/envs/collision_models.py @@ -36,11 +36,14 @@ def perpendicular(pt): """ Return a 2-vector's perpendicular vector - Args: - pt (np.ndarray, (2,)): input vector + Parameters + ---------- + pt : np.ndarray (2,) + Input vector. + + Returns + ------- - Returns: - pt (np.ndarray, (2,)): perpendicular vector """ temp = pt[0] pt[0] = pt[1] @@ -53,11 +56,18 @@ def tripleProduct(a, b, c): """ Return triple product of three vectors - Args: - a, b, c (np.ndarray, (2,)): input vectors + Parameters + ---------- + a : np.ndarray (2,) + First input vector. + b : np.ndarray (2,) + Second input vector. + c : np.ndarray (2,) + Third input vector. + + Returns + ------- - Returns: - (np.ndarray, (2,)): triple product """ ac = a.dot(c) bc = b.dot(c) @@ -69,11 +79,14 @@ def avgPoint(vertices): """ Return the average point of multiple vertices - Args: - vertices (np.ndarray, (n, 2)): the vertices we want to find avg on + Parameters + ---------- + vertices : np.ndarray (n, 2) + The vertices to find average of. + + Returns + ------- - Returns: - avg (np.ndarray, (2,)): average point of the vertices """ return np.sum(vertices, axis=0)/vertices.shape[0] @@ -83,11 +96,18 @@ def indexOfFurthestPoint(vertices, d): """ Return the index of the vertex furthest away along a direction in the list of vertices - Args: - vertices (np.ndarray, (n, 2)): the vertices we want to find avg on + Parameters + ---------- + vertices : np.ndarray (n, 2) + The vertices to search. + d : np.ndarray (2,) + Direction vector. + + Returns + ------- + idx : int + index of the furthest point - Returns: - idx (int): index of the furthest point """ return np.argmax(vertices.dot(d)) @@ -97,13 +117,18 @@ def support(vertices1, vertices2, d): """ Minkowski sum support function for GJK - Args: - vertices1 (np.ndarray, (n, 2)): vertices of the first body - vertices2 (np.ndarray, (n, 2)): vertices of the second body - d (np.ndarray, (2, )): direction to find the support along + Parameters + ---------- + vertices1 : np.ndarray (n, 2) + Vertices of the first body. + vertices2 : np.ndarray (n, 2) + Vertices of the second body. + d : np.ndarray (2,) + Direction to find the support along. + + Returns + ------- - Returns: - support (np.ndarray, (n, 2)): Minkowski sum """ i = indexOfFurthestPoint(vertices1, d) j = indexOfFurthestPoint(vertices2, -d) @@ -115,12 +140,18 @@ def collision(vertices1, vertices2): """ GJK test to see whether two bodies overlap - Args: - vertices1 (np.ndarray, (n, 2)): vertices of the first body - vertices2 (np.ndarray, (n, 2)): vertices of the second body + Parameters + ---------- + vertices1 : np.ndarray (n, 2) + Vertices of the first body. + vertices2 : np.ndarray (n, 2) + Vertices of the second body. + + Returns + ------- + overlap : boolean + True if two bodies collide - Returns: - overlap (boolean): True if two bodies collide """ index = 0 simplex = np.empty((3, 2)) @@ -186,12 +217,14 @@ def collision_multiple(vertices): """ Check pair-wise collisions for all provided vertices - Args: - vertices (np.ndarray (num_bodies, 4, 2)): all vertices for checking pair-wise collision + Parameters + ---------- + vertices : np.ndarray (num_bodies, 4, 2) + All vertices for checking pair-wise collision. + + Returns + ------- - Returns: - collisions (np.ndarray (num_vertices, )): whether each body is in collision - collision_idx (np.ndarray (num_vertices, )): which index of other body is each index's body is in collision, -1 if not in collision """ collisions = np.zeros((vertices.shape[0], )) collision_idx = -1 * np.ones((vertices.shape[0], )) @@ -220,11 +253,11 @@ def get_trmtx(pose): """ Get transformation matrix of vehicle frame -> global frame - Args: - pose (np.ndarray (3, )): current pose of the vehicle + Parameters + ---------- + pose : np.ndarray (3,) + Current pose of the vehicle. - return: - H (np.ndarray (4, 4)): transformation matrix """ x = pose[0] y = pose[1] @@ -239,13 +272,16 @@ def get_vertices(pose, length, width): """ Utility function to return vertices of the car body given pose and size - Args: - pose (np.ndarray, (3, )): current world coordinate pose of the vehicle - length (float): car length - width (float): car width + Parameters + ---------- + length : float + car length + width : float + car width + + Returns + ------- - Returns: - vertices (np.ndarray, (4, 2)): corner vertices of the vehicle body """ H = get_trmtx(pose) rl = H.dot(np.asarray([[-length/2],[width/2],[0.], [1.]])).flatten() diff --git a/gym/f110_gym/envs/dynamic_models.py b/gym/f110_gym/envs/dynamic_models.py index ec18e909..3d555130 100644 --- a/gym/f110_gym/envs/dynamic_models.py +++ b/gym/f110_gym/envs/dynamic_models.py @@ -31,16 +31,26 @@ def accl_constraints(vel, accl, v_switch, a_max, v_min, v_max): """ Acceleration constraints, adjusts the acceleration based on constraints - Args: - vel (float): current velocity of the vehicle - accl (float): unconstraint desired acceleration - v_switch (float): switching velocity (velocity at which the acceleration is no longer able to create wheel spin) - a_max (float): maximum allowed acceleration - v_min (float): minimum allowed velocity - v_max (float): maximum allowed velocity - - Returns: - accl (float): adjusted acceleration + Parameters + ---------- + vel : float + current velocity of the vehicle + accl : float + unconstraint desired acceleration + v_switch : float + switching velocity (velocity at which the acceleration is no longer able to create wheel spin) + a_max : float + maximum allowed acceleration + v_min : float + minimum allowed velocity + v_max : float + maximum allowed velocity + + Returns + ------- + accl : float + adjusted acceleration + """ # positive accl limit @@ -64,16 +74,26 @@ def steering_constraint(steering_angle, steering_velocity, s_min, s_max, sv_min, """ Steering constraints, adjusts the steering velocity based on constraints - Args: - steering_angle (float): current steering_angle of the vehicle - steering_velocity (float): unconstraint desired steering_velocity - s_min (float): minimum steering angle - s_max (float): maximum steering angle - sv_min (float): minimum steering velocity - sv_max (float): maximum steering velocity + Parameters + ---------- + steering_angle : float + current steering_angle of the vehicle + steering_velocity : float + unconstraint desired steering_velocity + s_min : float + minimum steering angle + s_max : float + maximum steering angle + sv_min : float + minimum steering velocity + sv_max : float + maximum steering velocity + + Returns + ------- + steering_velocity : float + adjusted steering velocity - Returns: - steering_velocity (float): adjusted steering velocity """ # constraint steering velocity @@ -92,19 +112,31 @@ def vehicle_dynamics_ks(x, u_init, mu, C_Sf, C_Sr, lf, lr, h, m, I, s_min, s_max """ Single Track Kinematic Vehicle Dynamics. - Args: - x (numpy.ndarray (3, )): vehicle state vector (x1, x2, x3, x4, x5) - x1: x position in global coordinates - x2: y position in global coordinates - x3: steering angle of front wheels - x4: velocity in x direction - x5: yaw angle - u (numpy.ndarray (2, )): control input vector (u1, u2) - u1: steering angle velocity of front wheels - u2: longitudinal acceleration - - Returns: - f (numpy.ndarray): right hand side of differential equations + Parameters + ---------- + x : numpy.ndarray (5,) + Vehicle state vector (x1, x2, x3, x4, x5): + x1: x position in global coordinates, + x2: y position in global coordinates, + x3: steering angle of front wheels, + x4: velocity in x direction, + x5: yaw angle. + u_init : numpy.ndarray (2,) + Control input vector (u1, u2): + u1: steering angle velocity of front wheels, + u2: longitudinal acceleration. + mu, C_Sf, C_Sr, lf, lr, h, m, I : float + Vehicle parameters. + s_min, s_max, sv_min, sv_max : float + Steering constraints. + v_switch, a_max, v_min, v_max : float + Velocity/acceleration constraints. + + Returns + ------- + f : numpy.ndarray + right hand side of differential equations + """ # wheelbase lwb = lf + lr @@ -125,21 +157,33 @@ def vehicle_dynamics_st(x, u_init, mu, C_Sf, C_Sr, lf, lr, h, m, I, s_min, s_max """ Single Track Dynamic Vehicle Dynamics. - Args: - x (numpy.ndarray (3, )): vehicle state vector (x1, x2, x3, x4, x5, x6, x7) - x1: x position in global coordinates - x2: y position in global coordinates - x3: steering angle of front wheels - x4: velocity in x direction - x5: yaw angle - x6: yaw rate - x7: slip angle at vehicle center - u (numpy.ndarray (2, )): control input vector (u1, u2) - u1: steering angle velocity of front wheels - u2: longitudinal acceleration - - Returns: - f (numpy.ndarray): right hand side of differential equations + Parameters + ---------- + x : numpy.ndarray (7,) + Vehicle state vector (x1, x2, x3, x4, x5, x6, x7): + x1: x position in global coordinates, + x2: y position in global coordinates, + x3: steering angle of front wheels, + x4: velocity in x direction, + x5: yaw angle, + x6: yaw rate, + x7: slip angle at vehicle center. + u_init : numpy.ndarray (2,) + Control input vector (u1, u2): + u1: steering angle velocity of front wheels, + u2: longitudinal acceleration. + mu, C_Sf, C_Sr, lf, lr, h, m, I : float + Vehicle parameters. + s_min, s_max, sv_min, sv_max : float + Steering constraints. + v_switch, a_max, v_min, v_max : float + Velocity/acceleration constraints. + + Returns + ------- + f : numpy.ndarray + right hand side of differential equations + """ # gravity constant m/s^2 @@ -180,13 +224,20 @@ def pid(speed, steer, current_speed, current_steer, max_sv, max_a, max_v, min_v) """ Basic controller for speed/steer -> accl./steer vel. - Args: - speed (float): desired input speed - steer (float): desired input steering angle + Parameters + ---------- + speed : float + desired input speed + steer : float + desired input steering angle + + Returns + ------- + accl : float + desired input acceleration + sv : float + desired input steering velocity - Returns: - accl (float): desired input acceleration - sv (float): desired input steering velocity """ # steering steer_diff = steer - current_steer diff --git a/gym/f110_gym/envs/f110_env.py b/gym/f110_gym/envs/f110_env.py index 44553a73..ef7c5f79 100644 --- a/gym/f110_gym/envs/f110_env.py +++ b/gym/f110_gym/envs/f110_env.py @@ -56,41 +56,43 @@ class F110Env(gym.Env): Env should be initialized by calling gym.make('f110_gym:f110-v0', **kwargs) - Args: - kwargs: - seed (int, default=12345): seed for random state and reproducibility - - map (str, default='vegas'): name of the map used for the environment. Currently, available environments include: 'berlin', 'vegas', 'skirk'. You could use a string of the absolute path to the yaml file of your custom map. - - map_ext (str, default='png'): image extension of the map image file. For example 'png', 'pgm' - - params (dict, default={'mu': 1.0489, 'C_Sf':, 'C_Sr':, 'lf': 0.15875, 'lr': 0.17145, 'h': 0.074, 'm': 3.74, 'I': 0.04712, 's_min': -0.4189, 's_max': 0.4189, 'sv_min': -3.2, 'sv_max': 3.2, 'v_switch':7.319, 'a_max': 9.51, 'v_min':-5.0, 'v_max': 20.0, 'width': 0.31, 'length': 0.58}): dictionary of vehicle parameters. - mu: surface friction coefficient - C_Sf: Cornering stiffness coefficient, front - C_Sr: Cornering stiffness coefficient, rear - lf: Distance from center of gravity to front axle - lr: Distance from center of gravity to rear axle - h: Height of center of gravity - m: Total mass of the vehicle - I: Moment of inertial of the entire vehicle about the z axis - s_min: Minimum steering angle constraint - s_max: Maximum steering angle constraint - sv_min: Minimum steering velocity constraint - sv_max: Maximum steering velocity constraint - v_switch: Switching velocity (velocity at which the acceleration is no longer able to create wheel spin) - a_max: Maximum longitudinal acceleration - v_min: Minimum longitudinal velocity - v_max: Maximum longitudinal velocity - width: width of the vehicle in meters - length: length of the vehicle in meters - - num_agents (int, default=2): number of agents in the environment - - timestep (float, default=0.01): physics timestep - - ego_idx (int, default=0): ego's index in list of agents - - lidar_dist (float, default=0): vertical distance between LiDAR and backshaft + Parameters + ---------- + seed : int, default 12345 + seed for random state and reproducibility + map : str, default 'vegas' + name of the map used for the environment. Currently, available environments include: 'berlin', 'vegas', 'skirk'. You could use a string of the absolute path to the yaml file of your custom map. + map_ext : str, default 'png' + image extension of the map image file. For example 'png', 'pgm' + params : dict, default {'mu': 1.0489, 'C_Sf':, 'C_Sr':, 'lf': 0.15875, 'lr': 0.17145, 'h': 0.074, 'm': 3.74, 'I': 0.04712, 's_min': -0.4189, 's_max': 0.4189, 'sv_min': -3.2, 'sv_max': 3.2, 'v_switch':7.319, 'a_max': 9.51, 'v_min':-5.0, 'v_max': 20.0, 'width': 0.31, 'length': 0.58} + dictionary of vehicle parameters. + mu: surface friction coefficient + C_Sf: Cornering stiffness coefficient, front + C_Sr: Cornering stiffness coefficient, rear + lf: Distance from center of gravity to front axle + lr: Distance from center of gravity to rear axle + h: Height of center of gravity + m: Total mass of the vehicle + I: Moment of inertial of the entire vehicle about the z axis + s_min: Minimum steering angle constraint + s_max: Maximum steering angle constraint + sv_min: Minimum steering velocity constraint + sv_max: Maximum steering velocity constraint + v_switch: Switching velocity (velocity at which the acceleration is no longer able to create wheel spin) + a_max: Maximum longitudinal acceleration + v_min: Minimum longitudinal velocity + v_max: Maximum longitudinal velocity + width: width of the vehicle in meters + length: length of the vehicle in meters + num_agents : int, default 2 + number of agents in the environment + timestep : float, default 0.01 + physics timestep + ego_idx : int, default 0 + ego's index in list of agents + lidar_dist : float, default 0 + vertical distance between LiDAR and backshaft + """ metadata = {'render.modes': ['human', 'human_fast']} @@ -204,13 +206,14 @@ def __del__(self): def _check_done(self): """ Check if the current rollout is done - - Args: - None - Returns: - done (bool): whether the rollout is done - toggle_list (list[int]): each agent's toggle list for crossing the finish zone + Returns + ------- + done : bool + whether the rollout is done + toggle_list : list[int] + each agent's toggle list for crossing the finish zone + """ # this is assuming 2 agents @@ -248,12 +251,12 @@ def _check_done(self): def _update_state(self, obs_dict): """ Update the env's states according to observations - - Args: - obs_dict (dict): dictionary of observation - Returns: - None + Parameters + ---------- + obs_dict : dict + dictionary of observation + """ self.poses_x = obs_dict['poses_x'] self.poses_y = obs_dict['poses_y'] @@ -264,14 +267,23 @@ def step(self, action): """ Step function for the gym env - Args: - action (np.ndarray(num_agents, 2)) + Parameters + ---------- + action : np.ndarray (num_agents, 2) + Control input for each agent. First column is desired steering + angle, second column is desired velocity. + + Returns + ------- + obs : dict + observation of the current step + reward : float, default self.timestep + step reward, currently is physics timestep + done : bool + if the simulation is done + info : dict + auxillary information dictionary - Returns: - obs (dict): observation of the current step - reward (float, default=self.timestep): step reward, currently is physics timestep - done (bool): if the simulation is done - info (dict): auxillary information dictionary """ # call simulation step @@ -307,14 +319,22 @@ def reset(self, poses): """ Reset the gym environment by given poses - Args: - poses (np.ndarray (num_agents, 3)): poses to reset agents to + Parameters + ---------- + poses : np.ndarray (num_agents, 3) + Poses to reset agents to. Each row is [x, y, theta]. + + Returns + ------- + obs : dict + observation of the current step + reward : float, default self.timestep + step reward, currently is physics timestep + done : bool + if the simulation is done + info : dict + auxillary information dictionary - Returns: - obs (dict): observation of the current step - reward (float, default=self.timestep): step reward, currently is physics timestep - done (bool): if the simulation is done - info (dict): auxillary information dictionary """ # reset counters and data members self.current_time = 0.0 @@ -352,25 +372,27 @@ def update_map(self, map_path, map_ext): """ Updates the map used by simulation - Args: - map_path (str): absolute path to the map yaml file - map_ext (str): extension of the map image file + Parameters + ---------- + map_path : str + absolute path to the map yaml file + map_ext : str + extension of the map image file - Returns: - None """ self.sim.set_map(map_path, map_ext) def update_params(self, params, index=-1): """ Updates the parameters used by simulation for vehicles - - Args: - params (dict): dictionary of parameters - index (int, default=-1): if >= 0 then only update a specific agent's params - Returns: - None + Parameters + ---------- + params : dict + dictionary of parameters + index : int, default -1 + if >= 0 then only update a specific agent's params + """ self.sim.update_params(params, agent_idx=index) @@ -378,8 +400,12 @@ def add_render_callback(self, callback_func): """ Add extra drawing function to call during rendering. - Args: - callback_func (function (EnvRenderer) -> None): custom function to called during render() + Parameters + ---------- + callback_func : callable + Custom function to be called during render(). Takes an + EnvRenderer as argument. + """ F110Env.render_callbacks.append(callback_func) @@ -388,13 +414,13 @@ def render(self, mode='human'): """ Renders the environment with pyglet. Use mouse scroll in the window to zoom in/out, use mouse click drag to pan. Shows the agents, the map, current fps (bottom left corner), and the race information near as text. - Args: - mode (str, default='human'): rendering mode, currently supports: - 'human': slowed down rendering such that the env is rendered in a way that sim time elapsed is close to real time elapsed - 'human_fast': render as fast as possible + Parameters + ---------- + mode : str, default 'human' + rendering mode, currently supports: + 'human': slowed down rendering such that the env is rendered in a way that sim time elapsed is close to real time elapsed + 'human_fast': render as fast as possible - Returns: - None """ assert mode in ['human', 'human_fast'] diff --git a/gym/f110_gym/envs/laser_models.py b/gym/f110_gym/envs/laser_models.py index 158060b1..c9c43c28 100644 --- a/gym/f110_gym/envs/laser_models.py +++ b/gym/f110_gym/envs/laser_models.py @@ -42,12 +42,14 @@ def get_dt(bitmap, resolution): Distance transformation, returns the distance matrix from the input bitmap. Uses scipy.ndimage, cannot be JITted. - Args: - bitmap (numpy.ndarray, (n, m)): input binary bitmap of the environment, where 0 is obstacles, and 255 (or anything > 0) is freespace - resolution (float): resolution of the input bitmap (m/cell) + Parameters + ---------- + resolution : float + resolution of the input bitmap (m/cell) + + Returns + ------- - Returns: - dt (numpy.ndarray, (n, m)): output distance matrix, where each cell has the corresponding distance (in meters) to the closest obstacle """ dt = resolution * edt(bitmap) return dt @@ -57,15 +59,24 @@ def xy_2_rc(x, y, orig_x, orig_y, orig_c, orig_s, height, width, resolution): """ Translate (x, y) coordinate into (r, c) in the matrix - Args: - x (float): coordinate in x (m) - y (float): coordinate in y (m) - orig_x (float): x coordinate of the map origin (m) - orig_y (float): y coordinate of the map origin (m) - - Returns: - r (int): row number in the transform matrix of the given point - c (int): column number in the transform matrix of the given point + Parameters + ---------- + x : float + coordinate in x (m) + y : float + coordinate in y (m) + orig_x : float + x coordinate of the map origin (m) + orig_y : float + y coordinate of the map origin (m) + + Returns + ------- + r : int + row number in the transform matrix of the given point + c : int + column number in the transform matrix of the given point + """ # translation x_trans = x - orig_x @@ -90,14 +101,22 @@ def distance_transform(x, y, orig_x, orig_y, orig_c, orig_s, height, width, reso """ Look up corresponding distance in the distance matrix - Args: - x (float): x coordinate of the lookup point - y (float): y coordinate of the lookup point - orig_x (float): x coordinate of the map origin (m) - orig_y (float): y coordinate of the map origin (m) + Parameters + ---------- + x : float + x coordinate of the lookup point + y : float + y coordinate of the lookup point + orig_x : float + x coordinate of the map origin (m) + orig_y : float + y coordinate of the map origin (m) + + Returns + ------- + distance : float + corresponding shortest distance to obstacle in meters - Returns: - distance (float): corresponding shortest distance to obstacle in meters """ r, c = xy_2_rc(x, y, orig_x, orig_y, orig_c, orig_s, height, width, resolution) distance = dt[r, c] @@ -109,15 +128,22 @@ def trace_ray(x, y, theta_index, sines, cosines, eps, orig_x, orig_y, orig_c, or Find the length of a specific ray at a specific scan angle theta Purely math calculation and loops, should be JITted. - Args: - x (float): current x coordinate of the ego (scan) frame - y (float): current y coordinate of the ego (scan) frame - theta_index(int): current index of the scan beam in the scan range - sines (numpy.ndarray (n, )): pre-calculated sines of the angle array - cosines (numpy.ndarray (n, )): pre-calculated cosines ... + Parameters + ---------- + x : float + current x coordinate of the ego (scan) frame + y : float + current y coordinate of the ego (scan) frame + theta_index : int + current index of the scan beam in the scan range + sines (numpy.ndarray (n, )): pre-calculated sines of the angle array + cosines (numpy.ndarray (n, )): pre-calculated cosines ... + + Returns + ------- + total_distance : float + the distance to first obstacle on the current scan beam - Returns: - total_distance (float): the distance to first obstacle on the current scan beam """ # int casting, and index precal trigs @@ -150,15 +176,20 @@ def get_scan(pose, theta_dis, fov, num_beams, theta_index_increment, sines, cosi """ Perform the scan for each discretized angle of each beam of the laser, loop heavy, should be JITted - Args: - pose (numpy.ndarray(3, )): current pose of the scan frame in the map - theta_dis (int): number of steps to discretize the angles between 0 and 2pi for look up - fov (float): field of view of the laser scan - num_beams (int): number of beams in the scan - theta_index_increment (float): increment between angle indices after discretization + Parameters + ---------- + theta_dis : int + number of steps to discretize the angles between 0 and 2pi for look up + fov : float + field of view of the laser scan + num_beams : int + number of beams in the scan + theta_index_increment : float + increment between angle indices after discretization + + Returns + ------- - Returns: - scan (numpy.ndarray(n, )): resulting laser scan at the pose, n=num_beams """ # empty scan array init scan = np.empty((num_beams,)) @@ -190,17 +221,23 @@ def check_ttc_jit(scan, vel, scan_angles, cosines, side_distances, ttc_thresh): """ Checks the iTTC of each beam in a scan for collision with environment - Args: - scan (np.ndarray(num_beams, )): current scan to check - vel (float): current velocity + Parameters + ---------- + vel : float + current velocity scan_angles (np.ndarray(num_beams, )): precomped angles of each beam cosines (np.ndarray(num_beams, )): precomped cosines of the scan angles side_distances (np.ndarray(num_beams, )): precomped distances at each beam from the laser to the sides of the car - ttc_thresh (float): threshold for iTTC for collision + ttc_thresh : float + threshold for iTTC for collision + + Returns + ------- + in_collision : bool + whether vehicle is in collision with environment + collision_angle : float + at which angle the collision happened - Returns: - in_collision (bool): whether vehicle is in collision with environment - collision_angle (float): at which angle the collision happened """ in_collision = False if vel != 0.0: @@ -221,11 +258,18 @@ def cross(v1, v2): """ Cross product of two 2-vectors - Args: - v1, v2 (np.ndarray(2, )): input vectors + Parameters + ---------- + v1 : np.ndarray (2,) + First input vector. + v2 : np.ndarray (2,) + Second input vector. + + Returns + ------- + crossproduct : float + cross product - Returns: - crossproduct (float): cross product """ return v1[0]*v2[1]-v1[1]*v2[0] @@ -234,11 +278,20 @@ def are_collinear(pt_a, pt_b, pt_c): """ Checks if three points are collinear in 2D - Args: - pt_a, pt_b, pt_c (np.ndarray(2, )): points to check in 2D + Parameters + ---------- + pt_a : np.ndarray (2,) + First point. + pt_b : np.ndarray (2,) + Second point. + pt_c : np.ndarray (2,) + Third point. + + Returns + ------- + col : bool + whether three points are collinear - Returns: - col (bool): whether three points are collinear """ tol = 1e-8 ba = pt_b - pt_a @@ -251,13 +304,17 @@ def get_range(pose, beam_theta, va, vb): """ Get the distance at a beam angle to the vector formed by two of the four vertices of a vehicle - Args: - pose (np.ndarray(3, )): pose of the scanning vehicle - beam_theta (float): angle of the current beam (world frame) + Parameters + ---------- + beam_theta : float + angle of the current beam (world frame) va, vb (np.ndarray(2, )): the two vertices forming an edge - Returns: - distance (float): smallest distance at beam theta from scanning pose to edge + Returns + ------- + distance : float + smallest distance at beam theta from scanning pose to edge + """ o = pose[0:2] v1 = o - va @@ -284,10 +341,15 @@ def get_blocked_view_indices(pose, vertices, scan_angles): """ Get the indices of the start and end of blocked fov in scans by another vehicle - Args: - pose (np.ndarray(3, )): pose of the scanning vehicle - vertices (np.ndarray(4, 2)): four vertices of a vehicle pose - scan_angles (np.ndarray(num_beams, )): corresponding beam angles + Parameters + ---------- + pose : np.ndarray (3,) + Pose of the scanning vehicle. + vertices : np.ndarray (4, 2) + Four vertices of a vehicle pose. + scan_angles : np.ndarray (num_beams,) + Corresponding beam angles. + """ # find four vectors formed by pose and 4 vertices: vecs = vertices - pose[:2] @@ -320,14 +382,20 @@ def ray_cast(pose, scan, scan_angles, vertices): """ Modify a scan by ray casting onto another agent's four vertices - Args: - pose (np.ndarray(3, )): pose of the vehicle performing scan - scan (np.ndarray(num_beams, )): original scan to modify - scan_angles (np.ndarray(num_beams, )): corresponding beam angles - vertices (np.ndarray(4, 2)): four vertices of a vehicle pose - - Returns: - new_scan (np.ndarray(num_beams, )): modified scan + Parameters + ---------- + pose : np.ndarray (3,) + Pose of the vehicle performing scan. + scan : np.ndarray (num_beams,) + Original scan to modify. + scan_angles : np.ndarray (num_beams,) + Corresponding beam angles. + vertices : np.ndarray (4, 2) + Four vertices of a vehicle pose. + + Returns + ------- + """ # pad vertices so loops around looped_vertices = np.empty((5, 2)) @@ -349,12 +417,19 @@ class ScanSimulator2D(object): """ 2D LIDAR scan simulator class - Init params: - num_beams (int): number of beams in the scan - fov (float): field of view of the laser scan - eps (float, default=0.0001): ray tracing iteration termination condition - theta_dis (int, default=2000): number of steps to discretize the angles between 0 and 2pi for look up - max_range (float, default=30.0): maximum range of the laser + Parameters + ---------- + num_beams : int + number of beams in the scan + fov : float + field of view of the laser scan + eps : float, default 0.0001 + ray tracing iteration termination condition + theta_dis : int, default 2000 + number of steps to discretize the angles between 0 and 2pi for look up + max_range : float, default 30.0 + maximum range of the laser + """ def __init__(self, num_beams, fov, eps=0.0001, theta_dis=2000, max_range=30.0): @@ -384,12 +459,18 @@ def set_map(self, map_path, map_ext): """ Set the bitmap of the scan simulator by path - Args: - map_path (str): path to the map yaml file - map_ext (str): extension (image type) of the map image + Parameters + ---------- + map_path : str + path to the map yaml file + map_ext : str + extension (image type) of the map image + + Returns + ------- + flag : bool + if image reading and loading is successful - Returns: - flag (bool): if image reading and loading is successful """ # TODO: do we open the option to flip the images, and turn rgb into grayscale? or specify the exact requirements in documentation. # TODO: throw error if image specification isn't met @@ -430,16 +511,21 @@ def scan(self, pose, rng, std_dev=0.01): """ Perform simulated 2D scan by pose on the given map - Args: - pose (numpy.ndarray (3, )): pose of the scan frame (x, y, theta) - rng (numpy.random.Generator): random number generator to use for whitenoise in scan, or None - std_dev (float, default=0.01): standard deviation of the generated whitenoise in the scan + Parameters + ---------- + rng : numpy.random.Generator + random number generator to use for whitenoise in scan, or None + std_dev : float, default 0.01 + standard deviation of the generated whitenoise in the scan + + Returns + ------- - Returns: - scan (numpy.ndarray (n, )): data array of the laserscan, n=num_beams + Raises + ------ + ValueError + when scan is called before a map is set - Raises: - ValueError: when scan is called before a map is set """ if self.map_height is None: diff --git a/gym/f110_gym/envs/rendering.py b/gym/f110_gym/envs/rendering.py index 8d8ba1ae..8b886ef5 100644 --- a/gym/f110_gym/envs/rendering.py +++ b/gym/f110_gym/envs/rendering.py @@ -55,12 +55,13 @@ def __init__(self, width, height, *args, **kwargs): """ Class constructor - Args: - width (int): width of the window - height (int): height of the window + Parameters + ---------- + width : int + width of the window + height : int + height of the window - Returns: - None """ conf = Config(sample_buffers=1, samples=4, @@ -112,12 +113,13 @@ def update_map(self, map_path, map_ext): """ Update the map being drawn by the renderer. Converts image to a list of 3D points representing each obstacle pixel in the map. - Args: - map_path (str): absolute path to the map without extensions - map_ext (str): extension for the map image file + Parameters + ---------- + map_path : str + absolute path to the map without extensions + map_ext : str + extension for the map image file - Returns: - None """ # load map metadata @@ -159,12 +161,13 @@ def on_resize(self, width, height): Potential improvements on current behavior: zoom/pan resets on window resize. - Args: - width (int): new width of window - height (int): new height of window + Parameters + ---------- + width : int + new width of window + height : int + new height of window - Returns: - None """ # call overrided function @@ -183,16 +186,21 @@ def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): """ Callback function on mouse drag, overrides inherited method. - Args: - x (int): Distance in pixels from the left edge of the window. - y (int): Distance in pixels from the bottom edge of the window. - dx (int): Relative X position from the previous mouse position. - dy (int): Relative Y position from the previous mouse position. - buttons (int): Bitwise combination of the mouse buttons currently pressed. - modifiers (int): Bitwise combination of any keyboard modifiers currently active. + Parameters + ---------- + x : int + Distance in pixels from the left edge of the window. + y : int + Distance in pixels from the bottom edge of the window. + dx : int + Relative X position from the previous mouse position. + dy : int + Relative Y position from the previous mouse position. + buttons : int + Bitwise combination of the mouse buttons currently pressed. + modifiers : int + Bitwise combination of any keyboard modifiers currently active. - Returns: - None """ # pan camera @@ -205,14 +213,17 @@ def on_mouse_scroll(self, x, y, dx, dy): """ Callback function on mouse scroll, overrides inherited method. - Args: - x (int): Distance in pixels from the left edge of the window. - y (int): Distance in pixels from the bottom edge of the window. - scroll_x (float): Amount of movement on the horizontal axis. - scroll_y (float): Amount of movement on the vertical axis. + Parameters + ---------- + x : int + Distance in pixels from the left edge of the window. + y : int + Distance in pixels from the bottom edge of the window. + scroll_x : float + Amount of movement on the horizontal axis. + scroll_y : float + Amount of movement on the vertical axis. - Returns: - None """ # Get scale factor @@ -243,14 +254,11 @@ def on_close(self): """ Callback function when the 'x' is clicked on the window, overrides inherited method. Also throws exception to end the python program when in a loop. - Args: - None + Raises + ------ + Exception + with a message that indicates the rendering window was closed - Returns: - None - - Raises: - Exception: with a message that indicates the rendering window was closed """ super().on_close() @@ -259,12 +267,7 @@ def on_close(self): def on_draw(self): """ Function when the pyglet is drawing. The function draws the batch created that includes the map points, the agent polygons, and the information text, and the fps display. - - Args: - None - Returns: - None """ # if map and poses doesn't exist, raise exception @@ -299,11 +302,11 @@ def update_obs(self, obs): """ Updates the renderer with the latest observation from the gym environment, including the agent poses, and the information text. - Args: - obs (dict): observation dict from the gym env + Parameters + ---------- + obs : dict + observation dict from the gym env - Returns: - None """ self.ego_idx = obs['ego_idx']