manual_control.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. #!/usr/bin/env python
  2. # Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma de
  3. # Barcelona (UAB).
  4. #
  5. # This work is licensed under the terms of the MIT license.
  6. # For a copy, see <https://opensource.org/licenses/MIT>.
  7. # Allows controlling a vehicle with a keyboard. For a simpler and more
  8. # documented example, please take a look at tutorial.py.
  9. """
  10. Welcome to CARLA manual control.
  11. Use ARROWS or WASD keys for control.
  12. W : throttle
  13. S : brake
  14. A/D : steer left/right
  15. Q : toggle reverse
  16. Space : hand-brake
  17. P : toggle autopilot
  18. M : toggle manual transmission
  19. ,/. : gear up/down
  20. L : toggle next light type
  21. SHIFT + L : toggle high beam
  22. Z/X : toggle right/left blinker
  23. I : toggle interior light
  24. TAB : change camera position
  25. R : toggle recording images to disk
  26. CTRL + R : toggle recording of simulation (replacing any previous)
  27. CTRL + P : start replaying last recorded simulation
  28. CTRL + + : increments the start time of the replay by 1 second (+SHIFT = 10 seconds)
  29. CTRL + - : decrements the start time of the replay by 1 second (+SHIFT = 10 seconds)
  30. F1 : toggle HUD
  31. H/? : toggle help
  32. ESC : quit
  33. """
  34. from __future__ import print_function
  35. import signal
  36. import subprocess
  37. import psutil
  38. # ==============================================================================
  39. # -- imports -------------------------------------------------------------------
  40. # ==============================================================================
  41. import carla
  42. from carla import ColorConverter as cc
  43. import argparse
  44. import os
  45. import sys
  46. import time
  47. import collections
  48. import datetime
  49. import logging
  50. import math
  51. import weakref
  52. import csv
  53. import random
  54. sys.path.append("/home/vangogh/software/FuzzScene/code/")
  55. import Constants
  56. try:
  57. import pygame
  58. from pygame.locals import K_ESCAPE
  59. from pygame.locals import K_F1
  60. from pygame.locals import KMOD_CTRL
  61. from pygame.locals import KMOD_SHIFT
  62. from pygame.locals import K_BACKSPACE
  63. from pygame.locals import K_TAB
  64. from pygame.locals import K_SPACE
  65. from pygame.locals import K_UP
  66. from pygame.locals import K_DOWN
  67. from pygame.locals import K_LEFT
  68. from pygame.locals import K_RIGHT
  69. from pygame.locals import K_w
  70. from pygame.locals import K_a
  71. from pygame.locals import K_s
  72. from pygame.locals import K_d
  73. from pygame.locals import K_q
  74. from pygame.locals import K_m
  75. from pygame.locals import K_COMMA
  76. from pygame.locals import K_PERIOD
  77. from pygame.locals import K_p
  78. from pygame.locals import K_i
  79. from pygame.locals import K_l
  80. from pygame.locals import K_z
  81. from pygame.locals import K_x
  82. from pygame.locals import K_r
  83. from pygame.locals import K_MINUS
  84. from pygame.locals import K_EQUALS
  85. except ImportError:
  86. raise RuntimeError('cannot import pygame, make sure pygame package is installed')
  87. try:
  88. import numpy as np
  89. except ImportError:
  90. raise RuntimeError('cannot import numpy, make sure numpy package is installed')
  91. number_record = 0
  92. rannumber = random.randint(10000000, 90000000)
  93. # ==============================================================================
  94. # -- Global functions ----------------------------------------------------------
  95. # ==============================================================================
  96. def get_actor_display_name(actor, truncate=250):
  97. name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:])
  98. return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name
  99. # ==============================================================================
  100. # -- World ---------------------------------------------------------------------
  101. # ==============================================================================
  102. class World(object):
  103. restarted = False
  104. def __init__(self, carla_world, hud, args):
  105. self.world = carla_world
  106. try:
  107. self.map = self.world.get_map()
  108. except RuntimeError as error:
  109. print('RuntimeError: {}'.format(error))
  110. print(' The server could not send the OpenDRIVE (.xodr) file:')
  111. print(' Make sure it exists, has the same name of your town, and is correct.')
  112. sys.exit(1)
  113. self.hud = hud
  114. self.player = None
  115. self.collision_sensor = None
  116. self.lane_invasion_sensor = None
  117. self.gnss_sensor = None
  118. self.imu_sensor = None
  119. self.radar_sensor = None
  120. self.camera_manager = None
  121. self.restart()
  122. self.world.on_tick(hud.on_world_tick)
  123. self.recording_enabled = False
  124. self.recording_start = 0
  125. def restart(self):
  126. if self.restarted:
  127. return
  128. self.restarted = True
  129. self.player_max_speed = 1.589
  130. self.player_max_speed_fast = 3.713
  131. # Keep same camera config if the camera manager exists.
  132. cam_index = self.camera_manager.index if self.camera_manager is not None else 0
  133. cam_pos_index = self.camera_manager.transform_index if self.camera_manager is not None else 1
  134. # Get the ego vehicle
  135. while self.player is None:
  136. print("Waiting for the ego vehicle...")
  137. time.sleep(1)
  138. possible_vehicles = self.world.get_actors().filter('vehicle.*')
  139. for vehicle in possible_vehicles:
  140. if vehicle.attributes['role_name'] == 'hero':
  141. print("Ego vehicle found")
  142. self.player = vehicle
  143. # print(vehicle.get_control().steer)
  144. break
  145. self.player_name = self.player.type_id
  146. # Set up the sensors.
  147. self.collision_sensor = CollisionSensor(self.player, self.hud)
  148. self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud)
  149. self.gnss_sensor = GnssSensor(self.player)
  150. self.imu_sensor = IMUSensor(self.player)
  151. self.camera_manager = CameraManager(self.player, self.hud)
  152. self.camera_manager.transform_index = cam_pos_index
  153. self.camera_manager.set_sensor(cam_index, self.player, notify=False)
  154. actor_type = get_actor_display_name(self.player)
  155. self.hud.notification(actor_type)
  156. self.world.wait_for_tick()
  157. def tick(self, clock):
  158. if len(self.world.get_actors().filter(self.player_name)) < 1:
  159. return False
  160. self.hud.tick(self, clock)
  161. return True
  162. def render(self, display):
  163. self.camera_manager.render(display)
  164. self.hud.render(display)
  165. def destroy_sensors(self):
  166. self.camera_manager.sensor.destroy()
  167. self.camera_manager.sensor = None
  168. self.camera_manager.index = None
  169. def destroy(self):
  170. sensors = [
  171. self.camera_manager.sensor,
  172. self.collision_sensor.sensor,
  173. self.lane_invasion_sensor.sensor,
  174. self.gnss_sensor.sensor,
  175. self.imu_sensor.sensor]
  176. for sensor in sensors:
  177. if sensor is not None:
  178. sensor.stop()
  179. sensor.destroy()
  180. if self.player is not None:
  181. self.player.destroy()
  182. # ==============================================================================
  183. # -- KeyboardControl -----------------------------------------------------------
  184. # ==============================================================================
  185. class KeyboardControl(object):
  186. """Class that handles keyboard input."""
  187. def __init__(self, world, start_in_autopilot):
  188. self._autopilot_enabled = start_in_autopilot
  189. self._control = carla.VehicleControl()
  190. self._lights = carla.VehicleLightState.NONE
  191. self._steer_cache = 0.0
  192. world.player.set_autopilot(self._autopilot_enabled)
  193. if (self._autopilot_enabled == True):
  194. world.camera_manager.toggle_recording()
  195. world.player.set_light_state(self._lights)
  196. world.hud.notification("Press 'H' or '?' for help.", seconds=4.0)
  197. def parse_events(self, client, world, clock):
  198. current_lights = self._lights
  199. for event in pygame.event.get():
  200. if event.type == pygame.QUIT:
  201. return True
  202. elif event.type == pygame.KEYUP:
  203. if self._is_quit_shortcut(event.key):
  204. return True
  205. elif event.key == K_BACKSPACE:
  206. if self._autopilot_enabled:
  207. world.player.set_autopilot(False)
  208. world.restart()
  209. world.player.set_autopilot(True)
  210. else:
  211. world.restart()
  212. elif event.key == K_F1:
  213. world.hud.toggle_info()
  214. elif event.key == K_TAB:
  215. world.camera_manager.toggle_camera(world.player)
  216. elif event.key == K_r and not (pygame.key.get_mods() & KMOD_CTRL):
  217. world.camera_manager.toggle_recording()
  218. elif event.key == K_r and (pygame.key.get_mods() & KMOD_CTRL):
  219. if (world.recording_enabled):
  220. client.stop_recorder()
  221. world.recording_enabled = False
  222. world.hud.notification("Recorder is OFF")
  223. else:
  224. client.start_recorder("manual_recording.rec")
  225. world.recording_enabled = True
  226. world.hud.notification("Recorder is ON")
  227. elif event.key == K_p and (pygame.key.get_mods() & KMOD_CTRL):
  228. # stop recorder
  229. client.stop_recorder()
  230. world.recording_enabled = False
  231. # work around to fix camera at start of replaying
  232. current_index = world.camera_manager.index
  233. world.destroy_sensors()
  234. # disable autopilot
  235. self._autopilot_enabled = False
  236. world.player.set_autopilot(self._autopilot_enabled)
  237. world.hud.notification("Replaying file 'manual_recording.rec'")
  238. # replayer
  239. client.replay_file("manual_recording.rec", world.recording_start, 0, 0)
  240. world.camera_manager.set_sensor(current_index)
  241. elif event.key == K_MINUS and (pygame.key.get_mods() & KMOD_CTRL):
  242. if pygame.key.get_mods() & KMOD_SHIFT:
  243. world.recording_start -= 10
  244. else:
  245. world.recording_start -= 1
  246. world.hud.notification("Recording start time is %d" % (world.recording_start))
  247. elif event.key == K_EQUALS and (pygame.key.get_mods() & KMOD_CTRL):
  248. if pygame.key.get_mods() & KMOD_SHIFT:
  249. world.recording_start += 10
  250. else:
  251. world.recording_start += 1
  252. world.hud.notification("Recording start time is %d" % (world.recording_start))
  253. elif event.key == K_q:
  254. self._control.gear = 1 if self._control.reverse else -1
  255. elif event.key == K_m:
  256. self._control.manual_gear_shift = not self._control.manual_gear_shift
  257. self._control.gear = world.player.get_control().gear
  258. world.hud.notification('%s Transmission' %
  259. ('Manual' if self._control.manual_gear_shift else 'Automatic'))
  260. elif self._control.manual_gear_shift and event.key == K_COMMA:
  261. self._control.gear = max(-1, self._control.gear - 1)
  262. elif self._control.manual_gear_shift and event.key == K_PERIOD:
  263. self._control.gear = self._control.gear + 1
  264. elif event.key == K_p and not pygame.key.get_mods() & KMOD_CTRL:
  265. self._autopilot_enabled = not self._autopilot_enabled
  266. world.player.set_autopilot(self._autopilot_enabled)
  267. world.hud.notification(
  268. 'Autopilot %s' % ('On' if self._autopilot_enabled else 'Off'))
  269. world.camera_manager.toggle_recording()
  270. elif event.key == K_l and pygame.key.get_mods() & KMOD_CTRL:
  271. current_lights ^= carla.VehicleLightState.Special1
  272. elif event.key == K_l and pygame.key.get_mods() & KMOD_SHIFT:
  273. current_lights ^= carla.VehicleLightState.HighBeam
  274. elif event.key == K_l:
  275. # Use 'L' key to switch between lights:
  276. # closed -> position -> low beam -> fog
  277. if not self._lights & carla.VehicleLightState.Position:
  278. world.hud.notification("Position lights")
  279. current_lights |= carla.VehicleLightState.Position
  280. else:
  281. world.hud.notification("Low beam lights")
  282. current_lights |= carla.VehicleLightState.LowBeam
  283. if self._lights & carla.VehicleLightState.LowBeam:
  284. world.hud.notification("Fog lights")
  285. current_lights |= carla.VehicleLightState.Fog
  286. if self._lights & carla.VehicleLightState.Fog:
  287. world.hud.notification("Lights off")
  288. current_lights ^= carla.VehicleLightState.Position
  289. current_lights ^= carla.VehicleLightState.LowBeam
  290. current_lights ^= carla.VehicleLightState.Fog
  291. elif event.key == K_i:
  292. current_lights ^= carla.VehicleLightState.Interior
  293. elif event.key == K_z:
  294. current_lights ^= carla.VehicleLightState.LeftBlinker
  295. elif event.key == K_x:
  296. current_lights ^= carla.VehicleLightState.RightBlinker
  297. if not self._autopilot_enabled:
  298. self._parse_vehicle_keys(pygame.key.get_pressed(), clock.get_time())
  299. self._control.reverse = self._control.gear < 0
  300. # Set automatic control-related vehicle lights
  301. if self._control.brake:
  302. current_lights |= carla.VehicleLightState.Brake
  303. else: # Remove the Brake flag
  304. current_lights &= ~carla.VehicleLightState.Brake
  305. if self._control.reverse:
  306. current_lights |= carla.VehicleLightState.Reverse
  307. else: # Remove the Reverse flag
  308. current_lights &= ~carla.VehicleLightState.Reverse
  309. if current_lights != self._lights: # Change the light state only if necessary
  310. self._lights = current_lights
  311. world.player.set_light_state(carla.VehicleLightState(self._lights))
  312. world.player.apply_control(self._control)
  313. def _parse_vehicle_keys(self, keys, milliseconds):
  314. if keys[K_UP] or keys[K_w]:
  315. self._control.throttle = min(self._control.throttle + 0.1, 1.00)
  316. else:
  317. self._control.throttle = 0.0
  318. if keys[K_DOWN] or keys[K_s]:
  319. self._control.brake = min(self._control.brake + 0.2, 1)
  320. else:
  321. self._control.brake = 0
  322. steer_increment = 5e-4 * milliseconds
  323. if keys[K_LEFT] or keys[K_a]:
  324. if self._steer_cache > 0:
  325. self._steer_cache = 0
  326. else:
  327. self._steer_cache -= steer_increment
  328. elif keys[K_RIGHT] or keys[K_d]:
  329. if self._steer_cache < 0:
  330. self._steer_cache = 0
  331. else:
  332. self._steer_cache += steer_increment
  333. else:
  334. self._steer_cache = 0.0
  335. self._steer_cache = min(1.0, max(-1.0, self._steer_cache))
  336. self._control.steer = round(self._steer_cache, 1)
  337. self._control.hand_brake = keys[K_SPACE]
  338. @staticmethod
  339. def _is_quit_shortcut(key):
  340. return (key == K_ESCAPE) or (key == K_q and pygame.key.get_mods() & KMOD_CTRL)
  341. # ==============================================================================
  342. # -- HUD -----------------------------------------------------------------------
  343. # ==============================================================================
  344. class HUD(object):
  345. def __init__(self, width, height):
  346. self.dim = (width, height)
  347. font = pygame.font.Font(pygame.font.get_default_font(), 20)
  348. font_name = 'courier' if os.name == 'nt' else 'mono'
  349. fonts = [x for x in pygame.font.get_fonts() if font_name in x]
  350. default_font = 'ubuntumono'
  351. mono = default_font if default_font in fonts else fonts[0]
  352. mono = pygame.font.match_font(mono)
  353. self._font_mono = pygame.font.Font(mono, 12 if os.name == 'nt' else 14)
  354. self._notifications = FadingText(font, (width, 40), (0, height - 40))
  355. self.help = HelpText(pygame.font.Font(mono, 16), width, height)
  356. self.server_fps = 0
  357. self.frame = 0
  358. self.simulation_time = 0
  359. self._show_info = True
  360. self._info_text = []
  361. self._server_clock = pygame.time.Clock()
  362. def on_world_tick(self, timestamp):
  363. self._server_clock.tick()
  364. self.server_fps = self._server_clock.get_fps()
  365. self.frame = timestamp.frame
  366. self.simulation_time = timestamp.elapsed_seconds
  367. def tick(self, world, clock):
  368. self._notifications.tick(world, clock)
  369. if not self._show_info:
  370. return
  371. t = world.player.get_transform()
  372. v = world.player.get_velocity()
  373. c = world.player.get_control()
  374. # print(c.steer)
  375. compass = world.imu_sensor.compass
  376. heading = 'N' if compass > 270.5 or compass < 89.5 else ''
  377. heading += 'S' if 90.5 < compass < 269.5 else ''
  378. heading += 'E' if 0.5 < compass < 179.5 else ''
  379. heading += 'W' if 180.5 < compass < 359.5 else ''
  380. colhist = world.collision_sensor.get_collision_history()
  381. collision = [colhist[x + self.frame - 200] for x in range(0, 200)]
  382. max_col = max(1.0, max(collision))
  383. collision = [x / max_col for x in collision]
  384. vehicles = world.world.get_actors().filter('vehicle.*')
  385. self._info_text = [
  386. 'Server: % 16.0f FPS' % self.server_fps,
  387. 'Client: % 16.0f FPS' % clock.get_fps(),
  388. '',
  389. 'Vehicle: % 20s' % get_actor_display_name(world.player, truncate=20),
  390. 'Map: % 20s' % world.map.name.split('/')[-1],
  391. 'Simulation time: % 12s' % datetime.timedelta(seconds=int(self.simulation_time)),
  392. '',
  393. 'Speed: % 15.0f km/h' % (3.6 * math.sqrt(v.x ** 2 + v.y ** 2 + v.z ** 2)),
  394. u'Compass:% 17.0f\N{DEGREE SIGN} % 2s' % (compass, heading),
  395. 'Accelero: (%5.1f,%5.1f,%5.1f)' % (world.imu_sensor.accelerometer),
  396. 'Gyroscop: (%5.1f,%5.1f,%5.1f)' % (world.imu_sensor.gyroscope),
  397. 'Location:% 20s' % ('(% 5.1f, % 5.1f)' % (t.location.x, t.location.y)),
  398. 'GNSS:% 24s' % ('(% 2.6f, % 3.6f)' % (world.gnss_sensor.lat, world.gnss_sensor.lon)),
  399. 'Height: % 18.0f m' % t.location.z,
  400. '']
  401. self._info_text += [
  402. ('Throttle:', c.throttle, 0.0, 1.0),
  403. ('Steer:', c.steer, -1.0, 1.0),
  404. ('Brake:', c.brake, 0.0, 1.0),
  405. ('Reverse:', c.reverse),
  406. ('Hand brake:', c.hand_brake),
  407. ('Manual:', c.manual_gear_shift),
  408. 'Gear: %s' % {-1: 'R', 0: 'N'}.get(c.gear, c.gear)]
  409. self._info_text += [
  410. '',
  411. 'Collision:',
  412. collision,
  413. '',
  414. 'Number of vehicles: % 8d' % len(vehicles)]
  415. if len(vehicles) > 1:
  416. self._info_text += ['Nearby vehicles:']
  417. distance = lambda l: math.sqrt(
  418. (l.x - t.location.x) ** 2 + (l.y - t.location.y) ** 2 + (l.z - t.location.z) ** 2)
  419. vehicles = [(distance(x.get_location()), x) for x in vehicles if x.id != world.player.id]
  420. for d, vehicle in sorted(vehicles, key=lambda vehicles: vehicles[0]):
  421. if d > 200.0:
  422. break
  423. vehicle_type = get_actor_display_name(vehicle, truncate=22)
  424. self._info_text.append('% 4dm %s' % (d, vehicle_type))
  425. def toggle_info(self):
  426. self._show_info = not self._show_info
  427. def notification(self, text, seconds=2.0):
  428. self._notifications.set_text(text, seconds=seconds)
  429. def error(self, text):
  430. self._notifications.set_text('Error: %s' % text, (255, 0, 0))
  431. def render(self, display):
  432. if self._show_info:
  433. info_surface = pygame.Surface((220, self.dim[1]))
  434. info_surface.set_alpha(100)
  435. display.blit(info_surface, (0, 0))
  436. v_offset = 4
  437. bar_h_offset = 100
  438. bar_width = 106
  439. for item in self._info_text:
  440. if v_offset + 18 > self.dim[1]:
  441. break
  442. if isinstance(item, list):
  443. if len(item) > 1:
  444. points = [(x + 8, v_offset + 8 + (1.0 - y) * 30) for x, y in enumerate(item)]
  445. pygame.draw.lines(display, (255, 136, 0), False, points, 2)
  446. item = None
  447. v_offset += 18
  448. elif isinstance(item, tuple):
  449. if isinstance(item[1], bool):
  450. rect = pygame.Rect((bar_h_offset, v_offset + 8), (6, 6))
  451. pygame.draw.rect(display, (255, 255, 255), rect, 0 if item[1] else 1)
  452. else:
  453. rect_border = pygame.Rect((bar_h_offset, v_offset + 8), (bar_width, 6))
  454. pygame.draw.rect(display, (255, 255, 255), rect_border, 1)
  455. f = (item[1] - item[2]) / (item[3] - item[2])
  456. if item[2] < 0.0:
  457. rect = pygame.Rect((bar_h_offset + f * (bar_width - 6), v_offset + 8), (6, 6))
  458. else:
  459. rect = pygame.Rect((bar_h_offset, v_offset + 8), (f * bar_width, 6))
  460. pygame.draw.rect(display, (255, 255, 255), rect)
  461. item = item[0]
  462. if item: # At this point has to be a str.
  463. surface = self._font_mono.render(item, True, (255, 255, 255))
  464. display.blit(surface, (8, v_offset))
  465. v_offset += 18
  466. self._notifications.render(display)
  467. self.help.render(display)
  468. # ==============================================================================
  469. # -- FadingText ----------------------------------------------------------------
  470. # ==============================================================================
  471. class FadingText(object):
  472. def __init__(self, font, dim, pos):
  473. self.font = font
  474. self.dim = dim
  475. self.pos = pos
  476. self.seconds_left = 0
  477. self.surface = pygame.Surface(self.dim)
  478. def set_text(self, text, color=(255, 255, 255), seconds=2.0):
  479. text_texture = self.font.render(text, True, color)
  480. self.surface = pygame.Surface(self.dim)
  481. self.seconds_left = seconds
  482. self.surface.fill((0, 0, 0, 0))
  483. self.surface.blit(text_texture, (10, 11))
  484. def tick(self, _, clock):
  485. delta_seconds = 1e-3 * clock.get_time()
  486. self.seconds_left = max(0.0, self.seconds_left - delta_seconds)
  487. self.surface.set_alpha(500.0 * self.seconds_left)
  488. def render(self, display):
  489. display.blit(self.surface, self.pos)
  490. # ==============================================================================
  491. # -- HelpText ------------------------------------------------------------------
  492. # ==============================================================================
  493. class HelpText(object):
  494. """Helper class to handle text output using pygame"""
  495. def __init__(self, font, width, height):
  496. lines = __doc__.split('\n')
  497. self.font = font
  498. self.line_space = 18
  499. self.dim = (780, len(lines) * self.line_space + 12)
  500. self.pos = (0.5 * width - 0.5 * self.dim[0], 0.5 * height - 0.5 * self.dim[1])
  501. self.seconds_left = 0
  502. self.surface = pygame.Surface(self.dim)
  503. self.surface.fill((0, 0, 0, 0))
  504. for n, line in enumerate(lines):
  505. text_texture = self.font.render(line, True, (255, 255, 255))
  506. self.surface.blit(text_texture, (22, n * self.line_space))
  507. self._render = False
  508. self.surface.set_alpha(220)
  509. def toggle(self):
  510. self._render = not self._render
  511. def render(self, display):
  512. if self._render:
  513. display.blit(self.surface, self.pos)
  514. # ==============================================================================
  515. # -- CollisionSensor -----------------------------------------------------------
  516. # ==============================================================================
  517. class CollisionSensor(object):
  518. def __init__(self, parent_actor, hud):
  519. self.sensor = None
  520. self.history = []
  521. self._parent = parent_actor
  522. self.hud = hud
  523. world = self._parent.get_world()
  524. bp = world.get_blueprint_library().find('sensor.other.collision')
  525. self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
  526. # We need to pass the lambda a weak reference to self to avoid circular
  527. # reference.
  528. weak_self = weakref.ref(self)
  529. self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event))
  530. def get_collision_history(self):
  531. history = collections.defaultdict(int)
  532. for frame, intensity in self.history:
  533. history[frame] += intensity
  534. return history
  535. @staticmethod
  536. def _on_collision(weak_self, event):
  537. self = weak_self()
  538. if not self:
  539. return
  540. actor_type = get_actor_display_name(event.other_actor)
  541. self.hud.notification('Collision with %r' % actor_type)
  542. impulse = event.normal_impulse
  543. intensity = math.sqrt(impulse.x ** 2 + impulse.y ** 2 + impulse.z ** 2)
  544. self.history.append((event.frame, intensity))
  545. if len(self.history) > 4000:
  546. self.history.pop(0)
  547. # ==============================================================================
  548. # -- LaneInvasionSensor --------------------------------------------------------
  549. # ==============================================================================
  550. class LaneInvasionSensor(object):
  551. def __init__(self, parent_actor, hud):
  552. self.sensor = None
  553. # If the spawn object is not a vehicle, we cannot use the Lane Invasion Sensor
  554. if parent_actor.type_id.startswith("vehicle."):
  555. self._parent = parent_actor
  556. self.hud = hud
  557. world = self._parent.get_world()
  558. bp = world.get_blueprint_library().find('sensor.other.lane_invasion')
  559. self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
  560. # We need to pass the lambda a weak reference to self to avoid circular
  561. # reference.
  562. weak_self = weakref.ref(self)
  563. self.sensor.listen(lambda event: LaneInvasionSensor._on_invasion(weak_self, event))
  564. @staticmethod
  565. def _on_invasion(weak_self, event):
  566. self = weak_self()
  567. if not self:
  568. return
  569. lane_types = set(x.type for x in event.crossed_lane_markings)
  570. text = ['%r' % str(x).split()[-1] for x in lane_types]
  571. self.hud.notification('Crossed line %s' % ' and '.join(text))
  572. # ==============================================================================
  573. # -- GnssSensor ----------------------------------------------------------------
  574. # ==============================================================================
  575. class GnssSensor(object):
  576. def __init__(self, parent_actor):
  577. self.sensor = None
  578. self._parent = parent_actor
  579. self.lat = 0.0
  580. self.lon = 0.0
  581. world = self._parent.get_world()
  582. bp = world.get_blueprint_library().find('sensor.other.gnss')
  583. self.sensor = world.spawn_actor(bp, carla.Transform(carla.Location(x=1.0, z=2.8)), attach_to=self._parent)
  584. # We need to pass the lambda a weak reference to self to avoid circular
  585. # reference.
  586. weak_self = weakref.ref(self)
  587. self.sensor.listen(lambda event: GnssSensor._on_gnss_event(weak_self, event))
  588. @staticmethod
  589. def _on_gnss_event(weak_self, event):
  590. self = weak_self()
  591. if not self:
  592. return
  593. self.lat = event.latitude
  594. self.lon = event.longitude
  595. # ==============================================================================
  596. # -- IMUSensor -----------------------------------------------------------------
  597. # ==============================================================================
  598. class IMUSensor(object):
  599. def __init__(self, parent_actor):
  600. self.sensor = None
  601. self._parent = parent_actor
  602. self.accelerometer = (0.0, 0.0, 0.0)
  603. self.gyroscope = (0.0, 0.0, 0.0)
  604. self.compass = 0.0
  605. world = self._parent.get_world()
  606. bp = world.get_blueprint_library().find('sensor.other.imu')
  607. self.sensor = world.spawn_actor(
  608. bp, carla.Transform(), attach_to=self._parent)
  609. # We need to pass the lambda a weak reference to self to avoid circular
  610. # reference.
  611. weak_self = weakref.ref(self)
  612. self.sensor.listen(
  613. lambda sensor_data: IMUSensor._IMU_callback(weak_self, sensor_data))
  614. @staticmethod
  615. def _IMU_callback(weak_self, sensor_data):
  616. self = weak_self()
  617. if not self:
  618. return
  619. limits = (-99.9, 99.9)
  620. self.accelerometer = (
  621. max(limits[0], min(limits[1], sensor_data.accelerometer.x)),
  622. max(limits[0], min(limits[1], sensor_data.accelerometer.y)),
  623. max(limits[0], min(limits[1], sensor_data.accelerometer.z)))
  624. self.gyroscope = (
  625. max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.x))),
  626. max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.y))),
  627. max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.z))))
  628. self.compass = math.degrees(sensor_data.compass)
  629. # ==============================================================================
  630. # -- RadarSensor ---------------------------------------------------------------
  631. # ==============================================================================
  632. class RadarSensor(object):
  633. def __init__(self, parent_actor):
  634. self.sensor = None
  635. self._parent = parent_actor
  636. bound_x = 0.5 + self._parent.bounding_box.extent.x
  637. bound_y = 0.5 + self._parent.bounding_box.extent.y
  638. bound_z = 0.5 + self._parent.bounding_box.extent.z
  639. self.velocity_range = 7.5 # m/s
  640. world = self._parent.get_world()
  641. self.debug = world.debug
  642. bp = world.get_blueprint_library().find('sensor.other.radar')
  643. bp.set_attribute('horizontal_fov', str(35))
  644. bp.set_attribute('vertical_fov', str(20))
  645. self.sensor = world.spawn_actor(
  646. bp,
  647. carla.Transform(
  648. carla.Location(x=bound_x + 0.05, z=bound_z + 0.05),
  649. carla.Rotation(pitch=5)),
  650. attach_to=self._parent)
  651. # We need a weak reference to self to avoid circular reference.
  652. weak_self = weakref.ref(self)
  653. self.sensor.listen(
  654. lambda radar_data: RadarSensor._Radar_callback(weak_self, radar_data))
  655. @staticmethod
  656. def _Radar_callback(weak_self, radar_data):
  657. self = weak_self()
  658. if not self:
  659. return
  660. # To get a numpy [[vel, altitude, azimuth, depth],...[,,,]]:
  661. # points = np.frombuffer(radar_data.raw_data, dtype=np.dtype('f4'))
  662. # points = np.reshape(points, (len(radar_data), 4))
  663. current_rot = radar_data.transform.rotation
  664. for detect in radar_data:
  665. azi = math.degrees(detect.azimuth)
  666. alt = math.degrees(detect.altitude)
  667. # The 0.25 adjusts a bit the distance so the dots can
  668. # be properly seen
  669. fw_vec = carla.Vector3D(x=detect.depth - 0.25)
  670. carla.Transform(
  671. carla.Location(),
  672. carla.Rotation(
  673. pitch=current_rot.pitch + alt,
  674. yaw=current_rot.yaw + azi,
  675. roll=current_rot.roll)).transform(fw_vec)
  676. def clamp(min_v, max_v, value):
  677. return max(min_v, min(value, max_v))
  678. norm_velocity = detect.velocity / self.velocity_range # range [-1, 1]
  679. r = int(clamp(0.0, 1.0, 1.0 - norm_velocity) * 255.0)
  680. g = int(clamp(0.0, 1.0, 1.0 - abs(norm_velocity)) * 255.0)
  681. b = int(abs(clamp(- 1.0, 0.0, - 1.0 - norm_velocity)) * 255.0)
  682. self.debug.draw_point(
  683. radar_data.transform.location + fw_vec,
  684. size=0.075,
  685. life_time=0.06,
  686. persistent_lines=False,
  687. color=carla.Color(r, g, b))
  688. # ==============================================================================
  689. # -- CameraManager -------------------------------------------------------------
  690. # ==============================================================================
  691. class CameraManager(object):
  692. def __init__(self, parent_actor, hud):
  693. self.sensor = None
  694. self.surface = None
  695. self._parent = parent_actor
  696. self.hud = hud
  697. self.recording = False
  698. bound_x = 0.5 + self._parent.bounding_box.extent.x
  699. bound_y = 0.5 + self._parent.bounding_box.extent.y
  700. bound_z = 0.5 + self._parent.bounding_box.extent.z
  701. Attachment = carla.AttachmentType
  702. self._camera_transforms = [
  703. (carla.Transform(carla.Location(x=-2.0 * bound_x, y=+0.0 * bound_y, z=2.0 * bound_z),
  704. carla.Rotation(pitch=8.0)), Attachment.SpringArm),
  705. (carla.Transform(carla.Location(x=+0.8 * bound_x, y=+0.0 * bound_y, z=1.3 * bound_z)), Attachment.Rigid),
  706. (
  707. carla.Transform(carla.Location(x=+1.9 * bound_x, y=+1.0 * bound_y, z=1.2 * bound_z)), Attachment.SpringArm),
  708. (carla.Transform(carla.Location(x=-2.8 * bound_x, y=+0.0 * bound_y, z=4.6 * bound_z),
  709. carla.Rotation(pitch=6.0)), Attachment.SpringArm),
  710. (carla.Transform(carla.Location(x=-1.0, y=-1.0 * bound_y, z=0.4 * bound_z)), Attachment.Rigid)]
  711. self.transform_index = 1
  712. self.sensors = [['sensor.camera.rgb', cc.Raw, 'Camera RGB']]
  713. world = self._parent.get_world()
  714. bp_library = world.get_blueprint_library()
  715. for item in self.sensors:
  716. bp = bp_library.find(item[0])
  717. bp.set_attribute('image_size_x', str(hud.dim[0]))
  718. bp.set_attribute('image_size_y', str(hud.dim[1]))
  719. bp.set_attribute('gamma', '2.2')
  720. # bp.set_attribute('sensor_tick', '0.02')
  721. item.append(bp)
  722. self.index = None
  723. def toggle_camera(self, player):
  724. self.transform_index = (self.transform_index + 1) % len(self._camera_transforms)
  725. self.set_sensor(self.index, player, notify=False, force_respawn=True)
  726. def set_sensor(self, index, player, notify=True, force_respawn=False):
  727. index = index % len(self.sensors)
  728. needs_respawn = True if self.index is None else \
  729. (force_respawn or (self.sensors[index][2] != self.sensors[self.index][2]))
  730. if needs_respawn:
  731. if self.sensor is not None:
  732. self.sensor.destroy()
  733. self.surface = None
  734. self.sensor = self._parent.get_world().spawn_actor(
  735. self.sensors[index][-1],
  736. self._camera_transforms[self.transform_index][0],
  737. attach_to=self._parent,
  738. attachment_type=self._camera_transforms[self.transform_index][1])
  739. # We need to pass the lambda a weak reference to self to avoid
  740. # circular reference.
  741. weak_self = weakref.ref(self)
  742. self.sensor.listen(lambda image: CameraManager._parse_image(weak_self, image, player))
  743. if notify:
  744. self.hud.notification(self.sensors[index][2])
  745. self.index = index
  746. def toggle_recording(self):
  747. self.recording = not self.recording
  748. self.hud.notification('Recording %s' % ('On' if self.recording else 'Off'))
  749. def render(self, display):
  750. if self.surface is not None:
  751. display.blit(self.surface, (0, 0))
  752. @staticmethod
  753. def _parse_image(weak_self, image, player):
  754. self = weak_self()
  755. if not self:
  756. return
  757. if self.sensors[self.index][0].startswith('sensor.lidar'):
  758. points = np.frombuffer(image.raw_data, dtype=np.dtype('f4'))
  759. points = np.reshape(points, (int(points.shape[0] / 4), 4))
  760. lidar_data = np.array(points[:, :2])
  761. lidar_data *= min(self.hud.dim) / (2.0 * self.lidar_range)
  762. lidar_data += (0.5 * self.hud.dim[0], 0.5 * self.hud.dim[1])
  763. lidar_data = np.fabs(lidar_data) # pylint: disable=E1111
  764. lidar_data = lidar_data.astype(np.int32)
  765. lidar_data = np.reshape(lidar_data, (-1, 2))
  766. lidar_img_size = (self.hud.dim[0], self.hud.dim[1], 3)
  767. lidar_img = np.zeros((lidar_img_size), dtype=np.uint8)
  768. lidar_img[tuple(lidar_data.T)] = (255, 255, 255)
  769. self.surface = pygame.surfarray.make_surface(lidar_img)
  770. elif self.sensors[self.index][0].startswith('sensor.camera.dvs'):
  771. # Example of converting the raw_data from a carla.DVSEventArray
  772. # sensor into a NumPy array and using it as an image
  773. dvs_events = np.frombuffer(image.raw_data, dtype=np.dtype([
  774. ('x', np.uint16), ('y', np.uint16), ('t', np.int64), ('pol', np.bool)]))
  775. dvs_img = np.zeros((image.height, image.width, 3), dtype=np.uint8)
  776. # Blue is positive, red is negative
  777. dvs_img[dvs_events[:]['y'], dvs_events[:]['x'], dvs_events[:]['pol'] * 2] = 255
  778. self.surface = pygame.surfarray.make_surface(dvs_img.swapaxes(0, 1))
  779. elif self.sensors[self.index][0].startswith('sensor.camera.optical_flow'):
  780. image = image.get_color_coded_flow()
  781. array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
  782. array = np.reshape(array, (image.height, image.width, 4))
  783. array = array[:, :, :3]
  784. array = array[:, :, ::-1]
  785. self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
  786. else:
  787. image.convert(self.sensors[self.index][1])
  788. array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
  789. array = np.reshape(array, (image.height, image.width, 4))
  790. array = array[:, :, :3]
  791. array = array[:, :, ::-1]
  792. self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
  793. if self.recording:
  794. global number_record
  795. global rannumber
  796. number_record = number_record + 1
  797. if number_record > 15 and number_record <= 140:
  798. frameid = image.frame + rannumber
  799. image.save_to_disk(carla_png_output_path + '%08d' % frameid)
  800. image_name = "%08d" % frameid
  801. steering = player.get_control().steer
  802. list_1 = []
  803. if (seed_name == ''):
  804. list_1 = [str(image_name) + ".png", steering, steering * 4]
  805. else:
  806. list_1 = [seed_name, str(image_name) + ".png", steering, steering * 4]
  807. #list_1 = [str(image_name) + ".png", str(seed_name), steering * 4, number_record-15]
  808. file_path = carla_label_output_path + 'label_test.csv'
  809. with open(file_path, 'a+', encoding='utf-8') as f:
  810. csv_writer = csv.writer(f)
  811. csv_writer.writerow(list_1)
  812. print("\n****************************************************")
  813. print("number_record: " + str(number_record))
  814. print("image_id: " + str(image_name))
  815. if (number_record == 140):
  816. print("TIMEOUT EVENT END AT:" + str(datetime.datetime.now()) + " EXIT MANUAL_CONTROL")
  817. # clear_processes();
  818. exit()
  819. def clear_processes():
  820. # try:
  821. # output = subprocess.check_output(['pgrep', '-f', 'CarlaUE4-Linux-Shipping'])
  822. # if output:
  823. # carla_id = int(output.strip())
  824. # if carla_id:
  825. # os.kill(carla_id, signal.SIGTERM)
  826. # print("*******************")
  827. # print("KILL CarlaUE4-Linux-Shipping")
  828. # except subprocess.CalledProcessError:
  829. # pass
  830. # try:
  831. # output = subprocess.check_output(['pgrep', '-f', 'CarlaUE4.sh'])
  832. # if output:
  833. # carla_id = int(output.strip())
  834. # if carla_id:
  835. # os.kill(carla_id, signal.SIGTERM)
  836. # print("*******************")
  837. # print("KILL CarlaUE4.sh")
  838. # except subprocess.CalledProcessError:
  839. # pass
  840. # os.system("pkill -9 Carla")
  841. for proc in psutil.process_iter(['pid', 'cmdline']):
  842. if proc.info['cmdline'] == ['python3', '/home/vangogh/software/FuzzScene/code/scenario_runner-0.9.13/scenario_runner.py',
  843. '--output', '--openscenario', Constants.RADAR_SEED_POOL + seed_name, '--sync', '--reloadWorld']:
  844. proc.kill()
  845. print("*******************")
  846. print("KILL scenario_runner")
  847. # if proc.info['cmdline'] == ['python3', '/home/vangogh/software/FuzzScene/code/scenario_runner-0.9.13/manual_control.py', '-a', '--name', seed_name, '--type', sim_type]:
  848. # proc.kill()
  849. # print("*******************")
  850. # print("KILL manual_control")
  851. print("*******************")
  852. print("CLEAR output IN manual_control")
  853. # ==============================================================================
  854. # -- game_loop() ---------------------------------------------------------------
  855. # ==============================================================================
  856. def game_loop(args):
  857. pygame.init()
  858. pygame.font.init()
  859. world = None
  860. try:
  861. client = carla.Client(args.host, args.port)
  862. client.set_timeout(200) # 200
  863. sim_world = client.get_world()
  864. display = pygame.display.set_mode(
  865. (args.width, args.height),
  866. pygame.HWSURFACE | pygame.DOUBLEBUF)
  867. display.fill((0, 0, 0))
  868. pygame.display.flip()
  869. hud = HUD(args.width, args.height)
  870. world = World(sim_world, hud, args)
  871. controller = KeyboardControl(world, args.autopilot)
  872. sim_world.wait_for_tick()
  873. clock = pygame.time.Clock()
  874. while True:
  875. clock.tick_busy_loop(60)
  876. if controller.parse_events(client, world, clock):
  877. return
  878. if not world.tick(clock):
  879. return
  880. world.render(display)
  881. pygame.display.flip()
  882. finally:
  883. if (world and world.recording_enabled):
  884. client.stop_recorder()
  885. if world is not None:
  886. # prevent destruction of ego vehicle
  887. if args.keep_ego_vehicle:
  888. world.player = None
  889. world.destroy()
  890. pygame.quit()
  891. sys.exit()
  892. # ==============================================================================
  893. # -- main() --------------------------------------------------------------------
  894. # ==============================================================================
  895. def main():
  896. argparser = argparse.ArgumentParser(
  897. description='CARLA Manual Control Client')
  898. argparser.add_argument(
  899. '-v', '--verbose',
  900. action='store_true',
  901. dest='debug',
  902. help='print debug information')
  903. argparser.add_argument(
  904. '--host',
  905. metavar='H',
  906. default='127.0.0.1',
  907. help='IP of the host server (default: 127.0.0.1)')
  908. argparser.add_argument(
  909. '-p', '--port',
  910. metavar='P',
  911. default=3000,
  912. type=int,
  913. help='TCP port to listen to (default: 3000)')
  914. argparser.add_argument(
  915. '-a', '--autopilot',
  916. action='store_true',
  917. help='enable autopilot. This does not autocomplete the scenario')
  918. argparser.add_argument(
  919. '--rolename',
  920. metavar='NAME',
  921. default='hero',
  922. help='role name of ego vehicle to control (default: "hero")')
  923. argparser.add_argument(
  924. '--res',
  925. metavar='WIDTHxHEIGHT',
  926. default='1280x720',
  927. help='window resolution (default: 1280x720)')
  928. argparser.add_argument(
  929. '--keep_ego_vehicle',
  930. action='store_true',
  931. help='do not destroy ego vehicle on exit')
  932. argparser.add_argument( # add name
  933. '--name',
  934. type=str,
  935. default='',
  936. help='seed name')
  937. argparser.add_argument( # add simulation type
  938. '-t', '--type',
  939. default='normal',
  940. type=str,
  941. help='Simulation type is normal or radar')
  942. args = argparser.parse_args()
  943. args.width, args.height = [int(x) for x in args.res.split('x')]
  944. log_level = logging.DEBUG if args.debug else logging.INFO
  945. logging.basicConfig(format='%(levelname)s: %(message)s', level=log_level)
  946. logging.info('listening to server %s:%s', args.host, args.port)
  947. print(__doc__)
  948. global seed_name
  949. global sim_type
  950. global carla_png_output_path
  951. global carla_label_output_path
  952. seed_name = args.name
  953. sim_type = args.type
  954. if (args.type == 'normal'):
  955. carla_png_output_path = Constants.CARLA_PNG_OUTPUT_PATH
  956. carla_label_output_path = Constants.CARLA_LABEL_OUTPUT_PATH
  957. elif (args.type == 'radar'):
  958. carla_png_output_path = Constants.CARLA_RADAR_PNG_OUTPUT_PATH
  959. carla_label_output_path = Constants.CARLA_RADAR_LABEL_OUTPUT_PATH
  960. try:
  961. game_loop(args)
  962. except KeyboardInterrupt:
  963. print('\nCancelled by user. Bye!')
  964. except Exception as error:
  965. logging.exception(error)
  966. if __name__ == '__main__':
  967. main()