def analyze_scenario(self, stdout, filename, junit):
        """
        This function is intended to be called from outside and provide
        the final statistics about the scenario (human-readable, in form of a junit
        report, etc.)
        """

        failure = False
        timeout = False
        result = "SUCCESS"

        if self.scenario.test_criteria is None:
            return True

        for criterion in self.scenario.get_criteria():
            if (not criterion.optional and criterion.test_status != "SUCCESS"
                    and criterion.test_status != "ACCEPTABLE"):
                failure = True
                result = "FAILURE"
            elif criterion.test_status == "ACCEPTABLE":
                result = "ACCEPTABLE"

        if self.scenario.timeout_node.timeout and not failure:
            timeout = True
            result = "TIMEOUT"

        output = ResultOutputProvider(self, result, stdout, filename, junit)
        output.write()

        if self._challenge_mode:
            ChallengeStatisticsManager.record_scenario_statistics()

        return failure or timeout
    def _tick_scenario(self, timestamp):
        """
        Run next tick of scenario
        This function is a callback for world.on_tick()

        Important:
        - It has to be ensured that the scenario has not yet completed/failed
          and that the time moved forward.
        - A thread lock should be used to avoid that the scenario tick is performed
          multiple times in parallel.
        """

        if self._timestamp_last_run < timestamp.elapsed_seconds and self._running:
            self._timestamp_last_run = timestamp.elapsed_seconds

            self._watchdog.update()

            if self._debug_mode:
                print("\n--------- Tick ---------\n")

            # Update game time and actor information
            GameTime.on_carla_tick(timestamp)
            CarlaDataProvider.on_carla_tick()

            if self._agent is not None:
                ego_action = self._agent()

            # Tick scenario
            self.scenario_tree.tick_once()

            if self._debug_mode:
                print("\n")
                py_trees.display.print_ascii_tree(self.scenario_tree,
                                                  show_status=True)
                sys.stdout.flush()

            if self.scenario_tree.status != py_trees.common.Status.RUNNING:
                self._running = False

            if self._challenge_mode:
                ChallengeStatisticsManager.compute_current_statistics()

            if self._agent is not None:
                self.ego_vehicles[0].apply_control(ego_action)

        if self._agent and self._running and self._watchdog.get_status():
            CarlaDataProvider.perform_carla_tick(self._timeout)
Example #3
0
    def load_scenario(self, scenario, agent=None):
        """
        Load a new scenario
        """
        self._reset()
        self._agent = AgentWrapper(agent, self._challenge_mode) if agent else None
        self.scenario_class = scenario
        self.scenario = scenario.scenario
        self.scenario_tree = self.scenario.scenario_tree
        self.ego_vehicles = scenario.ego_vehicles
        self.other_actors = scenario.other_actors

        CarlaDataProvider.register_actors(self.ego_vehicles)
        CarlaDataProvider.register_actors(self.other_actors)
        # To print the scenario tree uncomment the next line
        # py_trees.display.render_dot_tree(self.scenario_tree)

        if self._challenge_mode:
            ChallengeStatisticsManager.next_scenario(self.scenario)

        if self._agent is not None:
            self._agent.setup_sensors(self.ego_vehicles[0], self._debug_mode)
Example #4
0
def main():
    """
    main function
    """
    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'
    )
    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(
        '--agent',
        help=
        "Agent used to execute the scenario (optional). Currently only compatible with route-based scenarios."
    )
    parser.add_argument('--agentConfig',
                        type=str,
                        help="Path to Agent's configuration file",
                        default="")
    parser.add_argument('--openscenario',
                        help='Provide an OpenSCENARIO definition')
    parser.add_argument(
        '--route',
        help=
        'Run a route as a scenario, similar to the CARLA AD challenge (input: (route_file,scenario_file,[number of route]))',
        nargs='+',
        type=str)
    parser.add_argument('--challenge',
                        action="store_true",
                        help='Run in challenge mode')
    parser.add_argument(
        '--record',
        action="store_true",
        help='Use CARLA recording feature to create a recording of the scenario'
    )
    parser.add_argument('--timeout',
                        default="10.0",
                        help='Set the CARLA client timeout value in seconds')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version='%(prog)s ' + str(VERSION))
    arguments = parser.parse_args()
    # pylint: enable=line-too-long

    if arguments.list:
        print("Currently the following scenarios are supported:")
        print(*ScenarioConfigurationParser.get_list_of_scenarios(
            arguments.configFile),
              sep='\n')
        return 1

    if not arguments.scenario and not arguments.openscenario and not arguments.route:
        print("Please specify either a scenario or use the route mode\n\n")
        parser.print_help(sys.stdout)
        return 1

    if (arguments.route
            and arguments.openscenario) or (arguments.route
                                            and arguments.scenario):
        print(
            "The route mode cannot be used together with a scenario (incl. OpenSCENARIO)'\n\n"
        )
        parser.print_help(sys.stdout)
        return 1

    if arguments.agent and (arguments.openscenario or arguments.scenario):
        print("Agents are currently only compatible with route scenarios'\n\n")
        parser.print_help(sys.stdout)
        return 1

    if arguments.challenge and (arguments.openscenario or arguments.scenario):
        print(
            "The challenge mode can only be used with route-based scenarios'\n\n"
        )
        parser.print_help(sys.stdout)
        return 1

    if arguments.route:
        arguments.reloadWorld = True

    scenario_runner = None
    result = True
    try:
        scenario_runner = ScenarioRunner(arguments)
        result = scenario_runner.run()

    finally:
        if arguments.challenge:
            ChallengeStatisticsManager.report_challenge_statistics(
                'results.json', arguments.debug)
        if scenario_runner is not None:
            scenario_runner.destroy()
            del scenario_runner
    return not result
