Skip to content

Commit

Permalink
Update to CARLA 0.9.10 + Determinism improvements
Browse files Browse the repository at this point in the history
* Added determinism fixes
* Added human log and playback + TM sync
* Changed set_velocity to set_target_velocity

Co-authored-by: Fabian Oboril <[email protected]>
  • Loading branch information
glopezdiest and fabianoboril authored Sep 30, 2020
1 parent 2e580d8 commit 65bd4fd
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 96 deletions.
2 changes: 1 addition & 1 deletion CARLA_VER
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
HOST = https://carla-releases.s3.eu-west-3.amazonaws.com/Linux
RELEASE=CARLA_0.9.9
RELEASE=CARLA_0.9.10
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ from ubuntu:18.04
# Install base libs
run apt-get update && apt-get install --no-install-recommends -y libpng16-16=1.6.34-1ubuntu0.18.04.2 \
libtiff5=4.0.9-5ubuntu0.3 libjpeg8=8c-2ubuntu8 build-essential=12.4ubuntu1 wget=1.19.4-1ubuntu2.2 git=1:2.17.1-1ubuntu0.7 \
python3.6=3.6.9-1~18.04ubuntu1 python3.6-dev=3.6.9-1~18.04ubuntu1 python3-pip=9.0.1-2.3~ubuntu1.18.04.1 \
&& rm -rf /var/lib/apt/lists/*
python3.6 python3.6-dev python3-pip libxerces-c-dev \
&& rm -rf /var/lib/apt/lists/*

# Install python requirements
run pip3 install --user setuptools==46.3.0 wheel==0.34.2 && pip3 install py_trees==0.8.3 networkx==2.2 pygame==1.9.6 \
six==1.14.0 numpy==1.18.4 psutil==5.7.0 shapely==1.7.0 xmlschema==1.1.3 ephem==3.7.6.0 tabulate==0.8.7\
&& mkdir -p /app/scenario_runner
&& mkdir -p /app/scenario_runner

# Install scenario_runner
copy . /app/scenario_runner
Expand All @@ -19,7 +19,7 @@ copy . /app/scenario_runner
# CARLA_HOST : uri for carla package without trailing slash.
# For example, "https://carla-releases.s3.eu-west-3.amazonaws.com/Linux".
# If this environment is not passed to docker build, the value
# is taken from CARLA_VER file inside the repository.
# is taken from CARLA_VER file inside the repository.
#
# CARLA_RELEASE : Name of the package to be used. For example, "CARLA_0.9.9".
# If this environment is not passed to docker build, the value
Expand Down
2 changes: 2 additions & 0 deletions Docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* Changed manual control to be in par with the CARLA version. Among others, added vehicle lights, recording and some new sensors
* Removed unsupported scenarios (ChallengeBasic and BackgroundActivity, VehicleTurnLeftAtJunction)
* Added a new metrics module, which gives access to all the information about a scenario in order to allow the user to extract any desired information about the simulation. More information [here](metrics_module.md)
* Removed the default randomness at the ControlLoss scenario
* OpenSCENARIO support:
- Added support for controllers and provided default implementations for vehicles and pedestrians. This required changing the handling of actors, which results in that now all actors are controlled by an OSC controller. Supported controllers:
- Pedestrian controller
Expand Down Expand Up @@ -97,6 +98,7 @@
* Fixed exception bug in spawn function of CarlaDataProvider
* Fixed access to private member of CARLA LocalPlanner inside OSC NpcVehicleControl
* Fixed handling of OSC LanePosition (#625)
* Fixed bug causing the route repetitions to spawn different background activity
* Fixed bug causing the rotate_point function inside RunningRedLightTest to not function properly.
### :ghost: Maintenance
* Exposed traffic manager port flag to enable the execution of multiple scenarios on a single machine.
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ networkx==2.2
Shapely==1.6.4.post2
psutil
xmlschema==1.0.18
carla
ephem
tabulate
opencv-python==4.2.0.32
Expand Down
7 changes: 7 additions & 0 deletions scenario_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __init__(self, args):
self.client = carla.Client(args.host, int(args.port))
self.client.set_timeout(self.client_timeout)

self.traffic_manager = self.client.get_trafficmanager(int(self._args.trafficManagerPort))

dist = pkg_resources.get_distribution("carla")
if LooseVersion(dist.version) < LooseVersion('0.9.8'):
raise ImportError("CARLA version 0.9.8 or newer required. CARLA version found: {}".format(dist))
Expand Down Expand Up @@ -319,6 +321,9 @@ def _load_and_wait_for_world(self, town, ego_vehicles=None):
settings.fixed_delta_seconds = 1.0 / self.frame_rate
self.world.apply_settings(settings)

self.traffic_manager.set_synchronous_mode(True)
self.traffic_manager.set_random_device_seed(int(self._args.trafficManagerSeed))

CarlaDataProvider.set_client(self.client)
CarlaDataProvider.set_world(self.world)
CarlaDataProvider.set_traffic_manager_port(int(self._args.trafficManagerPort))
Expand Down Expand Up @@ -509,6 +514,8 @@ def main():
help='Set the CARLA client timeout value in seconds')
parser.add_argument('--trafficManagerPort', default='8000',
help='Port to use for the TrafficManager (default: 8000)')
parser.add_argument('--trafficManagerSeed', default='0',
help='Seed used by the TrafficManager (default: 0)')
parser.add_argument('--sync', action='store_true',
help='Forces the simulation to run synchronously')
parser.add_argument('--list', action="store_true", help='List all supported scenarios and exit')
Expand Down
212 changes: 139 additions & 73 deletions srunner/autoagents/human_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
This module provides a human agent to control the ego vehicle via keyboard
"""

import time
from threading import Thread
import cv2
import numpy as np
from __future__ import print_function

import json

try:
import pygame
Expand All @@ -23,6 +22,7 @@
from pygame.locals import K_d
from pygame.locals import K_s
from pygame.locals import K_w
from pygame.locals import K_q
except ImportError:
raise RuntimeError('cannot import pygame, make sure pygame package is installed')

Expand All @@ -37,13 +37,9 @@ class HumanInterface(object):
Class to control a vehicle manually for debugging purposes
"""

def __init__(self, parent):
self.quit = False
self._parent = parent
def __init__(self):
self._width = 800
self._height = 600
self._throttle_delta = 0.05
self._steering_delta = 0.01
self._surface = None

pygame.init()
Expand All @@ -52,39 +48,23 @@ def __init__(self, parent):
self._display = pygame.display.set_mode((self._width, self._height), pygame.HWSURFACE | pygame.DOUBLEBUF)
pygame.display.set_caption("Human Agent")

def run(self):
def run_interface(self, input_data):
"""
Run the GUI
"""
while not self._parent.agent_engaged and not self.quit:
time.sleep(0.5)

controller = KeyboardControl()
while not self.quit:
self._clock.tick_busy_loop(20)
controller.parse_events(self._parent.current_control, self._clock)
# Process events
pygame.event.pump()

# process sensor data
input_data = self._parent.sensor_interface.get_data()
image_center = input_data['Center'][1][:, :, -2::-1]
image_left = input_data['Left'][1][:, :, -2::-1]
image_right = input_data['Right'][1][:, :, -2::-1]
image_rear = input_data['Rear'][1][:, :, -2::-1]

top_row = np.hstack((image_left, image_center, image_right))
bottom_row = np.hstack((0 * image_rear, image_rear, 0 * image_rear))
comp_image = np.vstack((top_row, bottom_row))
# resize image
image_rescaled = cv2.resize(comp_image, dsize=(self._width, self._height), interpolation=cv2.INTER_CUBIC)

# display image
self._surface = pygame.surfarray.make_surface(image_rescaled.swapaxes(0, 1))
if self._surface is not None:
self._display.blit(self._surface, (0, 0))
pygame.display.flip()
# process sensor data
image_center = input_data['Center'][1][:, :, -2::-1]

# display image
self._surface = pygame.surfarray.make_surface(image_center.swapaxes(0, 1))
if self._surface is not None:
self._display.blit(self._surface, (0, 0))
pygame.display.flip()

def quit_interface(self):
"""
Stops the pygame window
"""
pygame.quit()


Expand All @@ -96,21 +76,17 @@ class HumanAgent(AutonomousAgent):

current_control = None
agent_engaged = False
prev_timestamp = 0

def setup(self, path_to_conf_file):
"""
Setup the agent parameters
"""

self.agent_engaged = False
self.current_control = carla.VehicleControl()
self.current_control.steer = 0.0
self.current_control.throttle = 1.0
self.current_control.brake = 0.0
self.current_control.hand_brake = False
self._hic = HumanInterface(self)
self._thread = Thread(target=self._hic.run)
self._thread.start()
self.prev_timestamp = 0
self._hic = HumanInterface()
self._controller = KeyboardControl(path_to_conf_file)

def sensors(self):
"""
Expand All @@ -132,17 +108,7 @@ def sensors(self):
"""
sensors = [{'type': 'sensor.camera.rgb', 'x': 0.7, 'y': 0.0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0,
'width': 300, 'height': 200, 'fov': 100, 'id': 'Center'},

{'type': 'sensor.camera.rgb', 'x': 0.7, 'y': -0.4, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0,
'yaw': -45.0, 'width': 300, 'height': 200, 'fov': 100, 'id': 'Left'},

{'type': 'sensor.camera.rgb', 'x': 0.7, 'y': 0.4, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0, 'yaw': 45.0,
'width': 300, 'height': 200, 'fov': 100, 'id': 'Right'},

{'type': 'sensor.camera.rgb', 'x': -1.8, 'y': 0, 'z': 1.60, 'roll': 0.0, 'pitch': 0.0,
'yaw': 180.0, 'width': 300, 'height': 200, 'fov': 130, 'id': 'Rear'},

'width': 800, 'height': 600, 'fov': 100, 'id': 'Center'},
{'type': 'sensor.other.gnss', 'x': 0.7, 'y': -0.4, 'z': 1.60, 'id': 'GPS'}
]

Expand All @@ -153,15 +119,18 @@ def run_step(self, input_data, timestamp):
Execute one step of navigation.
"""
self.agent_engaged = True
time.sleep(0.1)
return self.current_control
self._hic.run_interface(input_data)

control = self._controller.parse_events(timestamp - self.prev_timestamp)
self.prev_timestamp = timestamp

return control

def destroy(self):
"""
Cleanup
"""
self._hic.quit = True
self._thread.join()
self._hic.quit_interface = True


class KeyboardControl(object):
Expand All @@ -170,33 +139,91 @@ class KeyboardControl(object):
Keyboard control for the human agent
"""

def __init__(self):
def __init__(self, path_to_conf_file):
"""
Init
"""
self._control = carla.VehicleControl()
self._steer_cache = 0.0
self._clock = pygame.time.Clock()

# Get the mode
if path_to_conf_file:

with (open(path_to_conf_file, "r")) as f:
lines = f.read().split("\n")
self._mode = lines[0].split(" ")[1]
self._endpoint = lines[1].split(" ")[1]

# Get the needed vars
if self._mode == "log":
self._log_data = {'records': []}

elif self._mode == "playback":
self._index = 0
self._control_list = []

with open(self._endpoint) as fd:
try:
self._records = json.load(fd)
self._json_to_control()
except ValueError:
# Moving to Python 3.5+ this can be replaced with json.JSONDecodeError
pass
else:
self._mode = "normal"
self._endpoint = None

def parse_events(self, control, clock):
def _json_to_control(self):
"""
Parses the json file into a list of carla.VehicleControl
"""

# transform strs into VehicleControl commands
for entry in self._records['records']:
control = carla.VehicleControl(throttle=entry['control']['throttle'],
steer=entry['control']['steer'],
brake=entry['control']['brake'],
hand_brake=entry['control']['hand_brake'],
reverse=entry['control']['reverse'],
manual_gear_shift=entry['control']['manual_gear_shift'],
gear=entry['control']['gear'])
self._control_list.append(control)

def parse_events(self, timestamp):
"""
Parse the keyboard events and set the vehicle controls accordingly
"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
# Move the vehicle
if self._mode == "playback":
self._parse_json_control()
else:
self._parse_vehicle_keys(pygame.key.get_pressed(), timestamp * 1000)

# Record the control
if self._mode == "log":
self._record_control()

self._parse_vehicle_keys(pygame.key.get_pressed(), clock.get_time())
control.steer = self._control.steer
control.throttle = self._control.throttle
control.brake = self._control.brake
control.hand_brake = self._control.hand_brake
return self._control

def _parse_vehicle_keys(self, keys, milliseconds):
"""
Calculate new vehicle controls based on input keys
"""
self._control.throttle = 0.6 if keys[K_UP] or keys[K_w] else 0.0
steer_increment = 15.0 * 5e-4 * milliseconds
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.KEYUP:
if event.key == K_q:
self._control.gear = 1 if self._control.reverse else -1
self._control.reverse = self._control.gear < 0

if keys[K_UP] or keys[K_w]:
self._control.throttle = 0.6
else:
self._control.throttle = 0.0

steer_increment = 3e-4 * milliseconds
if keys[K_LEFT] or keys[K_a]:
self._steer_cache -= steer_increment
elif keys[K_RIGHT] or keys[K_d]:
Expand All @@ -208,3 +235,42 @@ def _parse_vehicle_keys(self, keys, milliseconds):
self._control.steer = round(self._steer_cache, 1)
self._control.brake = 1.0 if keys[K_DOWN] or keys[K_s] else 0.0
self._control.hand_brake = keys[K_SPACE]

def _parse_json_control(self):
"""
Gets the control corresponding to the current frame
"""

if self._index < len(self._control_list):
self._control = self._control_list[self._index]
self._index += 1
else:
print("JSON file has no more entries")

def _record_control(self):
"""
Saves the list of control into a json file
"""

new_record = {
'control': {
'throttle': self._control.throttle,
'steer': self._control.steer,
'brake': self._control.brake,
'hand_brake': self._control.hand_brake,
'reverse': self._control.reverse,
'manual_gear_shift': self._control.manual_gear_shift,
'gear': self._control.gear
}
}

self._log_data['records'].append(new_record)

def __del__(self):
"""
Delete method
"""
# Get ready to log user commands
if self._mode == "log" and self._log_data:
with open(self._endpoint, 'w') as fd:
json.dump(self._log_data, fd, indent=4, sort_keys=True)
9 changes: 9 additions & 0 deletions srunner/autoagents/human_agent_config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mode: log # Either 'log' or 'playback'
file: test.json # path to the file with the controls


This is the configuration file of the human agent. This agent incorporates two modes.
The log mode parses the controls given to the vehicle into a dictionary and records them into a .json file.
This file can be read by the playback mode to control the vehicle in the same way, resulting in a deterministic agent.
The file name can be chosen, and is the second argument of this config file.

Loading

0 comments on commit 65bd4fd

Please sign in to comment.