mirror of
https://github.com/wassname/ray.git
synced 2026-06-27 20:53:14 +08:00
[carla] In carla example, save all images and measurements to local disk (#1350)
* revamp saving * smaller jpgs * hide verbose * Tue Dec 19 22:25:01 PST 2017 * make sure temp dirs sort lexiographically * save total reward too * zero pad i * 160x160 dqn * ever higher res dqn
This commit is contained in:
committed by
Philipp Moritz
parent
3a301c3d56
commit
0ae660ce4e
+147
-54
@@ -2,7 +2,10 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from datetime import datetime
|
||||
import cv2
|
||||
import os
|
||||
import json
|
||||
import random
|
||||
import signal
|
||||
import subprocess
|
||||
@@ -23,26 +26,37 @@ import gym
|
||||
from gym.spaces import Box, Discrete
|
||||
|
||||
|
||||
RETRIES_ON_ERROR = 5
|
||||
IMAGE_OUT_PATH = os.environ.get("CARLA_OUT")
|
||||
# Set this where you want to save image outputs (or empty string to disable)
|
||||
CARLA_OUT_PATH = os.environ.get("CARLA_OUT", os.path.expanduser("~/carla_out"))
|
||||
if CARLA_OUT_PATH and not os.path.exists(CARLA_OUT_PATH):
|
||||
os.makedirs(CARLA_OUT_PATH)
|
||||
|
||||
# Set this to the path of your Carla binary
|
||||
SERVER_BINARY = os.environ.get(
|
||||
"CARLA_SERVER", "/home/ubuntu/carla-0.7/CarlaUE4.sh")
|
||||
|
||||
# Number of retries if the server doesn't respond
|
||||
RETRIES_ON_ERROR = 5
|
||||
|
||||
# Default environment configuration
|
||||
ENV_CONFIG = {
|
||||
"verbose": True,
|
||||
"render_x_res": 400,
|
||||
"render_y_res": 300,
|
||||
"x_res": 80,
|
||||
"y_res": 80,
|
||||
"map": "/Game/Maps/Town02",
|
||||
"random_starting_location": False,
|
||||
"use_depth_camera": True,
|
||||
"use_depth_camera": False,
|
||||
"discrete_actions": False,
|
||||
"max_steps": 150,
|
||||
"max_steps": 50,
|
||||
"num_vehicles": 20,
|
||||
"num_pedestrians": 40,
|
||||
"weather": [1], # [1, 3, 7, 8, 14]
|
||||
|
||||
# Defaults to driving down the road /Game/Maps/Town02, start pos 0
|
||||
"target_x": -7.5,
|
||||
"target_y": 300,
|
||||
"target_y": 120,
|
||||
}
|
||||
|
||||
|
||||
@@ -57,10 +71,10 @@ class CarlaEnv(gym.Env):
|
||||
self.action_space = Box(-1.0, 1.0, shape=(3,))
|
||||
if config["use_depth_camera"]:
|
||||
self.observation_space = Box(
|
||||
-1.0, 1.0, shape=(config["x_res"], config["y_res"], 1))
|
||||
-1.0, 1.0, shape=(config["y_res"], config["x_res"], 1))
|
||||
else:
|
||||
self.observation_space = Box(
|
||||
0.0, 255.0, shape=(config["x_res"], config["y_res"], 3))
|
||||
0.0, 255.0, shape=(config["y_res"], config["x_res"], 3))
|
||||
self._spec = lambda: None
|
||||
self._spec.id = "Carla-v0"
|
||||
|
||||
@@ -68,14 +82,19 @@ class CarlaEnv(gym.Env):
|
||||
self.server_process = None
|
||||
self.client = None
|
||||
self.num_steps = 0
|
||||
self.total_reward = 0
|
||||
self.prev_measurement = None
|
||||
self.episode_id = None
|
||||
self.measurements_file = None
|
||||
self.weather = None
|
||||
self.player_start = None
|
||||
|
||||
def init_server(self):
|
||||
print("Initializing new Carla server...")
|
||||
# Create a new server process and start the client.
|
||||
self.server_port = random.randint(10000, 60000)
|
||||
self.server_process = subprocess.Popen(
|
||||
[SERVER_BINARY, "/Game/Maps/Town02",
|
||||
[SERVER_BINARY, self.config["map"],
|
||||
"-windowed", "-ResX=400", "-ResY=300",
|
||||
"-carla-server",
|
||||
"-carla-world-port={}".format(self.server_port)],
|
||||
@@ -107,6 +126,9 @@ class CarlaEnv(gym.Env):
|
||||
try:
|
||||
if not self.server_process:
|
||||
self.init_server()
|
||||
# reset twice since the first time a server is initialized,
|
||||
# the starting location is different
|
||||
self._reset()
|
||||
return self._reset()
|
||||
except Exception as e:
|
||||
print("Error during reset: {}".format(traceback.format_exc()))
|
||||
@@ -117,48 +139,52 @@ class CarlaEnv(gym.Env):
|
||||
def _reset(self):
|
||||
self.num_steps = 0
|
||||
self.prev_measurement = None
|
||||
self.episode_id = datetime.today().strftime("%Y-%m-%d_%H-%M-%S_%f")
|
||||
self.measurements_file = None
|
||||
|
||||
# Create a CarlaSettings object. This object is a wrapper around
|
||||
# the CarlaSettings.ini file. Here we set the configuration we
|
||||
# want for the new episode.
|
||||
settings = CarlaSettings()
|
||||
self.weather = random.choice(self.config["weather"])
|
||||
settings.set(
|
||||
SynchronousMode=True,
|
||||
SendNonPlayerAgentsInfo=True,
|
||||
NumberOfVehicles=self.config["num_vehicles"],
|
||||
NumberOfPedestrians=self.config["num_pedestrians"],
|
||||
WeatherId=random.choice(self.config["weather"]))
|
||||
WeatherId=self.weather)
|
||||
settings.randomize_seeds()
|
||||
|
||||
if self.config["use_depth_camera"]:
|
||||
camera = Camera("CameraDepth", PostProcessing="Depth")
|
||||
camera.set_image_size(self.config["x_res"], self.config["y_res"])
|
||||
camera.set_position(30, 0, 130)
|
||||
settings.add_sensor(camera)
|
||||
else:
|
||||
camera = Camera("CameraRGB")
|
||||
camera.set_image_size(self.config["x_res"], self.config["y_res"])
|
||||
camera.set_position(30, 0, 130)
|
||||
settings.add_sensor(camera)
|
||||
camera1 = Camera("CameraDepth", PostProcessing="Depth")
|
||||
camera1.set_image_size(
|
||||
self.config["render_x_res"], self.config["render_y_res"])
|
||||
camera1.set_position(30, 0, 130)
|
||||
settings.add_sensor(camera1)
|
||||
|
||||
camera2 = Camera("CameraRGB")
|
||||
camera2.set_image_size(
|
||||
self.config["render_x_res"], self.config["render_y_res"])
|
||||
camera2.set_position(30, 0, 130)
|
||||
settings.add_sensor(camera2)
|
||||
|
||||
scene = self.client.load_settings(settings)
|
||||
|
||||
# Choose one player start at random.
|
||||
number_of_player_starts = len(scene.player_start_spots)
|
||||
if self.config["random_starting_location"]:
|
||||
player_start = random.randint(
|
||||
self.player_start = random.randint(
|
||||
0, max(0, number_of_player_starts - 1))
|
||||
else:
|
||||
player_start = 0
|
||||
self.player_start = 0
|
||||
|
||||
# Notify the server that we want to start the episode at the
|
||||
# player_start index. This function blocks until the server is ready
|
||||
# to start the episode.
|
||||
print("Starting new episode...")
|
||||
self.client.start_episode(player_start)
|
||||
self.client.start_episode(self.player_start)
|
||||
|
||||
image, measurements = self._read_observation()
|
||||
self.prev_measurement = measurements
|
||||
image, py_measurements = self._read_observation()
|
||||
self.prev_measurement = py_measurements
|
||||
return self.preprocess_image(image)
|
||||
|
||||
def step(self, action):
|
||||
@@ -206,38 +232,79 @@ class CarlaEnv(gym.Env):
|
||||
brake = max(0.0, min(1.0, action[2]))
|
||||
reverse = action[1] < 0.0
|
||||
|
||||
print(
|
||||
"steer", steer, "throttle", throttle, "brake", brake,
|
||||
"reverse", reverse)
|
||||
hand_brake = False
|
||||
|
||||
if self.config["verbose"]:
|
||||
print(
|
||||
"steer", steer, "throttle", throttle, "brake", brake,
|
||||
"reverse", reverse)
|
||||
|
||||
self.client.send_control(
|
||||
steer=steer, throttle=throttle, brake=brake, hand_brake=False,
|
||||
steer=steer, throttle=throttle, brake=brake, hand_brake=hand_brake,
|
||||
reverse=reverse)
|
||||
image, measurements = self._read_observation()
|
||||
|
||||
# Process observations
|
||||
image, py_measurements = self._read_observation()
|
||||
reward, done = compute_reward(
|
||||
self.config, self.prev_measurement, measurements)
|
||||
self.prev_measurement = measurements
|
||||
self.config, self.prev_measurement, py_measurements)
|
||||
if self.num_steps > self.config["max_steps"]:
|
||||
done = True
|
||||
self.total_reward += reward
|
||||
py_measurements["reward"] = reward
|
||||
py_measurements["total_reward"] = self.total_reward
|
||||
py_measurements["done"] = done
|
||||
py_measurements["action"] = action
|
||||
py_measurements["control"] = {
|
||||
"steer": steer,
|
||||
"throttle": throttle,
|
||||
"brake": brake,
|
||||
"reverse": reverse,
|
||||
"hand_brake": hand_brake,
|
||||
}
|
||||
self.prev_measurement = py_measurements
|
||||
|
||||
# Write out measurements to file
|
||||
if CARLA_OUT_PATH:
|
||||
if not self.measurements_file:
|
||||
self.measurements_file = open(
|
||||
os.path.join(
|
||||
CARLA_OUT_PATH,
|
||||
"measurements_{}.json".format(self.episode_id)),
|
||||
"w")
|
||||
self.measurements_file.write(json.dumps(py_measurements))
|
||||
self.measurements_file.write("\n")
|
||||
if done:
|
||||
self.measurements_file.close()
|
||||
self.measurements_file = None
|
||||
|
||||
self.num_steps += 1
|
||||
info = {}
|
||||
image = self.preprocess_image(image)
|
||||
return image, reward, done, info
|
||||
return image, reward, done, py_measurements
|
||||
|
||||
def preprocess_image(self, image):
|
||||
if self.config["use_depth_camera"]:
|
||||
data = (image.data - 0.5) * 2
|
||||
return data.reshape(self.config["x_res"], self.config["y_res"], 1)
|
||||
data = data.reshape(
|
||||
self.config["render_y_res"], self.config["render_x_res"], 1)
|
||||
data = cv2.resize(
|
||||
data, (self.config["x_res"], self.config["y_res"]),
|
||||
interpolation=cv2.INTER_AREA)
|
||||
else:
|
||||
return image.data.reshape(
|
||||
self.config["x_res"], self.config["y_res"], 3)
|
||||
data = image.data.reshape(
|
||||
self.config["render_y_res"], self.config["render_x_res"], 3)
|
||||
data = cv2.resize(
|
||||
data, (self.config["x_res"], self.config["y_res"]),
|
||||
interpolation=cv2.INTER_AREA)
|
||||
data = (data.astype(np.float32) - 128) / 128
|
||||
return data
|
||||
|
||||
def _read_observation(self):
|
||||
# Read the data produced by the server this frame.
|
||||
measurements, sensor_data = self.client.read_data()
|
||||
|
||||
# Print some of the measurements.
|
||||
print_measurements(measurements)
|
||||
if self.config["verbose"]:
|
||||
print_measurements(measurements)
|
||||
|
||||
observation = None
|
||||
if self.config["use_depth_camera"]:
|
||||
@@ -248,13 +315,41 @@ class CarlaEnv(gym.Env):
|
||||
if name == camera_name:
|
||||
observation = image
|
||||
|
||||
if IMAGE_OUT_PATH:
|
||||
cur = measurements.player_measurements
|
||||
py_measurements = {
|
||||
"episode_id": self.episode_id,
|
||||
"step": self.num_steps,
|
||||
"x": cur.transform.location.x,
|
||||
"y": cur.transform.location.y,
|
||||
"forward_speed": cur.forward_speed,
|
||||
"collision_vehicles": cur.collision_vehicles,
|
||||
"collision_pedestrians": cur.collision_pedestrians,
|
||||
"collision_other": cur.collision_other,
|
||||
"intersection_offroad": cur.intersection_offroad,
|
||||
"intersection_otherlane": cur.intersection_otherlane,
|
||||
"weather": self.weather,
|
||||
"map": self.config["map"],
|
||||
"target_x": self.config["target_x"],
|
||||
"target_y": self.config["target_y"],
|
||||
"x_res": self.config["x_res"],
|
||||
"y_res": self.config["y_res"],
|
||||
"num_vehicles": self.config["num_vehicles"],
|
||||
"num_pedestrians": self.config["num_pedestrians"],
|
||||
"max_steps": self.config["max_steps"],
|
||||
}
|
||||
|
||||
if CARLA_OUT_PATH:
|
||||
for name, image in sensor_data.items():
|
||||
scipy.misc.imsave("{}/{}-{}.jpg".format(
|
||||
IMAGE_OUT_PATH, name, self.num_steps), image.data)
|
||||
out_dir = os.path.join(CARLA_OUT_PATH, name)
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
out_file = os.path.join(
|
||||
out_dir,
|
||||
"{}_{:>04}.jpg".format(self.episode_id, self.num_steps))
|
||||
scipy.misc.imsave(out_file, image.data)
|
||||
|
||||
assert observation is not None, sensor_data
|
||||
return observation, measurements
|
||||
return observation, py_measurements
|
||||
|
||||
|
||||
def distance(x1, y1, x2, y2):
|
||||
@@ -262,13 +357,10 @@ def distance(x1, y1, x2, y2):
|
||||
|
||||
|
||||
def compute_reward(config, prev, current):
|
||||
prev = prev.player_measurements
|
||||
current = current.player_measurements
|
||||
|
||||
prev_x = prev.transform.location.x / 100 # cm -> m
|
||||
prev_y = prev.transform.location.y / 100
|
||||
cur_x = current.transform.location.x / 100 # cm -> m
|
||||
cur_y = current.transform.location.y / 100
|
||||
prev_x = prev["x"] / 100 # cm -> m
|
||||
prev_y = prev["y"] / 100
|
||||
cur_x = current["x"] / 100 # cm -> m
|
||||
cur_y = current["y"] / 100
|
||||
|
||||
reward = 0.0
|
||||
done = False
|
||||
@@ -279,20 +371,21 @@ def compute_reward(config, prev, current):
|
||||
distance(cur_x, cur_y, config["target_x"], config["target_y"]))
|
||||
|
||||
# Change in speed (km/h)
|
||||
reward += 0.05 * (current.forward_speed - prev.forward_speed)
|
||||
reward += 0.05 * (current["forward_speed"] - prev["forward_speed"])
|
||||
|
||||
# New collision damage
|
||||
reward -= .00002 * (
|
||||
current.collision_vehicles + current.collision_pedestrians +
|
||||
current.collision_other - prev.collision_vehicles -
|
||||
prev.collision_pedestrians - prev.collision_other)
|
||||
current["collision_vehicles"] + current["collision_pedestrians"] +
|
||||
current["collision_other"] - prev["collision_vehicles"] -
|
||||
prev["collision_pedestrians"] - prev["collision_other"])
|
||||
|
||||
# New sidewalk intersection
|
||||
reward -= 2 * (current.intersection_offroad - prev.intersection_offroad)
|
||||
reward -= 2 * (
|
||||
current["intersection_offroad"] - prev["intersection_offroad"])
|
||||
|
||||
# New opposite lane intersection
|
||||
reward -= 2 * (
|
||||
current.intersection_otherlane - prev.intersection_otherlane)
|
||||
current["intersection_otherlane"] - prev["intersection_otherlane"])
|
||||
|
||||
if distance(cur_x, cur_y, config["target_x"], config["target_y"]) < 10:
|
||||
done = True
|
||||
|
||||
@@ -9,11 +9,13 @@ from env import CarlaEnv, ENV_CONFIG
|
||||
env_name = "carla_env"
|
||||
env_config = ENV_CONFIG.copy()
|
||||
env_config.update({
|
||||
"x_res": 210,
|
||||
"y_res": 160,
|
||||
"verbose": False,
|
||||
"x_res": 240,
|
||||
"y_res": 240,
|
||||
"use_depth_camera": False,
|
||||
"discrete_actions": True,
|
||||
"max_steps": 50,
|
||||
"max_steps": 200,
|
||||
"weather": [1, 3, 7, 8, 14],
|
||||
})
|
||||
register_env(env_name, lambda: CarlaEnv(env_config))
|
||||
|
||||
@@ -23,6 +25,14 @@ run_experiments({
|
||||
"env": "carla_env",
|
||||
"resources": {"cpu": 4, "gpu": 1},
|
||||
"config": {
|
||||
"model": {
|
||||
"conv_filters": [
|
||||
[16, [8, 8], 4],
|
||||
[32, [5, 5], 3],
|
||||
[32, [5, 5], 2],
|
||||
[512, [10, 10], 1],
|
||||
],
|
||||
},
|
||||
"timesteps_per_iteration": 100,
|
||||
"learning_starts": 1000,
|
||||
"schedule_max_timesteps": 100000,
|
||||
|
||||
@@ -9,6 +9,7 @@ from env import CarlaEnv, ENV_CONFIG
|
||||
env_name = "carla_env"
|
||||
env_config = ENV_CONFIG.copy()
|
||||
env_config.update({
|
||||
"verbose": False,
|
||||
"x_res": 80,
|
||||
"y_res": 80,
|
||||
"use_depth_camera": True,
|
||||
|
||||
@@ -296,8 +296,10 @@ class Trial(object):
|
||||
if not os.path.exists(self.local_dir):
|
||||
os.makedirs(self.local_dir)
|
||||
self.logdir = tempfile.mkdtemp(
|
||||
prefix=str(self), dir=self.local_dir,
|
||||
suffix=datetime.today().strftime("_%Y-%m-%d_%H-%M-%S"))
|
||||
prefix="{}_{}".format(
|
||||
self,
|
||||
datetime.today().strftime("%Y-%m-%d_%H-%M-%S")),
|
||||
dir=self.local_dir)
|
||||
self.result_logger = UnifiedLogger(
|
||||
self.config, self.logdir, self.upload_dir)
|
||||
remote_logdir = self.logdir
|
||||
|
||||
Reference in New Issue
Block a user