Example #5
0
    def _run_challenge(self):
        """
        Run the challenge mode
        """
        result = False
        phase_codename = os.getenv('CHALLENGE_PHASE_CODENAME', 'dev_track_3')
        phase = phase_codename.split("_")[0]

        repetitions = self._args.repetitions

        if self._args.challenge:
            weather_profiles = CarlaDataProvider.find_weather_presets()
            scenario_runner_root = os.getenv('ROOT_SCENARIO_RUNNER', "./")

            if phase == 'dev':
                routes = '{}/srunner/challenge/routes_devtest.xml'.format(
                    scenario_runner_root)
                repetitions = 1
            elif phase == 'validation':
                routes = '{}/srunner/challenge/routes_testprep.xml'.format(
                    scenario_runner_root)
                repetitions = 3
            elif phase == 'test':
                routes = '{}/srunner/challenge/routes_testchallenge.xml'.format(
                    scenario_runner_root)
                repetitions = 3
            else:
                # debug mode
                routes = '{}/srunner/challenge/routes_debug.xml'.format(
                    scenario_runner_root)
                repetitions = 1

        if self._args.route:
            routes = self._args.route[0]
            scenario_file = self._args.route[1]
            single_route = None
            if len(self._args.route) > 2:
                single_route = self._args.route[2]

        # retrieve routes
        route_descriptions_list = RouteParser.parse_routes_file(
            routes, single_route)
        # find and filter potential scenarios for each of the evaluated routes
        # For each of the routes and corresponding possible scenarios to be evaluated.
        if self._args.challenge:
            n_routes = len(route_descriptions_list) * repetitions
            ChallengeStatisticsManager.set_number_of_scenarios(n_routes)

        for _, route_description in enumerate(route_descriptions_list):
            for repetition in range(repetitions):

                if self._args.challenge and not self._within_available_time():
                    error_message = 'Not enough simulation time available to continue'
                    print(error_message)
                    ChallengeStatisticsManager.record_fatal_error(
                        error_message)
                    self._cleanup()
                    return False

                config = RouteScenarioConfiguration(route_description,
                                                    scenario_file)

                if self._args.challenge:
                    profile = weather_profiles[repetition %
                                               len(weather_profiles)]
                    config.weather = profile[0]
                    config.weather.sun_azimuth_angle = -1
                    config.weather.sun_altitude_angle = -1

                result = self._load_and_run_scenario(config)
                self._cleanup()
        return result
Example #6
0
    def _load_and_run_scenario(self, config):
        """
        Load and run the scenario given by config
        """
        result = False
        if not self._load_and_wait_for_world(config.town, config.ego_vehicles):
            self._cleanup()
            return False

        if self._args.agent:
            agent_class_name = self.module_agent.__name__.title().replace(
                '_', '')
            try:
                self.agent_instance = getattr(self.module_agent,
                                              agent_class_name)(
                                                  self._args.agentConfig)
                config.agent = self.agent_instance
            except Exception as e:  # pylint: disable=broad-except
                traceback.print_exc()
                print("Could not setup required agent due to {}".format(e))
                self._cleanup()
                return False

        # Prepare scenario
        print("Preparing scenario: " + config.name)
        try:
            self._prepare_ego_vehicles(config.ego_vehicles)
            if self._args.openscenario:
                scenario = OpenScenario(world=self.world,
                                        ego_vehicles=self.ego_vehicles,
                                        config=config,
                                        config_file=self._args.openscenario,
                                        timeout=100000)
            elif self._args.route:
                scenario = RouteScenario(world=self.world,
                                         config=config,
                                         debug_mode=self._args.debug)
            else:
                scenario_class = self._get_scenario_class_or_fail(config.type)
                scenario = scenario_class(self.world, self.ego_vehicles,
                                          config, self._args.randomize,
                                          self._args.debug)
        except Exception as exception:  # pylint: disable=broad-except
            print("The scenario cannot be loaded")
            traceback.print_exc()
            print(exception)
            self._cleanup()
            return False

        # Set the appropriate weather conditions
        self.world.set_weather(config.weather)

        # Set the appropriate road friction
        if config.friction is not None:
            friction_bp = self.world.get_blueprint_library().find(
                'static.trigger.friction')
            extent = carla.Location(1000000.0, 1000000.0, 1000000.0)
            friction_bp.set_attribute('friction', str(config.friction))
            friction_bp.set_attribute('extent_x', str(extent.x))
            friction_bp.set_attribute('extent_y', str(extent.y))
            friction_bp.set_attribute('extent_z', str(extent.z))

            # Spawn Trigger Friction
            transform = carla.Transform()
            transform.location = carla.Location(-10000.0, -10000.0, 0.0)
            self.world.spawn_actor(friction_bp, transform)

        try:
            # Load scenario and run it
            if self._args.record:
                self.client.start_recorder("{}/{}.log".format(
                    os.getenv('ROOT_SCENARIO_RUNNER', "./"), config.name))
            self.manager.load_scenario(scenario, self.agent_instance)
            self.manager.run_scenario()

            # Provide outputs if required
            self._analyze_scenario(config)

            # Remove all actors
            scenario.remove_all_actors()

            result = True
        except SensorConfigurationInvalid as e:
            self._cleanup()
            ChallengeStatisticsManager.record_fatal_error(e)
            sys.exit(-1)

        except Exception as e:  # pylint: disable=broad-except
            traceback.print_exc()
            if self._args.challenge:
                ChallengeStatisticsManager.set_error_message(
                    traceback.format_exc())
            print(e)
            result = False

        self._cleanup()
        return result
