scenario_manager.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #!/usr/bin/env python
  2. # Copyright (c) 2018-2020 Intel Corporation
  3. #
  4. # This work is licensed under the terms of the MIT license.
  5. # For a copy, see <https://opensource.org/licenses/MIT>.
  6. """
  7. This module provides the ScenarioManager implementation.
  8. It must not be modified and is for reference only!
  9. """
  10. from __future__ import print_function
  11. import sys
  12. import time
  13. import py_trees
  14. from srunner.autoagents.agent_wrapper import AgentWrapper
  15. from srunner.scenariomanager.carla_data_provider import CarlaDataProvider
  16. from srunner.scenariomanager.result_writer import ResultOutputProvider
  17. from srunner.scenariomanager.timer import GameTime
  18. from srunner.scenariomanager.watchdog import Watchdog
  19. class ScenarioManager(object):
  20. """
  21. Basic scenario manager class. This class holds all functionality
  22. required to start, and analyze a scenario.
  23. The user must not modify this class.
  24. To use the ScenarioManager:
  25. 1. Create an object via manager = ScenarioManager()
  26. 2. Load a scenario via manager.load_scenario()
  27. 3. Trigger the execution of the scenario manager.run_scenario()
  28. This function is designed to explicitly control start and end of
  29. the scenario execution
  30. 4. Trigger a result evaluation with manager.analyze_scenario()
  31. 5. If needed, cleanup with manager.stop_scenario()
  32. """
  33. def __init__(self, debug_mode=False, sync_mode=False, timeout=2.0):
  34. """
  35. Setups up the parameters, which will be filled at load_scenario()
  36. """
  37. self.scenario = None
  38. self.scenario_tree = None
  39. self.scenario_class = None
  40. self.ego_vehicles = None
  41. self.other_actors = None
  42. self._debug_mode = debug_mode
  43. self._agent = None
  44. self._sync_mode = sync_mode
  45. self._watchdog = None
  46. self._timeout = timeout
  47. self._running = False
  48. self._timestamp_last_run = 0.0
  49. self.scenario_duration_system = 0.0
  50. self.scenario_duration_game = 0.0
  51. self.start_system_time = None
  52. self.end_system_time = None
  53. def _reset(self):
  54. """
  55. Reset all parameters
  56. """
  57. self._running = False
  58. self._timestamp_last_run = 0.0
  59. self.scenario_duration_system = 0.0
  60. self.scenario_duration_game = 0.0
  61. self.start_system_time = None
  62. self.end_system_time = None
  63. GameTime.restart()
  64. def cleanup(self):
  65. """
  66. This function triggers a proper termination of a scenario
  67. """
  68. if self._watchdog is not None:
  69. self._watchdog.stop()
  70. self._watchdog = None
  71. if self.scenario is not None:
  72. self.scenario.terminate()
  73. if self._agent is not None:
  74. self._agent.cleanup()
  75. self._agent = None
  76. CarlaDataProvider.cleanup()
  77. def load_scenario(self, scenario, agent=None):
  78. """
  79. Load a new scenario
  80. """
  81. self._reset()
  82. self._agent = AgentWrapper(agent) if agent else None
  83. if self._agent is not None:
  84. self._sync_mode = True
  85. self.scenario_class = scenario
  86. self.scenario = scenario.scenario
  87. self.scenario_tree = self.scenario.scenario_tree
  88. self.ego_vehicles = scenario.ego_vehicles
  89. self.other_actors = scenario.other_actors
  90. # To print the scenario tree uncomment the next line
  91. # py_trees.display.render_dot_tree(self.scenario_tree)
  92. if self._agent is not None:
  93. self._agent.setup_sensors(self.ego_vehicles[0], self._debug_mode)
  94. def run_scenario(self):
  95. """
  96. Trigger the start of the scenario and wait for it to finish/fail
  97. """
  98. print("ScenarioManager: Running scenario {}".format(self.scenario_tree.name))
  99. self.start_system_time = time.time()
  100. start_game_time = GameTime.get_time()
  101. self._watchdog = Watchdog(float(self._timeout))
  102. self._watchdog.start()
  103. self._running = True
  104. while self._running:
  105. timestamp = None
  106. world = CarlaDataProvider.get_world()
  107. if world:
  108. snapshot = world.get_snapshot()
  109. if snapshot:
  110. timestamp = snapshot.timestamp
  111. if timestamp:
  112. self._tick_scenario(timestamp)
  113. self.cleanup()
  114. self.end_system_time = time.time()
  115. end_game_time = GameTime.get_time()
  116. self.scenario_duration_system = self.end_system_time - \
  117. self.start_system_time
  118. self.scenario_duration_game = end_game_time - start_game_time
  119. if self.scenario_tree.status == py_trees.common.Status.FAILURE:
  120. print("ScenarioManager: Terminated due to failure")
  121. def _tick_scenario(self, timestamp):
  122. """
  123. Run next tick of scenario and the agent.
  124. If running synchornously, it also handles the ticking of the world.
  125. """
  126. if self._timestamp_last_run < timestamp.elapsed_seconds and self._running:
  127. self._timestamp_last_run = timestamp.elapsed_seconds
  128. self._watchdog.update()
  129. if self._debug_mode:
  130. print("\n--------- Tick ---------\n")
  131. # Update game time and actor information
  132. GameTime.on_carla_tick(timestamp)
  133. CarlaDataProvider.on_carla_tick()
  134. if self._agent is not None:
  135. ego_action = self._agent() # pylint: disable=not-callable
  136. if self._agent is not None:
  137. self.ego_vehicles[0].apply_control(ego_action)
  138. # Tick scenario
  139. self.scenario_tree.tick_once()
  140. if self._debug_mode:
  141. print("\n")
  142. py_trees.display.print_ascii_tree(self.scenario_tree, show_status=True)
  143. sys.stdout.flush()
  144. if self.scenario_tree.status != py_trees.common.Status.RUNNING:
  145. self._running = False
  146. if self._sync_mode and self._running and self._watchdog.get_status():
  147. CarlaDataProvider.get_world().tick()
  148. def get_running_status(self):
  149. """
  150. returns:
  151. bool: False if watchdog exception occured, True otherwise
  152. """
  153. return self._watchdog.get_status()
  154. def stop_scenario(self):
  155. """
  156. This function is used by the overall signal handler to terminate the scenario execution
  157. """
  158. self._running = False
  159. def analyze_scenario(self, stdout, filename, junit, json):
  160. """
  161. This function is intended to be called from outside and provide
  162. the final statistics about the scenario (human-readable, in form of a junit
  163. report, etc.)
  164. """
  165. failure = False
  166. timeout = False
  167. result = "SUCCESS"
  168. if self.scenario.test_criteria is None:
  169. print("Nothing to analyze, this scenario has no criteria")
  170. return True
  171. for criterion in self.scenario.get_criteria():
  172. if (not criterion.optional and
  173. criterion.test_status != "SUCCESS" and
  174. criterion.test_status != "ACCEPTABLE"):
  175. failure = True
  176. result = "FAILURE"
  177. elif criterion.test_status == "ACCEPTABLE":
  178. result = "ACCEPTABLE"
  179. if self.scenario.timeout_node.timeout and not failure:
  180. timeout = True
  181. result = "TIMEOUT"
  182. output = ResultOutputProvider(self, result, stdout, filename, junit, json)
  183. output.write()
  184. return failure or timeout