forked from carla-simulator/scenario_runner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
scenario_runner.py
416 lines (341 loc) · 15.9 KB
/
scenario_runner.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
#!/usr/bin/env python
# Copyright (c) 2018-2019 Intel Corporation
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
"""
Welcome to CARLA scenario_runner
This is the main script to be executed when running a scenario.
It loads the scenario configuration, loads the scenario and manager,
and finally triggers the scenario execution.
"""
from __future__ import print_function
import traceback
import argparse
from argparse import RawTextHelpFormatter
from datetime import datetime
import importlib
import inspect
import carla
from srunner.scenariomanager.carla_data_provider import *
from srunner.scenariomanager.scenario_manager import ScenarioManager
from srunner.scenarios.background_activity import *
from srunner.scenarios.control_loss import *
from srunner.scenarios.follow_leading_vehicle import *
from srunner.scenarios.maneuver_opposite_direction import *
from srunner.scenarios.master_scenario import *
from srunner.scenarios.no_signal_junction_crossing import *
from srunner.scenarios.object_crash_intersection import *
from srunner.scenarios.object_crash_vehicle import *
from srunner.scenarios.opposite_vehicle_taking_priority import *
from srunner.scenarios.other_leading_vehicle import *
from srunner.scenarios.signalized_junction_left_turn import *
from srunner.scenarios.signalized_junction_right_turn import *
from srunner.scenarios.basic_scenario import BasicScenario
from srunner.scenarios.open_scenario import OpenScenario
from srunner.tools.config_parser import *
from srunner.tools.openscenario_parser import OpenScenarioConfiguration
# Version of scenario_runner
VERSION = 0.5
# Dictionary of all supported scenarios.
# key = Name of config file in Configs/
# value = List as defined in the scenario module
SCENARIOS = {
"BackgroundActivity": BACKGROUND_ACTIVITY_SCENARIOS,
"FollowLeadingVehicle": FOLLOW_LEADING_VEHICLE_SCENARIOS,
"ObjectCrossing": OBJECT_CROSSING_SCENARIOS,
"RunningRedLight": RUNNING_RED_LIGHT_SCENARIOS,
"NoSignalJunction": NO_SIGNAL_JUNCTION_SCENARIOS,
"VehicleTurning": VEHICLE_TURNING_SCENARIOS,
"ControlLoss": CONTROL_LOSS_SCENARIOS,
"OppositeDirection": MANEUVER_OPPOSITE_DIRECTION,
"OtherLeadingVehicle": OTHER_LEADING_VEHICLE_SCENARIOS,
"SignalizedJunctionRightTurn": TURNING_RIGHT_SIGNALIZED_JUNCTION_SCENARIOS,
"SignalizedJunctionLeftTurn": TURN_LEFT_SIGNALIZED_JUNCTION_SCENARIOS,
"MasterScenario": MASTER_SCENARIO
}
class ScenarioRunner(object):
"""
This is the core scenario runner module. It is responsible for
running (and repeating) a single scenario or a list of scenarios.
Usage:
scenario_runner = ScenarioRunner(args)
scenario_runner.run(args)
del scenario_runner
"""
ego_vehicles = []
# Tunable parameters
client_timeout = 30.0 # in seconds
wait_for_world = 20.0 # in seconds
# CARLA world and scenario handlers
world = None
manager = None
additional_scenario_module = None
def __init__(self, args):
"""
Setup CARLA client and world
Setup ScenarioManager
"""
# First of all, we need to create the client that will send the requests
# to the simulator. Here we'll assume the simulator is accepting
# requests in the localhost at port 2000.
self.client = carla.Client(args.host, int(args.port))
self.client.set_timeout(self.client_timeout)
# Once we have a client we can retrieve the world that is currently
# running.
self.world = self.client.get_world()
CarlaDataProvider.set_world(self.world)
# Load additional scenario definitions, if there are any
if args.additionalScenario != '':
module_name = os.path.basename(args.additionalScenario).split('.')[0]
sys.path.insert(0, os.path.dirname(args.additionalScenario))
self.additional_scenario_module = importlib.import_module(module_name)
def __del__(self):
"""
Cleanup and delete actors, ScenarioManager and CARLA world
"""
self.cleanup(True)
if self.manager is not None:
del self.manager
if self.world is not None:
del self.world
def get_scenario_class_or_fail(self, scenario):
"""
Get scenario class by scenario name
If scenario is not supported or not found, exit script
"""
for scenarios in SCENARIOS.values():
if scenario in scenarios:
if scenario in globals():
return globals()[scenario]
for member in inspect.getmembers(self.additional_scenario_module):
if scenario in member and inspect.isclass(member[1]):
return member[1]
print("Scenario '{}' not supported ... Exiting".format(scenario))
sys.exit(-1)
def cleanup(self, ego=False):
"""
Remove and destroy all actors
"""
CarlaDataProvider.cleanup()
CarlaActorPool.cleanup()
for i, _ in enumerate(self.ego_vehicles):
if self.ego_vehicles[i]:
if ego:
self.ego_vehicles[i].destroy()
self.ego_vehicles[i] = None
self.ego_vehicles = []
def prepare_ego_vehicles(self, config, wait_for_ego_vehicles=False):
"""
Spawn or update the ego vehicle according to
its parameters provided in config
As the world is re-loaded for every scenario, no ego exists so far
"""
if not wait_for_ego_vehicles:
for vehicle in config.ego_vehicles:
self.ego_vehicles.append(CarlaActorPool.setup_actor(vehicle.model,
vehicle.transform,
vehicle.rolename,
True))
else:
ego_vehicle_missing = True
while ego_vehicle_missing:
self.ego_vehicles = []
ego_vehicle_missing = False
for ego_vehicle in config.ego_vehicles:
ego_vehicle_found = False
carla_vehicles = CarlaDataProvider.get_world().get_actors().filter('vehicle.*')
for carla_vehicle in carla_vehicles:
if carla_vehicle.attributes['role_name'] == ego_vehicle.rolename:
ego_vehicle_found = True
self.ego_vehicles.append(carla_vehicle)
break
if not ego_vehicle_found:
ego_vehicle_missing = True
break
for i, _ in enumerate(self.ego_vehicles):
self.ego_vehicles[i].set_transform(config.ego_vehicles[i].transform)
# sync state
CarlaDataProvider.get_world().wait_for_tick()
def analyze_scenario(self, args, config):
"""
Provide feedback about success/failure of a scenario
"""
current_time = str(datetime.now().strftime('%Y-%m-%d-%H-%M-%S'))
junit_filename = None
config_name = config.name
if args.outputDir != '':
config_name = os.path.join(args.outputDir, config_name)
if args.junit:
junit_filename = config_name + current_time + ".xml"
filename = None
if args.file:
filename = config_name + current_time + ".txt"
if not self.manager.analyze_scenario(args.output, filename, junit_filename):
print("Success!")
else:
print("Failure!")
def run(self, args):
"""
Run all scenarios according to provided commandline args
"""
if args.openscenario:
self.run_openscenario(args)
return
# Setup and run the scenarios for repetition times
for _ in range(int(args.repetitions)):
# Load the scenario configurations provided in the config file
scenario_configurations = None
scenario_config_file = find_scenario_config(args.scenario, args.configFile)
if scenario_config_file is None:
print("Configuration for scenario {} cannot be found!".format(args.scenario))
continue
scenario_configurations = parse_scenario_configuration(scenario_config_file, args.scenario)
# Execute each configuration
config_counter = 0
for config in scenario_configurations:
if args.reloadWorld:
self.world = self.client.load_world(config.town)
else:
if CarlaDataProvider.get_map().name != config.town:
print("The CARLA server uses the wrong map!")
print("This scenario requires to use map {}".format(config.town))
self.cleanup()
continue
CarlaActorPool.set_client(self.client)
CarlaDataProvider.set_world(self.world)
# Wait for the world to be ready
self.world.wait_for_tick(self.wait_for_world)
# Create scenario manager
self.manager = ScenarioManager(self.world, args.debug)
# Prepare scenario
print("Preparing scenario: " + config.name)
scenario_class = self.get_scenario_class_or_fail(config.type)
try:
CarlaActorPool.set_world(self.world)
self.prepare_ego_vehicles(config, args.waitForEgo or (config_counter > 0))
scenario = scenario_class(self.world,
self.ego_vehicles,
config,
args.randomize,
args.debug)
except Exception as exception:
print("The scenario cannot be loaded")
if args.debug:
traceback.print_exc()
print(exception)
self.cleanup()
config_counter += 1
continue
# Load scenario and run it
self.manager.load_scenario(scenario)
self.manager.run_scenario()
# Provide outputs if required
self.analyze_scenario(args, config)
# Stop scenario and cleanup
self.manager.stop_scenario()
scenario.remove_all_actors()
self.cleanup()
config_counter += 1
self.cleanup(ego=(not args.waitForEgo))
print("No more scenarios .... Exiting")
def run_openscenario(self, args):
"""
Run openscenario
"""
# Load the scenario configurations provided in the config file
if not os.path.isfile(args.openscenario):
print("File does not exist")
self.cleanup()
return
CarlaActorPool.set_client(self.client)
CarlaDataProvider.set_world(self.world)
config = OpenScenarioConfiguration(args.openscenario)
if args.reloadWorld:
self.world = self.client.load_world(config.town)
else:
if CarlaDataProvider.get_map().name != config.town:
print("The CARLA server uses the wrong map!")
print("This scenario requires to use map {}".format(config.town))
self.cleanup()
return
# Wait for the world to be ready
self.world.wait_for_tick(self.wait_for_world)
# Create scenario manager
self.manager = ScenarioManager(self.world, args.debug)
# Prepare scenario
print("Preparing scenario: " + config.name)
try:
CarlaActorPool.set_world(self.world)
self.prepare_ego_vehicles(config, args.waitForEgo)
scenario = OpenScenario(world=self.world,
ego_vehicles=self.ego_vehicles,
config=config,
config_file=args.openscenario,
timeout=100000)
except Exception as exception:
print("The scenario cannot be loaded")
if args.debug:
traceback.print_exc()
print(exception)
self.cleanup()
return
# Load scenario and run it
self.manager.load_scenario(scenario)
self.manager.run_scenario()
# Provide outputs if required
self.analyze_scenario(args, config)
# Stop scenario and cleanup
self.manager.stop_scenario()
scenario.remove_all_actors()
self.cleanup(ego=(not args.waitForEgo))
print("No more scenarios .... Exiting")
if __name__ == '__main__':
DESCRIPTION = ("CARLA Scenario Runner: Setup, Run and Evaluate scenarios using CARLA\n"
"Current version: " + str(VERSION))
PARSER = argparse.ArgumentParser(description=DESCRIPTION,
formatter_class=RawTextHelpFormatter)
PARSER.add_argument('--host', default='127.0.0.1',
help='IP of the host server (default: localhost)')
PARSER.add_argument('--port', default='2000',
help='TCP port to listen to (default: 2000)')
PARSER.add_argument('--debug', action="store_true", help='Run with debug output')
PARSER.add_argument('--output', action="store_true", help='Provide results on stdout')
PARSER.add_argument('--file', action="store_true", help='Write results into a txt file')
PARSER.add_argument('--junit', action="store_true", help='Write results into a junit file')
PARSER.add_argument('--outputDir', default='', help='Directory for output files (default: this directory)')
PARSER.add_argument('--waitForEgo', action="store_true", help='Connect the scenario to an existing ego vehicle')
PARSER.add_argument('--configFile', default='', help='Provide an additional scenario configuration file (*.xml)')
PARSER.add_argument('--additionalScenario', default='', help='Provide additional scenario implementations (*.py)')
PARSER.add_argument('--reloadWorld', action="store_true",
help='Reload the CARLA world before starting a scenario (default=True)')
# pylint: disable=line-too-long
PARSER.add_argument(
'--scenario', help='Name of the scenario to be executed. Use the preposition \'group:\' to run all scenarios of one class, e.g. ControlLoss or FollowLeadingVehicle')
# pylint: enable=line-too-long
PARSER.add_argument('--randomize', action="store_true", help='Scenario parameters are randomized')
PARSER.add_argument('--repetitions', default=1, help='Number of scenario executions')
PARSER.add_argument('--list', action="store_true", help='List all supported scenarios and exit')
PARSER.add_argument('--listClass', action="store_true", help='List all supported scenario classes and exit')
PARSER.add_argument('--openscenario', help='Provide an OpenScenario definition')
PARSER.add_argument('-v', '--version', action='version', version='%(prog)s ' + str(VERSION))
ARGUMENTS = PARSER.parse_args()
if ARGUMENTS.list:
print("Currently the following scenarios are supported:")
print(*get_list_of_scenarios(ARGUMENTS.configFile), sep='\n')
sys.exit(0)
if ARGUMENTS.listClass:
print("Currently the following scenario classes are supported:")
print(*SCENARIOS.keys(), sep='\n')
sys.exit(0)
if not ARGUMENTS.scenario and not ARGUMENTS.openscenario:
print("Please specify a scenario using '--scenario SCENARIONAME'\n\n")
PARSER.print_help(sys.stdout)
sys.exit(0)
SCENARIORUNNER = None
try:
SCENARIORUNNER = ScenarioRunner(ARGUMENTS)
SCENARIORUNNER.run(ARGUMENTS)
finally:
if SCENARIORUNNER is not None:
del SCENARIORUNNER