Example #7
0
            "The route mode cannot be used together with a scenario (incl. OpenSCENARIO)'\n\n"
        )
        PARSER.print_help(sys.stdout)
        sys.exit(0)

    if ARGUMENTS.agent and (ARGUMENTS.openscenario or ARGUMENTS.scenario):
        print("Agents are currently only compatible with route scenarios'\n\n")
        PARSER.print_help(sys.stdout)
        sys.exit(0)

    if ARGUMENTS.challenge and (ARGUMENTS.openscenario or ARGUMENTS.scenario):
        print(
            "The challenge mode can only be used with route-based scenarios'\n\n"
        )
        PARSER.print_help(sys.stdout)
        sys.exit(0)

    if ARGUMENTS.route:
        ARGUMENTS.reloadWorld = True

    SCENARIORUNNER = None
    try:
        SCENARIORUNNER = ScenarioRunner(ARGUMENTS)
        SCENARIORUNNER.run(ARGUMENTS)
    finally:
        if ARGUMENTS.challenge:
            ChallengeStatisticsManager.report_challenge_statistics(
                'results.json', ARGUMENTS.debug)
        if SCENARIORUNNER is not None:
            del SCENARIORUNNER
Example #8
0
    def _load_and_run_scenario(self, args, config):
        """
        Load and run the scenario given by config
        """

        if not self._load_and_wait_for_world(args, config.town,
                                             config.ego_vehicles):
            self._cleanup()
            return

        if args.agent:
            agent_class_name = self.module_agent.__name__.title().replace(
                '_', '')
            try:
                self.agent_instance = getattr(
                    self.module_agent, agent_class_name)(args.agentConfig)
                config.agent = self.agent_instance
            except Exception as e:
                print("Could not setup required agent due to {}".format(e))
                self._cleanup()
                return

        # Prepare scenario
        print("Preparing scenario: " + config.name)
        try:
            self._prepare_ego_vehicles(config.ego_vehicles, args.waitForEgo)
            if args.openscenario:
                scenario = OpenScenario(world=self.world,
                                        ego_vehicles=self.ego_vehicles,
                                        config=config,
                                        config_file=args.openscenario,
                                        timeout=100000)
            elif args.route:
                scenario = RouteScenario(world=self.world,
                                         config=config,
                                         debug_mode=args.debug)
            else:
                scenario_class = self._get_scenario_class_or_fail(config.type)
                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()
            return

        # Set the appropriate weather conditions
        weather = carla.WeatherParameters(
            cloudyness=config.weather.cloudyness,
            precipitation=config.weather.precipitation,
            precipitation_deposits=config.weather.precipitation_deposits,
            wind_intensity=config.weather.wind_intensity,
            sun_azimuth_angle=config.weather.sun_azimuth,
            sun_altitude_angle=config.weather.sun_altitude)

        self.world.set_weather(weather)

        try:
            # Load scenario and run it
            if args.record:
                self.client.start_recorder("{}/{}.log".format(
                    os.getenv('ROOT_SCENARIO_RUNNER', "./"), config.name))
            self.manager.load_scenario(scenario, self.agent_instance)
            self.manager.run_scenario()

            # Stop scenario
            self.manager.stop_scenario()

            # Provide outputs if required
            self._analyze_scenario(args, config)

            # Remove all actors
            scenario.remove_all_actors()
        except SensorConfigurationInvalid as e:
            self._cleanup(True)
            ChallengeStatisticsManager.record_fatal_error(e)
            sys.exit(-1)
        except Exception as e:
            if args.debug:
                traceback.print_exc()
            if args.challenge:
                ChallengeStatisticsManager.set_error_message(
                    traceback.format_exc())
            print(e)

        self._cleanup()