#!/usr/bin/env python # Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma de # Barcelona (UAB). # # This work is licensed under the terms of the MIT license. # For a copy, see . # # Modified for DBC paper. import random import glob import os import sys import time from PIL import Image from PIL.PngImagePlugin import PngImageFile, PngInfo try: sys.path.append(glob.glob('../carla/dist/carla-*%d.%d-%s.egg' % ( sys.version_info.major, sys.version_info.minor, 'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0]) except IndexError: pass import carla import math from dotmap import DotMap try: import pygame except ImportError: raise RuntimeError('cannot import pygame, make sure pygame package is installed') try: import numpy as np except ImportError: raise RuntimeError('cannot import numpy, make sure numpy package is installed') try: import queue except ImportError: import Queue as queue from agents.navigation.agent import Agent, AgentState from agents.navigation.local_planner import LocalPlanner class CarlaSyncMode(object): """ Context manager to synchronize output from different sensors. Synchronous mode is enabled as long as we are inside this context with CarlaSyncMode(world, sensors) as sync_mode: while True: data = sync_mode.tick(timeout=1.0) """ def __init__(self, world, *sensors, **kwargs): self.world = world self.sensors = sensors self.frame = None self.delta_seconds = 1.0 / kwargs.get('fps', 20) self._queues = [] self._settings = None self.start() def start(self): self._settings = self.world.get_settings() self.frame = self.world.apply_settings(carla.WorldSettings( no_rendering_mode=False, synchronous_mode=True, fixed_delta_seconds=self.delta_seconds)) def make_queue(register_event): q = queue.Queue() register_event(q.put) self._queues.append(q) make_queue(self.world.on_tick) for sensor in self.sensors: make_queue(sensor.listen) def tick(self, timeout): self.frame = self.world.tick() data = [self._retrieve_data(q, timeout) for q in self._queues] assert all(x.frame == self.frame for x in data) return data def __exit__(self, *args, **kwargs): self.world.apply_settings(self._settings) def _retrieve_data(self, sensor_queue, timeout): while True: data = sensor_queue.get(timeout=timeout) if data.frame == self.frame: return data def draw_image(surface, image, blend=False): array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8")) array = np.reshape(array, (image.height, image.width, 4)) array = array[:, :, :3] array = array[:, :, ::-1] image_surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) if blend: image_surface.set_alpha(100) surface.blit(image_surface, (0, 0)) def get_font(): fonts = [x for x in pygame.font.get_fonts()] default_font = 'ubuntumono' font = default_font if default_font in fonts else fonts[0] font = pygame.font.match_font(font) return pygame.font.Font(font, 14) def should_quit(): for event in pygame.event.get(): if event.type == pygame.QUIT: return True elif event.type == pygame.KEYUP: if event.key == pygame.K_ESCAPE: return True return False def clamp(value, minimum=0.0, maximum=100.0): return max(minimum, min(value, maximum)) class Sun(object): def __init__(self, azimuth, altitude): self.azimuth = azimuth self.altitude = altitude self._t = 0.0 def tick(self, delta_seconds): self._t += 0.008 * delta_seconds self._t %= 2.0 * math.pi self.azimuth += 0.25 * delta_seconds self.azimuth %= 360.0 # self.altitude = (70 * math.sin(self._t)) - 20 # [50, -90] min_alt, max_alt = [20, 90] self.altitude = 0.5 * (max_alt + min_alt) + 0.5 * (max_alt - min_alt) * math.cos(self._t) def __str__(self): return 'Sun(alt: %.2f, azm: %.2f)' % (self.altitude, self.azimuth) class Storm(object): def __init__(self, precipitation): self._t = precipitation if precipitation > 0.0 else -50.0 self._increasing = True self.clouds = 0.0 self.rain = 0.0 self.wetness = 0.0 self.puddles = 0.0 self.wind = 0.0 self.fog = 0.0 def tick(self, delta_seconds): delta = (1.3 if self._increasing else -1.3) * delta_seconds self._t = clamp(delta + self._t, -250.0, 100.0) self.clouds = clamp(self._t + 40.0, 0.0, 60.0) self.rain = clamp(self._t, 0.0, 80.0) self.wind = 5.0 if self.clouds <= 20 else 90 if self.clouds >= 70 else 40 if self._t == -250.0: self._increasing = True if self._t == 100.0: self._increasing = False def __str__(self): return 'Storm(clouds=%d%%, rain=%d%%, wind=%d%%)' % (self.clouds, self.rain, self.wind) class Weather(object): def __init__(self, world, changing_weather_speed): self.world = world self.reset() self.weather = world.get_weather() self.changing_weather_speed = changing_weather_speed self._sun = Sun(self.weather.sun_azimuth_angle, self.weather.sun_altitude_angle) self._storm = Storm(self.weather.precipitation) def reset(self): weather_params = carla.WeatherParameters(sun_altitude_angle=90.) self.world.set_weather(weather_params) def tick(self): self._sun.tick(self.changing_weather_speed) self._storm.tick(self.changing_weather_speed) self.weather.cloudiness = self._storm.clouds self.weather.precipitation = self._storm.rain self.weather.precipitation_deposits = self._storm.puddles self.weather.wind_intensity = self._storm.wind self.weather.fog_density = self._storm.fog self.weather.wetness = self._storm.wetness self.weather.sun_azimuth_angle = self._sun.azimuth self.weather.sun_altitude_angle = self._sun.altitude self.world.set_weather(self.weather) def __str__(self): return '%s %s' % (self._sun, self._storm) class CarlaEnv(object): def __init__(self, render_display=0, # 0, 1 record_display_images=0, # 0, 1 record_rl_images=0, # 0, 1 changing_weather_speed=0.0, # [0, +inf) display_text=0, # 0, 1 rl_image_size=84, max_episode_steps=1000, frame_skip=1, is_other_cars=True, start_lane=None, fov=60, # degrees for rl camera num_cameras=5, port=2000 ): if record_display_images: assert render_display self.render_display = render_display self.save_display_images = record_display_images self.save_rl_images = record_rl_images self.changing_weather_speed = changing_weather_speed self.display_text = display_text self.rl_image_size = rl_image_size self._max_episode_steps = max_episode_steps # DMC uses this self.frame_skip = frame_skip self.is_other_cars = is_other_cars self.start_lane = start_lane self.num_cameras = num_cameras self.actor_list = [] if self.render_display: pygame.init() self.display = pygame.display.set_mode((800, 600), pygame.HWSURFACE | pygame.DOUBLEBUF) self.font = get_font() self.clock = pygame.time.Clock() self.client = carla.Client('localhost', port) self.client.set_timeout(5.0) self.world = self.client.load_world("Town04") self.map = self.world.get_map() assert self.map.name == "Town04" # remove old vehicles and sensors (in case they survived) self.world.tick() actor_list = self.world.get_actors() for vehicle in actor_list.filter("*vehicle*"): # if vehicle.id != self.vehicle.id: print("Warning: removing old vehicle") vehicle.destroy() for sensor in actor_list.filter("*sensor*"): print("Warning: removing old sensor") sensor.destroy() self.vehicle = None self.vehicle_start_pose = None self.vehicles_list = [] # their ids self.vehicles = None self.reset_vehicle() # creates self.vehicle self.actor_list.append(self.vehicle) blueprint_library = self.world.get_blueprint_library() if render_display: self.camera_rgb = self.world.spawn_actor( blueprint_library.find('sensor.camera.rgb'), carla.Transform(carla.Location(x=-5.5, z=2.8), carla.Rotation(pitch=-15)), attach_to=self.vehicle) self.actor_list.append(self.camera_rgb) # we'll use up to five cameras, which we'll stitch together bp = blueprint_library.find('sensor.camera.rgb') bp.set_attribute('image_size_x', str(self.rl_image_size)) bp.set_attribute('image_size_y', str(self.rl_image_size)) bp.set_attribute('fov', str(fov)) location = carla.Location(x=1.6, z=1.7) self.camera_rl = self.world.spawn_actor(bp, carla.Transform(location, carla.Rotation(yaw=0.0)), attach_to=self.vehicle) self.camera_rl_left = self.world.spawn_actor(bp, carla.Transform(location, carla.Rotation(yaw=-float(fov))), attach_to=self.vehicle) self.camera_rl_lefter = self.world.spawn_actor(bp, carla.Transform(location, carla.Rotation(yaw=-2*float(fov))), attach_to=self.vehicle) self.camera_rl_right = self.world.spawn_actor(bp, carla.Transform(location, carla.Rotation(yaw=float(fov))), attach_to=self.vehicle) self.camera_rl_righter = self.world.spawn_actor(bp, carla.Transform(location, carla.Rotation(yaw=2*float(fov))), attach_to=self.vehicle) self.actor_list.append(self.camera_rl) self.actor_list.append(self.camera_rl_left) self.actor_list.append(self.camera_rl_lefter) self.actor_list.append(self.camera_rl_right) self.actor_list.append(self.camera_rl_righter) bp = self.world.get_blueprint_library().find('sensor.other.collision') self.collision_sensor = self.world.spawn_actor(bp, carla.Transform(), attach_to=self.vehicle) self.collision_sensor.listen(lambda event: self._on_collision(event)) self.actor_list.append(self.collision_sensor) self._collision_intensities_during_last_time_step = [] if self.save_display_images or self.save_rl_images: import datetime now = datetime.datetime.now() image_dir = "images-" + now.strftime("%Y-%m-%d-%H-%M-%S") os.mkdir(image_dir) self.image_dir = image_dir if self.render_display: self.sync_mode = CarlaSyncMode(self.world, self.camera_rgb, self.camera_rl, self.camera_rl_left, self.camera_rl_lefter, self.camera_rl_right, self.camera_rl_righter, fps=20) else: self.sync_mode = CarlaSyncMode(self.world, self.camera_rl, self.camera_rl_left, self.camera_rl_lefter, self.camera_rl_right, self.camera_rl_righter, fps=20) # weather self.weather = Weather(self.world, self.changing_weather_speed) # dummy variables given bisim's assumption on deep-mind-control suite APIs low = -1.0 high = 1.0 self.action_space = DotMap() self.action_space.low.min = lambda: low self.action_space.high.max = lambda: high self.action_space.shape = [2] self.observation_space = DotMap() self.observation_space.shape = (3, rl_image_size, num_cameras * rl_image_size) self.observation_space.dtype = np.dtype(np.uint8) self.reward_range = None self.metadata = None self.action_space.sample = lambda: np.random.uniform(low=low, high=high, size=self.action_space.shape[0]).astype(np.float32) # roaming carla agent self.agent = None self.count = 0 self.dist_s = 0 self.return_ = 0 self.velocities = [] self.world.tick() self.reset() # creates self.agent def dist_from_center_lane(self, vehicle, info): # assume on highway vehicle_location = vehicle.get_location() vehicle_waypoint = self.map.get_waypoint(vehicle_location) vehicle_velocity = vehicle.get_velocity() # Vecor3D vehicle_velocity_xy = np.array([vehicle_velocity.x, vehicle_velocity.y]) speed = np.linalg.norm(vehicle_velocity_xy) vehicle_waypoint_closest_to_road = \ self.map.get_waypoint(vehicle_location, project_to_road=True, lane_type=carla.LaneType.Driving) road_id = vehicle_waypoint_closest_to_road.road_id assert road_id is not None lane_id_sign = int(np.sign(vehicle_waypoint_closest_to_road.lane_id)) assert lane_id_sign in [-1, 1] current_waypoint = self.map.get_waypoint(vehicle_location, project_to_road=False) if current_waypoint is None: print("Episode fail: current waypoint is off the road! (frame %d)" % self.count) info['reason_episode_ended'] = 'off_road' done, dist, vel_s = True, 100., 0. return dist, vel_s, speed, done, info goal_waypoint = current_waypoint.next(5.)[0] if goal_waypoint is None: print("Episode fail: goal waypoint is off the road! (frame %d)" % self.count) info['reason_episode_ended'] = 'off_road' done, dist, vel_s = True, 100., 0. else: goal_location = goal_waypoint.transform.location goal_xy = np.array([goal_location.x, goal_location.y]) dist = 0. next_goal_waypoint = goal_waypoint.next(0.1) # waypoints are ever 0.02 meters if len(next_goal_waypoint) != 1: print('warning: {} waypoints (not 1)'.format(len(next_goal_waypoint))) if len(next_goal_waypoint) == 0: print("Episode done: no more waypoints left. (frame %d)" % self.count) info['reason_episode_ended'] = 'no_waypoints' done, vel_s = True, 0. else: location_ahead = next_goal_waypoint[0].transform.location highway_vector = np.array([location_ahead.x, location_ahead.y]) - goal_xy highway_unit_vector = np.array(highway_vector) / np.linalg.norm(highway_vector) vel_s = np.dot(vehicle_velocity_xy, highway_unit_vector) done = False # not algorithm's fault, but the simulator sometimes throws the car in the air wierdly if vehicle_velocity.z > 1. and self.count < 20: print("Episode done: vertical velocity too high ({}), usually a simulator glitch (frame {})".format(vehicle_velocity.z, self.count)) info['reason_episode_ended'] = 'carla_bug' done = True if vehicle_location.z > 0.5 and self.count < 20: print("Episode done: vertical velocity too high ({}), usually a simulator glitch (frame {})".format(vehicle_location.z, self.count)) info['reason_episode_ended'] = 'carla_bug' done = True return dist, vel_s, speed, done, info def _on_collision(self, event): impulse = event.normal_impulse intensity = math.sqrt(impulse.x ** 2 + impulse.y ** 2 + impulse.z ** 2) print('Collision (intensity {})'.format(intensity)) self._collision_intensities_during_last_time_step.append(intensity) def reset(self): self.reset_vehicle() self.world.tick() self.reset_other_vehicles() self.world.tick() self.agent = RoamingAgentModified(self.vehicle, follow_traffic_lights=False) self.count = 0 self.dist_s = 0 self.return_ = 0 self.velocities = [] # get obs: obs, _, _, _ = self.step(action=None) return obs def reset_vehicle(self): start_lane = self.start_lane if self.start_lane is not None else np.random.choice([1, 2, 3, 4]) start_x = 1.5 + 3.5 * start_lane # 3.5 = lane width self.vehicle_start_pose = carla.Transform(carla.Location(x=start_x, y=0, z=0.1), carla.Rotation(yaw=-90)) if self.vehicle is None: # create vehicle blueprint_library = self.world.get_blueprint_library() vehicle_blueprint = blueprint_library.find('vehicle.audi.a2') self.vehicle = self.world.spawn_actor(vehicle_blueprint, self.vehicle_start_pose) else: self.vehicle.set_transform(self.vehicle_start_pose) self.vehicle.set_velocity(carla.Vector3D()) self.vehicle.set_angular_velocity(carla.Vector3D()) def reset_other_vehicles(self): if not self.is_other_cars: return # clear out old vehicles self.client.apply_batch([carla.command.DestroyActor(x) for x in self.vehicles_list]) self.world.tick() self.vehicles_list = [] blueprints = self.world.get_blueprint_library().filter('vehicle.*') blueprints = [x for x in blueprints if int(x.get_attribute('number_of_wheels')) == 4] num_vehicles = 10 other_car_transforms = [] for _ in range(num_vehicles): lane_id = random.choice([1, 2, 3, 4]) start_x = 1.5 + 3.5 * lane_id start_y = random.uniform(-40., 40.) transform = carla.Transform(carla.Location(x=start_x, y=start_y, z=0.1), carla.Rotation(yaw=-90)) other_car_transforms.append(transform) # Spawn vehicles batch = [] for n, transform in enumerate(other_car_transforms): blueprint = random.choice(blueprints) if blueprint.has_attribute('color'): color = random.choice(blueprint.get_attribute('color').recommended_values) blueprint.set_attribute('color', color) if blueprint.has_attribute('driver_id'): driver_id = random.choice(blueprint.get_attribute('driver_id').recommended_values) blueprint.set_attribute('driver_id', driver_id) blueprint.set_attribute('role_name', 'autopilot') batch.append(carla.command.SpawnActor(blueprint, transform).then( carla.command.SetAutopilot(carla.command.FutureActor, True))) for response in self.client.apply_batch_sync(batch, False): self.vehicles_list.append(response.actor_id) for response in self.client.apply_batch_sync(batch): if response.error: pass # print(response.error) else: self.vehicles_list.append(response.actor_id) def compute_steer_action(self): control = self.agent.run_step() # PID decides control.steer steer = control.steer throttle = control.throttle brake = control.brake throttle_brake = -brake if throttle > 0.: throttle_brake = throttle steer_action = np.array([steer, throttle_brake], dtype=np.float32) return steer_action def step(self, action): rewards = [] for _ in range(self.frame_skip): # default 1 next_obs, reward, done, info = self._simulator_step(action) rewards.append(reward) if done: break return next_obs, np.mean(rewards), done, info # just last info? def _simulator_step(self, action, dt=0.05): if self.render_display: if should_quit(): return self.clock.tick() if action is not None: steer = float(action[0]) throttle_brake = float(action[1]) if throttle_brake >= 0.0: throttle = throttle_brake brake = 0.0 else: throttle = 0.0 brake = -throttle_brake assert 0.0 <= throttle <= 1.0 assert -1.0 <= steer <= 1.0 assert 0.0 <= brake <= 1.0 vehicle_control = carla.VehicleControl( throttle=throttle, steer=steer, brake=brake, hand_brake=False, reverse=False, manual_gear_shift=False ) self.vehicle.apply_control(vehicle_control) else: throttle, steer, brake = 0., 0., 0. # Advance the simulation and wait for the data. if self.render_display: snapshot, image_rgb, image_rl, image_rl_left, image_rl_lefter, image_rl_right, image_rl_righter = self.sync_mode.tick(timeout=2.0) else: snapshot, image_rl, image_rl_left, image_rl_lefter, image_rl_right, image_rl_righter = self.sync_mode.tick(timeout=2.0) info = {} info['reason_episode_ended'] = '' dist_from_center, vel_s, speed, done, info = self.dist_from_center_lane(self.vehicle, info) collision_intensities_during_last_time_step = sum(self._collision_intensities_during_last_time_step) self._collision_intensities_during_last_time_step.clear() # clear it ready for next time step assert collision_intensities_during_last_time_step >= 0. collision_cost = 0.0001 * collision_intensities_during_last_time_step vel_t = math.sqrt(speed**2 - vel_s**2) reward = vel_s * dt - collision_cost - abs(steer) # doesn't work if 0.001 cost collisions info['crash_intensity'] = collision_intensities_during_last_time_step info['steer'] = steer info['brake'] = brake info['distance'] = vel_s * dt self.dist_s += vel_s * dt self.return_ += reward self.weather.tick() # Draw the display. if self.render_display: draw_image(self.display, image_rgb) if self.display_text: self.display.blit(self.font.render('frame %d' % self.count, True, (255, 255, 255)), (8, 10)) self.display.blit(self.font.render('highway progression %4.1f m/s (%5.1f m) (%5.2f speed)' % (vel_s, self.dist_s, speed), True, (255, 255, 255)), (8, 28)) self.display.blit(self.font.render('%5.2f meters off center' % dist_from_center, True, (255, 255, 255)), (8, 46)) self.display.blit(self.font.render('%5.2f reward (return %.2f)' % (reward, self.return_), True, (255, 255, 255)), (8, 64)) self.display.blit(self.font.render('%5.2f collision intensity ' % collision_intensities_during_last_time_step, True, (255, 255, 255)), (8, 82)) self.display.blit(self.font.render('%5.2f thottle, %3.2f steer, %3.2f brake' % (throttle, steer, brake), True, (255, 255, 255)), (8, 100)) self.display.blit(self.font.render(str(self.weather), True, (255, 255, 255)), (8, 118)) pygame.display.flip() rgbs = [] if self.num_cameras == 1: ims = [image_rl] elif self.num_cameras == 3: ims = [image_rl_left, image_rl, image_rl_right] elif self.num_cameras == 5: ims = [image_rl_lefter, image_rl_left, image_rl, image_rl_right, image_rl_righter] else: raise ValueError("num cameras must be 1 or 3 or 5") for im in ims: bgra = np.array(im.raw_data).reshape(self.rl_image_size, self.rl_image_size, 4) # BGRA format bgr = bgra[:, :, :3] # BGR format (84 x 84 x 3) rgb = np.flip(bgr, axis=2) # RGB format (84 x 84 x 3) rgbs.append(rgb) rgb = np.concatenate(rgbs, axis=1) # (84 x 252 x 3) # Rowan added if self.render_display and self.save_display_images: image_name = os.path.join(self.image_dir, "display%08d.jpg" % self.count) pygame.image.save(self.display, image_name) # ffmpeg -r 20 -pattern_type glob -i 'display*.jpg' carla.mp4 if self.save_rl_images: image_name = os.path.join(self.image_dir, "rl%08d.png" % self.count) im = Image.fromarray(rgb) metadata = PngInfo() metadata.add_text("throttle", str(throttle)) metadata.add_text("steer", str(steer)) metadata.add_text("brake", str(brake)) im.save(image_name, "PNG", pnginfo=metadata) # # Example usage: # from PIL.PngImagePlugin import PngImageFile # im = PngImageFile("rl00001234.png") # # Actions are stored in the image's metadata: # print("Actions: %s" % im.text) # throttle = float(im.text['throttle']) # range [0, 1] # steer = float(im.text['steer']) # range [-1, 1] # brake = float(im.text['brake']) # range [0, 1] self.count += 1 next_obs = rgb # (84 x 252 x 3) or (84 x 420 x 3) # debugging - to inspect images: # import matplotlib.pyplot as plt # import pdb; pdb.set_trace() # plt.imshow(next_obs) # plt.show() next_obs = np.transpose(next_obs, [2, 0, 1]) # 3 x 84 x 84/252/420 assert next_obs.shape == self.observation_space.shape if self.count >= self._max_episode_steps: print("Episode success: I've reached the episode horizon ({}).".format(self._max_episode_steps)) info['reason_episode_ended'] = 'success' done = True if speed < 0.02 and self.count >= 100 and self.count % 100 == 0: # a hack, instead of a counter print("Episode fail: speed too small ({}), think I'm stuck! (frame {})".format(speed, self.count)) info['reason_episode_ended'] = 'stuck' done = True return next_obs, reward, done, info def finish(self): print('destroying actors.') for actor in self.actor_list: actor.destroy() print('\ndestroying %d vehicles' % len(self.vehicles_list)) self.client.apply_batch([carla.command.DestroyActor(x) for x in self.vehicles_list]) time.sleep(0.5) pygame.quit() print('done.') class LocalPlannerModified(LocalPlanner): def __del__(self): pass # otherwise it deletes our vehicle object def run_step(self): return super().run_step(debug=False) # otherwise by default shows waypoints, that interfere with our camera class RoamingAgentModified(Agent): """ RoamingAgent implements a basic agent that navigates scenes making random choices when facing an intersection. This agent respects traffic lights and other vehicles. """ def __init__(self, vehicle, follow_traffic_lights=True): """ :param vehicle: actor to apply to local planner logic onto """ super(RoamingAgentModified, self).__init__(vehicle) self._proximity_threshold = 10.0 # meters self._state = AgentState.NAVIGATING self._follow_traffic_lights = follow_traffic_lights # for throttle 0.5, 0.75, 1.0 args_lateral_dict = { 'K_P': 1.0, 'K_D': 0.005, 'K_I': 0.0, 'dt': 1.0 / 20.0} opt_dict = {'lateral_control_dict': args_lateral_dict} self._local_planner = LocalPlannerModified(self._vehicle, opt_dict) def run_step(self, debug=False): """ Execute one step of navigation. :return: carla.VehicleControl """ # is there an obstacle in front of us? hazard_detected = False # retrieve relevant elements for safe navigation, i.e.: traffic lights # and other vehicles actor_list = self._world.get_actors() vehicle_list = actor_list.filter("*vehicle*") lights_list = actor_list.filter("*traffic_light*") # check possible obstacles vehicle_state, vehicle = self._is_vehicle_hazard(vehicle_list) if vehicle_state: if debug: print('!!! VEHICLE BLOCKING AHEAD [{}])'.format(vehicle.id)) self._state = AgentState.BLOCKED_BY_VEHICLE hazard_detected = True # check for the state of the traffic lights light_state, traffic_light = self._is_light_red(lights_list) if light_state and self._follow_traffic_lights: if debug: print('=== RED LIGHT AHEAD [{}])'.format(traffic_light.id)) self._state = AgentState.BLOCKED_RED_LIGHT hazard_detected = True if hazard_detected: control = self.emergency_stop() else: self._state = AgentState.NAVIGATING # standard local planner behavior control = self._local_planner.run_step() return control if __name__ == '__main__': env = CarlaEnv( render_display=1, # 0, 1 record_display_images=0, # 0, 1 record_rl_images=1, # 0, 1 changing_weather_speed=1.0, # [0, +inf) display_text=1, # 0, 1 is_other_cars=True, frame_skip=4, max_episode_steps=100000, rl_image_size=84, start_lane=1, ) try: done = False while not done: action = env.compute_steer_action() next_obs, reward, done, info = env.step(action) obs = env.reset() finally: env.finish()