2018-07-30 05:52:13 +08:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
# Copyright (c) 2017 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 <https://opensource.org/licenses/MIT>.
|
|
|
|
|
2018-10-28 18:23:59 +08:00
|
|
|
# Allows controlling a vehicle with a keyboard. For a simpler and more
|
|
|
|
# documented example, please take a look at tutorial.py.
|
2018-07-30 05:52:13 +08:00
|
|
|
|
|
|
|
"""
|
|
|
|
Welcome to CARLA manual control.
|
|
|
|
|
|
|
|
Use ARROWS or WASD keys for control.
|
|
|
|
|
|
|
|
W : throttle
|
|
|
|
S : brake
|
|
|
|
AD : steer
|
|
|
|
Q : toggle reverse
|
|
|
|
Space : hand-brake
|
|
|
|
P : toggle autopilot
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
TAB : change camera position
|
|
|
|
` : next camera sensor
|
|
|
|
[1-9] : change to camera sensor [1-9]
|
2018-10-18 06:16:59 +08:00
|
|
|
C : change weather (Shift+C reverse)
|
2018-10-22 06:30:35 +08:00
|
|
|
Backspace : change vehicle
|
2018-10-10 00:04:50 +08:00
|
|
|
|
|
|
|
R : toggle recording images to disk
|
2018-07-30 05:52:13 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
H/? : toggle help
|
|
|
|
ESC : quit
|
|
|
|
"""
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
from __future__ import print_function
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- find carla module ---------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
import glob
|
2018-10-02 22:11:21 +08:00
|
|
|
import os
|
2018-10-10 00:04:50 +08:00
|
|
|
import sys
|
|
|
|
|
|
|
|
try:
|
|
|
|
sys.path.append(glob.glob('**/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
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- imports -------------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
|
|
|
|
import carla
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
from carla import ColorConverter as cc
|
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import random
|
2018-10-18 06:16:59 +08:00
|
|
|
import re
|
2018-10-10 00:04:50 +08:00
|
|
|
import weakref
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
try:
|
|
|
|
import pygame
|
2018-10-10 00:04:50 +08:00
|
|
|
from pygame.locals import KMOD_CTRL
|
|
|
|
from pygame.locals import KMOD_SHIFT
|
|
|
|
from pygame.locals import K_0
|
|
|
|
from pygame.locals import K_9
|
|
|
|
from pygame.locals import K_BACKQUOTE
|
2018-10-22 06:30:35 +08:00
|
|
|
from pygame.locals import K_BACKSPACE
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_DOWN
|
2018-10-10 00:04:50 +08:00
|
|
|
from pygame.locals import K_ESCAPE
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_LEFT
|
|
|
|
from pygame.locals import K_RIGHT
|
2018-10-10 00:04:50 +08:00
|
|
|
from pygame.locals import K_SLASH
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_SPACE
|
2018-10-10 00:04:50 +08:00
|
|
|
from pygame.locals import K_TAB
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_UP
|
|
|
|
from pygame.locals import K_a
|
2018-10-15 18:01:31 +08:00
|
|
|
from pygame.locals import K_c
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_d
|
2018-10-10 00:04:50 +08:00
|
|
|
from pygame.locals import K_h
|
2018-07-30 05:52:13 +08:00
|
|
|
from pygame.locals import K_p
|
|
|
|
from pygame.locals import K_q
|
|
|
|
from pygame.locals import K_r
|
|
|
|
from pygame.locals import K_s
|
|
|
|
from pygame.locals import K_w
|
|
|
|
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')
|
|
|
|
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# -- World ---------------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
2018-07-30 05:52:13 +08:00
|
|
|
|
|
|
|
|
2018-10-18 06:16:59 +08:00
|
|
|
def find_weather_presets():
|
|
|
|
rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)')
|
|
|
|
name = lambda x: ' '.join(m.group(0) for m in rgx.finditer(x))
|
|
|
|
presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)]
|
|
|
|
return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets]
|
|
|
|
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
class World(object):
|
|
|
|
def __init__(self, carla_world, hud):
|
2018-10-22 06:30:35 +08:00
|
|
|
self.world = carla_world
|
2018-10-10 00:04:50 +08:00
|
|
|
self.hud = hud
|
2018-10-22 06:30:35 +08:00
|
|
|
blueprint = self._get_random_blueprint()
|
2018-10-25 19:59:26 +08:00
|
|
|
spawn_points = self.world.get_map().get_spawn_points()
|
|
|
|
spawn_point = random.choice(spawn_points) if spawn_points else carla.Transform()
|
|
|
|
self.vehicle = self.world.spawn_actor(blueprint, spawn_point)
|
2018-10-21 02:33:37 +08:00
|
|
|
self.collision_sensor = CollisionSensor(self.vehicle, self.hud)
|
2018-10-10 00:04:50 +08:00
|
|
|
self.camera_manager = CameraManager(self.vehicle, self.hud)
|
2018-10-22 06:30:35 +08:00
|
|
|
self.camera_manager.set_sensor(0, notify=False)
|
2018-10-10 00:04:50 +08:00
|
|
|
self.controller = None
|
2018-10-18 06:16:59 +08:00
|
|
|
self._weather_presets = find_weather_presets()
|
|
|
|
self._weather_index = 0
|
2018-10-15 18:01:31 +08:00
|
|
|
|
2018-10-22 06:30:35 +08:00
|
|
|
def restart(self):
|
|
|
|
cam_index = self.camera_manager._index
|
|
|
|
cam_pos_index = self.camera_manager._transform_index
|
|
|
|
start_pose = self.vehicle.get_transform()
|
|
|
|
start_pose.location.z += 2.0
|
|
|
|
start_pose.rotation.roll = 0.0
|
|
|
|
start_pose.rotation.pitch = 0.0
|
|
|
|
blueprint = self._get_random_blueprint()
|
|
|
|
self.destroy()
|
|
|
|
self.vehicle = self.world.spawn_actor(blueprint, start_pose)
|
|
|
|
self.collision_sensor = CollisionSensor(self.vehicle, self.hud)
|
|
|
|
self.camera_manager = CameraManager(self.vehicle, self.hud)
|
|
|
|
self.camera_manager._transform_index = cam_pos_index
|
|
|
|
self.camera_manager.set_sensor(cam_index, notify=False)
|
|
|
|
actor_type = ' '.join(self.vehicle.type_id.replace('_', '.').title().split('.')[1:])
|
|
|
|
self.hud.notification(actor_type)
|
|
|
|
|
2018-10-18 06:16:59 +08:00
|
|
|
def next_weather(self, reverse=False):
|
|
|
|
self._weather_index += -1 if reverse else 1
|
|
|
|
self._weather_index %= len(self._weather_presets)
|
|
|
|
preset = self._weather_presets[self._weather_index]
|
|
|
|
self.hud.notification('Weather: %s' % preset[1])
|
|
|
|
self.vehicle.get_world().set_weather(preset[0])
|
2018-10-10 00:04:50 +08:00
|
|
|
|
|
|
|
def tick(self, clock):
|
|
|
|
self.hud.tick(self, clock)
|
|
|
|
|
|
|
|
def render(self, display):
|
|
|
|
self.camera_manager.render(display)
|
|
|
|
self.hud.render(display)
|
|
|
|
|
|
|
|
def destroy(self):
|
2018-10-21 02:33:37 +08:00
|
|
|
for actor in [self.camera_manager.sensor, self.collision_sensor.sensor, self.vehicle]:
|
2018-10-10 00:04:50 +08:00
|
|
|
if actor is not None:
|
|
|
|
actor.destroy()
|
|
|
|
|
2018-10-22 06:30:35 +08:00
|
|
|
def _get_random_blueprint(self):
|
|
|
|
bp = random.choice(self.world.get_blueprint_library().filter('vehicle'))
|
2018-10-22 20:35:48 +08:00
|
|
|
if bp.has_attribute('color'):
|
2018-10-22 06:30:35 +08:00
|
|
|
color = random.choice(bp.get_attribute('color').recommended_values)
|
|
|
|
bp.set_attribute('color', color)
|
|
|
|
return bp
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- KeyboardControl -----------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
class KeyboardControl(object):
|
|
|
|
def __init__(self, world, start_in_autopilot):
|
|
|
|
self._autopilot_enabled = start_in_autopilot
|
|
|
|
self._control = carla.VehicleControl()
|
|
|
|
self._steer_cache = 0.0
|
|
|
|
world.vehicle.set_autopilot(self._autopilot_enabled)
|
|
|
|
world.hud.notification("Press 'H' or '?' for help.", seconds=4.0)
|
|
|
|
|
|
|
|
def parse_events(self, world, clock):
|
|
|
|
for event in pygame.event.get():
|
|
|
|
if event.type == pygame.QUIT:
|
|
|
|
return True
|
|
|
|
elif event.type == pygame.KEYUP:
|
|
|
|
if self._is_quit_shortcut(event.key):
|
|
|
|
return True
|
2018-10-22 06:30:35 +08:00
|
|
|
elif event.key == K_BACKSPACE:
|
|
|
|
world.restart()
|
2018-10-10 00:04:50 +08:00
|
|
|
elif event.key == K_h or (event.key == K_SLASH and pygame.key.get_mods() & KMOD_SHIFT):
|
|
|
|
world.hud.help.toggle()
|
|
|
|
elif event.key == K_TAB:
|
|
|
|
world.camera_manager.toggle_camera()
|
2018-10-18 06:16:59 +08:00
|
|
|
elif event.key == K_c and pygame.key.get_mods() & KMOD_SHIFT:
|
|
|
|
world.next_weather(reverse=True)
|
2018-10-15 18:01:31 +08:00
|
|
|
elif event.key == K_c:
|
|
|
|
world.next_weather()
|
2018-10-10 00:04:50 +08:00
|
|
|
elif event.key == K_BACKQUOTE:
|
|
|
|
world.camera_manager.next_sensor()
|
|
|
|
elif event.key > K_0 and event.key <= K_9:
|
|
|
|
world.camera_manager.set_sensor(event.key - 1)
|
|
|
|
elif event.key == K_r:
|
|
|
|
world.camera_manager.toggle_recording()
|
|
|
|
elif event.key == K_q:
|
|
|
|
self._control.reverse = not self._control.reverse
|
|
|
|
elif event.key == K_p:
|
|
|
|
self._autopilot_enabled = not self._autopilot_enabled
|
|
|
|
world.vehicle.set_autopilot(self._autopilot_enabled)
|
|
|
|
world.hud.notification('Autopilot %s' % ('On' if self._autopilot_enabled else 'Off'))
|
|
|
|
if not self._autopilot_enabled:
|
|
|
|
self._parse_keys(pygame.key.get_pressed(), clock.get_time())
|
|
|
|
world.vehicle.apply_control(self._control)
|
2018-07-30 05:52:13 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
def _parse_keys(self, keys, milliseconds):
|
|
|
|
self._control.throttle = 1.0 if keys[K_UP] or keys[K_w] else 0.0
|
|
|
|
steer_increment = 5e-4 * milliseconds
|
|
|
|
if keys[K_LEFT] or keys[K_a]:
|
|
|
|
self._steer_cache -= steer_increment
|
|
|
|
elif keys[K_RIGHT] or keys[K_d]:
|
|
|
|
self._steer_cache += steer_increment
|
|
|
|
else:
|
|
|
|
self._steer_cache = 0.0
|
|
|
|
self._steer_cache = min(0.7, max(-0.7, self._steer_cache))
|
|
|
|
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]
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _is_quit_shortcut(key):
|
|
|
|
return (key == K_ESCAPE) or (key == K_q and pygame.key.get_mods() & KMOD_CTRL)
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- HUD -----------------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
class HUD(object):
|
|
|
|
def __init__(self, width, height):
|
|
|
|
self.dim = (width, height)
|
|
|
|
font = pygame.font.Font(pygame.font.get_default_font(), 20)
|
|
|
|
mono = next(x for x in pygame.font.get_fonts() if 'mono' in x) # hope for the best...
|
|
|
|
mono = pygame.font.match_font(mono, bold=True)
|
|
|
|
self._font_mono = pygame.font.Font(mono, 14)
|
|
|
|
self._notifications = FadingText(font, (width, 40), (0, height - 40))
|
|
|
|
self.help = HelpText(pygame.font.Font(mono, 24), width, height)
|
|
|
|
self.client_fps = 0
|
|
|
|
self.server_fps = 0
|
|
|
|
|
|
|
|
def tick(self, world, clock):
|
|
|
|
self.client_fps = clock.get_fps()
|
|
|
|
self._notifications.tick(world, clock)
|
|
|
|
|
|
|
|
def notification(self, text, seconds=2.0):
|
|
|
|
self._notifications.set_text(text, seconds=seconds)
|
|
|
|
|
|
|
|
def error(self, text):
|
|
|
|
self._notifications.set_text('Error: %s' % text, (255, 0, 0))
|
|
|
|
|
|
|
|
def render(self, display):
|
|
|
|
self._notifications.render(display)
|
|
|
|
self.help.render(display)
|
|
|
|
fps_text = 'client: %02d FPS; server: %02d FPS' % (self.client_fps, self.server_fps)
|
|
|
|
fps = self._font_mono.render(fps_text, True, (60, 60, 60))
|
|
|
|
display.blit(fps, (6, 4))
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- FadingText ----------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
class FadingText(object):
|
|
|
|
def __init__(self, font, dim, pos):
|
|
|
|
self.font = font
|
|
|
|
self.dim = dim
|
|
|
|
self.pos = pos
|
|
|
|
self.seconds_left = 0
|
|
|
|
self.surface = pygame.Surface(self.dim)
|
|
|
|
|
|
|
|
def set_text(self, text, color=(255, 255, 255), seconds=2.0):
|
|
|
|
text_texture = self.font.render(text, True, color)
|
|
|
|
self.surface = pygame.Surface(self.dim)
|
|
|
|
self.seconds_left = seconds
|
|
|
|
self.surface.fill((0, 0, 0, 0))
|
|
|
|
self.surface.blit(text_texture, (10, 11))
|
|
|
|
|
|
|
|
def tick(self, _, clock):
|
|
|
|
delta_seconds = 1e-3 * clock.get_time()
|
|
|
|
self.seconds_left = max(0.0, self.seconds_left - delta_seconds)
|
|
|
|
self.surface.set_alpha(500.0 * self.seconds_left)
|
|
|
|
|
|
|
|
def render(self, display):
|
|
|
|
display.blit(self.surface, self.pos)
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
# -- HelpText ------------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
class HelpText(object):
|
|
|
|
def __init__(self, font, width, height):
|
2018-10-22 06:30:35 +08:00
|
|
|
lines = __doc__.split('\n')
|
2018-10-10 00:04:50 +08:00
|
|
|
self.font = font
|
2018-10-22 06:30:35 +08:00
|
|
|
self.dim = (680, len(lines) * 22 + 12)
|
2018-10-10 00:04:50 +08:00
|
|
|
self.pos = (0.5 * width - 0.5 * self.dim[0], 0.5 * height - 0.5 * self.dim[1])
|
|
|
|
self.seconds_left = 0
|
|
|
|
self.surface = pygame.Surface(self.dim)
|
|
|
|
self.surface.fill((0, 0, 0, 0))
|
2018-10-22 06:30:35 +08:00
|
|
|
for n, line in enumerate(lines):
|
2018-10-10 00:04:50 +08:00
|
|
|
text_texture = self.font.render(line, True, (255, 255, 255))
|
2018-10-22 06:30:35 +08:00
|
|
|
self.surface.blit(text_texture, (22, n * 22))
|
2018-10-10 00:04:50 +08:00
|
|
|
self._render = False
|
|
|
|
self.surface.set_alpha(220)
|
|
|
|
|
|
|
|
def toggle(self):
|
|
|
|
self._render = not self._render
|
|
|
|
|
|
|
|
def render(self, display):
|
|
|
|
if self._render:
|
|
|
|
display.blit(self.surface, self.pos)
|
|
|
|
|
|
|
|
|
2018-10-21 02:33:37 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# -- CollisionSensor -----------------------------------------------------------
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
class CollisionSensor(object):
|
|
|
|
def __init__(self, parent_actor, hud):
|
|
|
|
self.sensor = None
|
|
|
|
self._parent = parent_actor
|
|
|
|
self._hud = hud
|
|
|
|
world = self._parent.get_world()
|
|
|
|
bp = world.get_blueprint_library().find('sensor.other.collision')
|
|
|
|
self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
|
|
|
|
# We need to pass the lambda a weak reference to self to avoid circular
|
|
|
|
# reference.
|
|
|
|
weak_self = weakref.ref(self)
|
|
|
|
self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _on_collision(weak_self, event):
|
|
|
|
self = weak_self()
|
|
|
|
if not self:
|
|
|
|
return
|
2018-10-22 06:30:35 +08:00
|
|
|
actor_type = ' '.join(event.other_actor.type_id.replace('_', '.').title().split('.')[1:])
|
|
|
|
self._hud.notification('Collision with %r' % actor_type)
|
2018-10-21 02:33:37 +08:00
|
|
|
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# -- CameraManager -------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
|
|
|
|
class CameraManager(object):
|
|
|
|
def __init__(self, parent_actor, hud):
|
|
|
|
self.sensor = None
|
|
|
|
self._surface = None
|
|
|
|
self._parent = parent_actor
|
|
|
|
self._hud = hud
|
|
|
|
self._recording = False
|
|
|
|
self._camera_transforms = [
|
|
|
|
carla.Transform(carla.Location(x=1.6, z=1.7)),
|
2018-10-22 05:29:12 +08:00
|
|
|
carla.Transform(carla.Location(x=-5.5, z=2.8), carla.Rotation(pitch=-15))]
|
2018-10-22 06:30:35 +08:00
|
|
|
self._transform_index = 1
|
2018-10-10 00:04:50 +08:00
|
|
|
self._sensors = [
|
2018-10-22 18:44:13 +08:00
|
|
|
['sensor.camera.rgb', cc.Raw, 'Camera RGB'],
|
|
|
|
['sensor.camera.depth', cc.Raw, 'Camera Depth (Raw)'],
|
2018-10-10 00:04:50 +08:00
|
|
|
['sensor.camera.depth', cc.Depth, 'Camera Depth (Gray Scale)'],
|
|
|
|
['sensor.camera.depth', cc.LogarithmicDepth, 'Camera Depth (Logarithmic Gray Scale)'],
|
2018-10-22 18:44:13 +08:00
|
|
|
['sensor.camera.semantic_segmentation', cc.Raw, 'Camera Semantic Segmentation (Raw)'],
|
2018-10-10 00:04:50 +08:00
|
|
|
['sensor.camera.semantic_segmentation', cc.CityScapesPalette, 'Camera Semantic Segmentation (CityScapes Palette)']]
|
|
|
|
world = self._parent.get_world()
|
|
|
|
bp_library = world.get_blueprint_library()
|
|
|
|
for item in self._sensors:
|
|
|
|
bp = bp_library.find(item[0])
|
|
|
|
bp.set_attribute('image_size_x', str(hud.dim[0]))
|
|
|
|
bp.set_attribute('image_size_y', str(hud.dim[1]))
|
|
|
|
item.append(bp)
|
|
|
|
self._index = None
|
|
|
|
self._server_clock = pygame.time.Clock()
|
|
|
|
|
|
|
|
def toggle_camera(self):
|
2018-10-22 05:29:12 +08:00
|
|
|
self._transform_index = (self._transform_index + 1) % len(self._camera_transforms)
|
|
|
|
self.sensor.set_transform(self._camera_transforms[self._transform_index])
|
2018-10-10 00:04:50 +08:00
|
|
|
|
2018-10-22 06:30:35 +08:00
|
|
|
def set_sensor(self, index, notify=True):
|
2018-10-10 00:04:50 +08:00
|
|
|
index = index % len(self._sensors)
|
|
|
|
needs_respawn = True if self._index is None \
|
|
|
|
else self._sensors[index][0] != self._sensors[self._index][0]
|
|
|
|
if needs_respawn:
|
|
|
|
if self.sensor is not None:
|
|
|
|
self.sensor.destroy()
|
|
|
|
self._surface = None
|
|
|
|
self.sensor = self._parent.get_world().spawn_actor(
|
|
|
|
self._sensors[index][-1],
|
2018-10-22 05:29:12 +08:00
|
|
|
self._camera_transforms[self._transform_index],
|
2018-10-10 00:04:50 +08:00
|
|
|
attach_to=self._parent)
|
|
|
|
# We need to pass the lambda a weak reference to self to avoid
|
|
|
|
# circular reference.
|
|
|
|
weak_self = weakref.ref(self)
|
|
|
|
self.sensor.listen(lambda image: CameraManager._parse_image(weak_self, image))
|
2018-10-22 06:30:35 +08:00
|
|
|
if notify:
|
|
|
|
self._hud.notification(self._sensors[index][2])
|
2018-10-10 00:04:50 +08:00
|
|
|
self._index = index
|
|
|
|
|
|
|
|
def next_sensor(self):
|
|
|
|
self.set_sensor(self._index + 1)
|
|
|
|
|
|
|
|
def toggle_recording(self):
|
|
|
|
self._recording = not self._recording
|
|
|
|
self._hud.notification('Recording %s' % ('On' if self._recording else 'Off'))
|
|
|
|
|
|
|
|
def render(self, display):
|
|
|
|
if self._surface is not None:
|
|
|
|
display.blit(self._surface, (0, 0))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _parse_image(weak_self, image):
|
|
|
|
self = weak_self()
|
|
|
|
if not self:
|
|
|
|
return
|
|
|
|
self._server_clock.tick()
|
|
|
|
self._hud.server_fps = self._server_clock.get_fps()
|
|
|
|
image.convert(self._sensors[self._index][1])
|
2018-07-30 05:52:13 +08:00
|
|
|
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]
|
|
|
|
self._surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
|
2018-10-10 00:04:50 +08:00
|
|
|
if self._recording:
|
|
|
|
image.save_to_disk('_out/%08d' % image.frame_number)
|
2018-07-30 05:52:13 +08:00
|
|
|
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# -- game_loop() ---------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
2018-10-02 22:11:21 +08:00
|
|
|
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
def game_loop(args):
|
|
|
|
pygame.init()
|
|
|
|
pygame.font.init()
|
|
|
|
world = None
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
try:
|
|
|
|
client = carla.Client(args.host, args.port)
|
|
|
|
client.set_timeout(2.0)
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
display = pygame.display.set_mode(
|
|
|
|
(args.width, args.height),
|
|
|
|
pygame.HWSURFACE | pygame.DOUBLEBUF)
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
hud = HUD(args.width, args.height)
|
|
|
|
world = World(client.get_world(), hud)
|
|
|
|
controller = KeyboardControl(world, args.autopilot)
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
clock = pygame.time.Clock()
|
|
|
|
while True:
|
|
|
|
clock.tick_busy_loop(60)
|
|
|
|
if controller.parse_events(world, clock):
|
|
|
|
return
|
|
|
|
world.tick(clock)
|
|
|
|
world.render(display)
|
|
|
|
pygame.display.flip()
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
finally:
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
if world is not None:
|
|
|
|
world.destroy()
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
pygame.quit()
|
2018-07-30 05:52:13 +08:00
|
|
|
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# -- main() --------------------------------------------------------------------
|
|
|
|
# ==============================================================================
|
2018-07-30 05:52:13 +08:00
|
|
|
|
2018-10-02 22:11:21 +08:00
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
def main():
|
|
|
|
argparser = argparse.ArgumentParser(
|
|
|
|
description='CARLA Manual Control Client')
|
|
|
|
argparser.add_argument(
|
|
|
|
'-v', '--verbose',
|
|
|
|
action='store_true',
|
|
|
|
dest='debug',
|
|
|
|
help='print debug information')
|
|
|
|
argparser.add_argument(
|
|
|
|
'--host',
|
|
|
|
metavar='H',
|
2018-10-02 22:11:21 +08:00
|
|
|
default='127.0.0.1',
|
2018-10-10 00:04:50 +08:00
|
|
|
help='IP of the host server (default: 127.0.0.1)')
|
2018-07-30 05:52:13 +08:00
|
|
|
argparser.add_argument(
|
|
|
|
'-p', '--port',
|
|
|
|
metavar='P',
|
|
|
|
default=2000,
|
|
|
|
type=int,
|
|
|
|
help='TCP port to listen to (default: 2000)')
|
|
|
|
argparser.add_argument(
|
|
|
|
'-a', '--autopilot',
|
|
|
|
action='store_true',
|
|
|
|
help='enable autopilot')
|
2018-10-10 00:04:50 +08:00
|
|
|
argparser.add_argument(
|
|
|
|
'--res',
|
|
|
|
metavar='WIDTHxHEIGHT',
|
|
|
|
default='1280x720',
|
|
|
|
help='window resolution (default: 1280x720)')
|
2018-07-30 05:52:13 +08:00
|
|
|
args = argparser.parse_args()
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
args.width, args.height = [int(x) for x in args.res.split('x')]
|
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
log_level = logging.DEBUG if args.debug else logging.INFO
|
|
|
|
logging.basicConfig(format='%(levelname)s: %(message)s', level=log_level)
|
|
|
|
|
|
|
|
logging.info('listening to server %s:%s', args.host, args.port)
|
2018-10-10 00:04:50 +08:00
|
|
|
|
2018-07-30 05:52:13 +08:00
|
|
|
print(__doc__)
|
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
try:
|
2018-07-30 05:52:13 +08:00
|
|
|
|
2018-10-10 00:04:50 +08:00
|
|
|
game_loop(args)
|
2018-07-30 05:52:13 +08:00
|
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print('\nCancelled by user. Bye!')
|
2018-10-10 00:04:50 +08:00
|
|
|
except Exception as error:
|
|
|
|
logging.exception(error)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
main()
|