object_crash_intersection.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. #!/usr/bin/env python
  2. #
  3. # This work is licensed under the terms of the MIT license.
  4. # For a copy, see <https://opensource.org/licenses/MIT>.
  5. """
  6. Object crash with prior vehicle action scenario:
  7. The scenario realizes the user controlled ego vehicle
  8. moving along the road and encounters a cyclist ahead after taking a right or left turn.
  9. """
  10. from __future__ import print_function
  11. import math
  12. import py_trees
  13. import carla
  14. from srunner.scenariomanager.carla_data_provider import CarlaDataProvider
  15. from srunner.scenariomanager.scenarioatomics.atomic_behaviors import (ActorTransformSetter,
  16. ActorDestroy,
  17. KeepVelocity,
  18. HandBrakeVehicle)
  19. from srunner.scenariomanager.scenarioatomics.atomic_criteria import CollisionTest
  20. from srunner.scenariomanager.scenarioatomics.atomic_trigger_conditions import (InTriggerDistanceToLocationAlongRoute,
  21. InTriggerDistanceToVehicle,
  22. DriveDistance)
  23. from srunner.scenariomanager.timer import TimeOut
  24. from srunner.scenarios.basic_scenario import BasicScenario
  25. from srunner.tools.scenario_helper import generate_target_waypoint, generate_target_waypoint_in_route
  26. def get_opponent_transform(added_dist, waypoint, trigger_location):
  27. """
  28. Calculate the transform of the adversary
  29. """
  30. lane_width = waypoint.lane_width
  31. offset = {"orientation": 270, "position": 90, "k": 1.0}
  32. _wp = waypoint.next(added_dist)
  33. if _wp:
  34. _wp = _wp[-1]
  35. else:
  36. raise RuntimeError("Cannot get next waypoint !")
  37. location = _wp.transform.location
  38. orientation_yaw = _wp.transform.rotation.yaw + offset["orientation"]
  39. position_yaw = _wp.transform.rotation.yaw + offset["position"]
  40. offset_location = carla.Location(
  41. offset['k'] * lane_width * math.cos(math.radians(position_yaw)),
  42. offset['k'] * lane_width * math.sin(math.radians(position_yaw)))
  43. location += offset_location
  44. location.z = trigger_location.z
  45. transform = carla.Transform(location, carla.Rotation(yaw=orientation_yaw))
  46. return transform
  47. def get_right_driving_lane(waypoint):
  48. """
  49. Gets the driving / parking lane that is most to the right of the waypoint
  50. as well as the number of lane changes done
  51. """
  52. lane_changes = 0
  53. while True:
  54. wp_next = waypoint.get_right_lane()
  55. lane_changes += 1
  56. if wp_next is None or wp_next.lane_type == carla.LaneType.Sidewalk:
  57. break
  58. elif wp_next.lane_type == carla.LaneType.Shoulder:
  59. # Filter Parkings considered as Shoulders
  60. if is_lane_a_parking(wp_next):
  61. lane_changes += 1
  62. waypoint = wp_next
  63. break
  64. else:
  65. waypoint = wp_next
  66. return waypoint, lane_changes
  67. def is_lane_a_parking(waypoint):
  68. """
  69. This function filters false negative Shoulder which are in reality Parking lanes.
  70. These are differentiated from the others because, similar to the driving lanes,
  71. they have, on the right, a small Shoulder followed by a Sidewalk.
  72. """
  73. # Parking are wide lanes
  74. if waypoint.lane_width > 2:
  75. wp_next = waypoint.get_right_lane()
  76. # That are next to a mini-Shoulder
  77. if wp_next is not None and wp_next.lane_type == carla.LaneType.Shoulder:
  78. wp_next_next = wp_next.get_right_lane()
  79. # Followed by a Sidewalk
  80. if wp_next_next is not None and wp_next_next.lane_type == carla.LaneType.Sidewalk:
  81. return True
  82. return False
  83. class VehicleTurningRight(BasicScenario):
  84. """
  85. This class holds everything required for a simple object crash
  86. with prior vehicle action involving a vehicle and a cyclist.
  87. The ego vehicle is passing through a road and encounters
  88. a cyclist after taking a right turn. (Traffic Scenario 4)
  89. This is a single ego vehicle scenario
  90. """
  91. def __init__(self, world, ego_vehicles, config, randomize=False, debug_mode=False, criteria_enable=True,
  92. timeout=60):
  93. """
  94. Setup all relevant parameters and create scenario
  95. """
  96. self._other_actor_target_velocity = 10
  97. self._wmap = CarlaDataProvider.get_map()
  98. self._reference_waypoint = self._wmap.get_waypoint(config.trigger_points[0].location)
  99. self._trigger_location = config.trigger_points[0].location
  100. self._other_actor_transform = None
  101. self._num_lane_changes = 0
  102. # Timeout of scenario in seconds
  103. self.timeout = timeout
  104. # Total Number of attempts to relocate a vehicle before spawning
  105. self._number_of_attempts = 6
  106. # Number of attempts made so far
  107. self._spawn_attempted = 0
  108. self._ego_route = CarlaDataProvider.get_ego_vehicle_route()
  109. super(VehicleTurningRight, self).__init__("VehicleTurningRight",
  110. ego_vehicles,
  111. config,
  112. world,
  113. debug_mode,
  114. criteria_enable=criteria_enable)
  115. def _initialize_actors(self, config):
  116. """
  117. Custom initialization
  118. """
  119. # Get the waypoint right after the junction
  120. waypoint = generate_target_waypoint(self._reference_waypoint, 1)
  121. # Move a certain distance to the front
  122. start_distance = 8
  123. waypoint = waypoint.next(start_distance)[0]
  124. # Get the last driving lane to the right
  125. waypoint, self._num_lane_changes = get_right_driving_lane(waypoint)
  126. # And for synchrony purposes, move to the front a bit
  127. added_dist = self._num_lane_changes
  128. while True:
  129. # Try to spawn the actor
  130. try:
  131. self._other_actor_transform = get_opponent_transform(added_dist, waypoint, self._trigger_location)
  132. first_vehicle = CarlaDataProvider.request_new_actor(
  133. 'vehicle.diamondback.century', self._other_actor_transform)
  134. first_vehicle.set_simulate_physics(enabled=False)
  135. break
  136. # Move the spawning point a bit and try again
  137. except RuntimeError as r:
  138. # In the case there is an object just move a little bit and retry
  139. print(" Base transform is blocking objects ", self._other_actor_transform)
  140. added_dist += 0.5
  141. self._spawn_attempted += 1
  142. if self._spawn_attempted >= self._number_of_attempts:
  143. raise r
  144. # Set the transform to -500 z after we are able to spawn it
  145. actor_transform = carla.Transform(
  146. carla.Location(self._other_actor_transform.location.x,
  147. self._other_actor_transform.location.y,
  148. self._other_actor_transform.location.z - 500),
  149. self._other_actor_transform.rotation)
  150. first_vehicle.set_transform(actor_transform)
  151. first_vehicle.set_simulate_physics(enabled=False)
  152. self.other_actors.append(first_vehicle)
  153. def _create_behavior(self):
  154. """
  155. After invoking this scenario, cyclist will wait for the user
  156. controlled vehicle to enter the in the trigger distance region,
  157. the cyclist starts crossing the road once the condition meets,
  158. ego vehicle has to avoid the crash after a right turn, but
  159. continue driving after the road is clear.If this does not happen
  160. within 90 seconds, a timeout stops the scenario.
  161. """
  162. root = py_trees.composites.Parallel(
  163. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE, name="IntersectionRightTurn")
  164. lane_width = self._reference_waypoint.lane_width
  165. dist_to_travel = lane_width + (1.10 * lane_width * self._num_lane_changes)
  166. bycicle_start_dist = 13 + dist_to_travel
  167. if self._ego_route is not None:
  168. trigger_distance = InTriggerDistanceToLocationAlongRoute(self.ego_vehicles[0],
  169. self._ego_route,
  170. self._other_actor_transform.location,
  171. bycicle_start_dist)
  172. else:
  173. trigger_distance = InTriggerDistanceToVehicle(self.other_actors[0],
  174. self.ego_vehicles[0],
  175. bycicle_start_dist)
  176. actor_velocity = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  177. actor_traverse = DriveDistance(self.other_actors[0], 0.30 * dist_to_travel)
  178. post_timer_velocity_actor = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  179. post_timer_traverse_actor = DriveDistance(self.other_actors[0], 0.70 * dist_to_travel)
  180. end_condition = TimeOut(5)
  181. # non leaf nodes
  182. scenario_sequence = py_trees.composites.Sequence()
  183. actor_ego_sync = py_trees.composites.Parallel(
  184. "Synchronization of actor and ego vehicle",
  185. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  186. after_timer_actor = py_trees.composites.Parallel(
  187. "After timeout actor will cross the remaining lane_width",
  188. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  189. # building the tree
  190. root.add_child(scenario_sequence)
  191. scenario_sequence.add_child(ActorTransformSetter(self.other_actors[0], self._other_actor_transform,
  192. name='TransformSetterTS4'))
  193. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], True))
  194. scenario_sequence.add_child(trigger_distance)
  195. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], False))
  196. scenario_sequence.add_child(actor_ego_sync)
  197. scenario_sequence.add_child(after_timer_actor)
  198. scenario_sequence.add_child(end_condition)
  199. scenario_sequence.add_child(ActorDestroy(self.other_actors[0]))
  200. actor_ego_sync.add_child(actor_velocity)
  201. actor_ego_sync.add_child(actor_traverse)
  202. after_timer_actor.add_child(post_timer_velocity_actor)
  203. after_timer_actor.add_child(post_timer_traverse_actor)
  204. return root
  205. def _create_test_criteria(self):
  206. """
  207. A list of all test criteria will be created that is later used
  208. in parallel behavior tree.
  209. """
  210. criteria = []
  211. collision_criterion = CollisionTest(self.ego_vehicles[0])
  212. criteria.append(collision_criterion)
  213. return criteria
  214. def __del__(self):
  215. """
  216. Remove all actors upon deletion
  217. """
  218. self.remove_all_actors()
  219. class VehicleTurningLeft(BasicScenario):
  220. """
  221. This class holds everything required for a simple object crash
  222. with prior vehicle action involving a vehicle and a cyclist.
  223. The ego vehicle is passing through a road and encounters
  224. a cyclist after taking a left turn. (Traffic Scenario 4)
  225. This is a single ego vehicle scenario
  226. """
  227. def __init__(self, world, ego_vehicles, config, randomize=False, debug_mode=False, criteria_enable=True,
  228. timeout=60):
  229. """
  230. Setup all relevant parameters and create scenario
  231. """
  232. self._other_actor_target_velocity = 10
  233. self._wmap = CarlaDataProvider.get_map()
  234. self._reference_waypoint = self._wmap.get_waypoint(config.trigger_points[0].location)
  235. self._trigger_location = config.trigger_points[0].location
  236. self._other_actor_transform = None
  237. self._num_lane_changes = 0
  238. # Timeout of scenario in seconds
  239. self.timeout = timeout
  240. # Total Number of attempts to relocate a vehicle before spawning
  241. self._number_of_attempts = 6
  242. # Number of attempts made so far
  243. self._spawn_attempted = 0
  244. self._ego_route = CarlaDataProvider.get_ego_vehicle_route()
  245. super(VehicleTurningLeft, self).__init__("VehicleTurningLeft",
  246. ego_vehicles,
  247. config,
  248. world,
  249. debug_mode,
  250. criteria_enable=criteria_enable)
  251. def _initialize_actors(self, config):
  252. """
  253. Custom initialization
  254. """
  255. # Get the waypoint right after the junction
  256. waypoint = generate_target_waypoint(self._reference_waypoint, -1)
  257. # Move a certain distance to the front
  258. start_distance = 8
  259. waypoint = waypoint.next(start_distance)[0]
  260. # Get the last driving lane to the right
  261. waypoint, self._num_lane_changes = get_right_driving_lane(waypoint)
  262. # And for synchrony purposes, move to the front a bit
  263. added_dist = self._num_lane_changes
  264. while True:
  265. # Try to spawn the actor
  266. try:
  267. self._other_actor_transform = get_opponent_transform(added_dist, waypoint, self._trigger_location)
  268. first_vehicle = CarlaDataProvider.request_new_actor(
  269. 'vehicle.diamondback.century', self._other_actor_transform)
  270. first_vehicle.set_simulate_physics(enabled=False)
  271. break
  272. # Move the spawning point a bit and try again
  273. except RuntimeError as r:
  274. # In the case there is an object just move a little bit and retry
  275. print(" Base transform is blocking objects ", self._other_actor_transform)
  276. added_dist += 0.5
  277. self._spawn_attempted += 1
  278. if self._spawn_attempted >= self._number_of_attempts:
  279. raise r
  280. # Set the transform to -500 z after we are able to spawn it
  281. actor_transform = carla.Transform(
  282. carla.Location(self._other_actor_transform.location.x,
  283. self._other_actor_transform.location.y,
  284. self._other_actor_transform.location.z - 500),
  285. self._other_actor_transform.rotation)
  286. first_vehicle.set_transform(actor_transform)
  287. first_vehicle.set_simulate_physics(enabled=False)
  288. self.other_actors.append(first_vehicle)
  289. def _create_behavior(self):
  290. """
  291. After invoking this scenario, cyclist will wait for the user
  292. controlled vehicle to enter the in the trigger distance region,
  293. the cyclist starts crossing the road once the condition meets,
  294. ego vehicle has to avoid the crash after a left turn, but
  295. continue driving after the road is clear.If this does not happen
  296. within 90 seconds, a timeout stops the scenario.
  297. """
  298. root = py_trees.composites.Parallel(
  299. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE, name="IntersectionLeftTurn")
  300. lane_width = self._reference_waypoint.lane_width
  301. dist_to_travel = lane_width + (1.10 * lane_width * self._num_lane_changes)
  302. bycicle_start_dist = 13 + dist_to_travel
  303. if self._ego_route is not None:
  304. trigger_distance = InTriggerDistanceToLocationAlongRoute(self.ego_vehicles[0],
  305. self._ego_route,
  306. self._other_actor_transform.location,
  307. bycicle_start_dist)
  308. else:
  309. trigger_distance = InTriggerDistanceToVehicle(self.other_actors[0],
  310. self.ego_vehicles[0],
  311. bycicle_start_dist)
  312. actor_velocity = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  313. actor_traverse = DriveDistance(self.other_actors[0], 0.30 * dist_to_travel)
  314. post_timer_velocity_actor = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  315. post_timer_traverse_actor = DriveDistance(self.other_actors[0], 0.70 * dist_to_travel)
  316. end_condition = TimeOut(5)
  317. # non leaf nodes
  318. scenario_sequence = py_trees.composites.Sequence()
  319. actor_ego_sync = py_trees.composites.Parallel(
  320. "Synchronization of actor and ego vehicle",
  321. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  322. after_timer_actor = py_trees.composites.Parallel(
  323. "After timeout actor will cross the remaining lane_width",
  324. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  325. # building the tree
  326. root.add_child(scenario_sequence)
  327. scenario_sequence.add_child(ActorTransformSetter(self.other_actors[0], self._other_actor_transform,
  328. name='TransformSetterTS4'))
  329. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], True))
  330. scenario_sequence.add_child(trigger_distance)
  331. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], False))
  332. scenario_sequence.add_child(actor_ego_sync)
  333. scenario_sequence.add_child(after_timer_actor)
  334. scenario_sequence.add_child(end_condition)
  335. scenario_sequence.add_child(ActorDestroy(self.other_actors[0]))
  336. actor_ego_sync.add_child(actor_velocity)
  337. actor_ego_sync.add_child(actor_traverse)
  338. after_timer_actor.add_child(post_timer_velocity_actor)
  339. after_timer_actor.add_child(post_timer_traverse_actor)
  340. return root
  341. def _create_test_criteria(self):
  342. """
  343. A list of all test criteria will be created that is later used
  344. in parallel behavior tree.
  345. """
  346. criteria = []
  347. collision_criterion = CollisionTest(self.ego_vehicles[0])
  348. criteria.append(collision_criterion)
  349. return criteria
  350. def __del__(self):
  351. """
  352. Remove all actors upon deletion
  353. """
  354. self.remove_all_actors()
  355. class VehicleTurningRoute(BasicScenario):
  356. """
  357. This class holds everything required for a simple object crash
  358. with prior vehicle action involving a vehicle and a cyclist.
  359. The ego vehicle is passing through a road and encounters
  360. a cyclist after taking a turn. This is the version used when the ego vehicle
  361. is following a given route. (Traffic Scenario 4)
  362. This is a single ego vehicle scenario
  363. """
  364. def __init__(self, world, ego_vehicles, config, randomize=False, debug_mode=False, criteria_enable=True,
  365. timeout=60):
  366. """
  367. Setup all relevant parameters and create scenario
  368. """
  369. self._other_actor_target_velocity = 10
  370. self._wmap = CarlaDataProvider.get_map()
  371. self._reference_waypoint = self._wmap.get_waypoint(config.trigger_points[0].location)
  372. self._trigger_location = config.trigger_points[0].location
  373. self._other_actor_transform = None
  374. self._num_lane_changes = 0
  375. # Timeout of scenario in seconds
  376. self.timeout = timeout
  377. # Total Number of attempts to relocate a vehicle before spawning
  378. self._number_of_attempts = 6
  379. # Number of attempts made so far
  380. self._spawn_attempted = 0
  381. self._ego_route = CarlaDataProvider.get_ego_vehicle_route()
  382. super(VehicleTurningRoute, self).__init__("VehicleTurningRoute",
  383. ego_vehicles,
  384. config,
  385. world,
  386. debug_mode,
  387. criteria_enable=criteria_enable)
  388. def _initialize_actors(self, config):
  389. """
  390. Custom initialization
  391. """
  392. # Get the waypoint right after the junction
  393. waypoint = generate_target_waypoint_in_route(self._reference_waypoint, self._ego_route)
  394. # Move a certain distance to the front
  395. start_distance = 8
  396. waypoint = waypoint.next(start_distance)[0]
  397. # Get the last driving lane to the right
  398. waypoint, self._num_lane_changes = get_right_driving_lane(waypoint)
  399. # And for synchrony purposes, move to the front a bit
  400. added_dist = self._num_lane_changes
  401. while True:
  402. # Try to spawn the actor
  403. try:
  404. self._other_actor_transform = get_opponent_transform(added_dist, waypoint, self._trigger_location)
  405. first_vehicle = CarlaDataProvider.request_new_actor(
  406. 'vehicle.diamondback.century', self._other_actor_transform)
  407. first_vehicle.set_simulate_physics(enabled=False)
  408. break
  409. # Move the spawning point a bit and try again
  410. except RuntimeError as r:
  411. # In the case there is an object just move a little bit and retry
  412. print(" Base transform is blocking objects ", self._other_actor_transform)
  413. added_dist += 0.5
  414. self._spawn_attempted += 1
  415. if self._spawn_attempted >= self._number_of_attempts:
  416. raise r
  417. # Set the transform to -500 z after we are able to spawn it
  418. actor_transform = carla.Transform(
  419. carla.Location(self._other_actor_transform.location.x,
  420. self._other_actor_transform.location.y,
  421. self._other_actor_transform.location.z - 500),
  422. self._other_actor_transform.rotation)
  423. first_vehicle.set_transform(actor_transform)
  424. first_vehicle.set_simulate_physics(enabled=False)
  425. self.other_actors.append(first_vehicle)
  426. def _create_behavior(self):
  427. """
  428. After invoking this scenario, cyclist will wait for the user
  429. controlled vehicle to enter the in the trigger distance region,
  430. the cyclist starts crossing the road once the condition meets,
  431. ego vehicle has to avoid the crash after a turn, but
  432. continue driving after the road is clear.If this does not happen
  433. within 90 seconds, a timeout stops the scenario.
  434. """
  435. root = py_trees.composites.Parallel(
  436. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE, name="IntersectionRouteTurn")
  437. lane_width = self._reference_waypoint.lane_width
  438. dist_to_travel = lane_width + (1.10 * lane_width * self._num_lane_changes)
  439. bycicle_start_dist = 13 + dist_to_travel
  440. if self._ego_route is not None:
  441. trigger_distance = InTriggerDistanceToLocationAlongRoute(self.ego_vehicles[0],
  442. self._ego_route,
  443. self._other_actor_transform.location,
  444. bycicle_start_dist)
  445. else:
  446. trigger_distance = InTriggerDistanceToVehicle(self.other_actors[0],
  447. self.ego_vehicles[0],
  448. bycicle_start_dist)
  449. actor_velocity = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  450. actor_traverse = DriveDistance(self.other_actors[0], 0.30 * dist_to_travel)
  451. post_timer_velocity_actor = KeepVelocity(self.other_actors[0], self._other_actor_target_velocity)
  452. post_timer_traverse_actor = DriveDistance(self.other_actors[0], 0.70 * dist_to_travel)
  453. end_condition = TimeOut(5)
  454. # non leaf nodes
  455. scenario_sequence = py_trees.composites.Sequence()
  456. actor_ego_sync = py_trees.composites.Parallel(
  457. "Synchronization of actor and ego vehicle",
  458. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  459. after_timer_actor = py_trees.composites.Parallel(
  460. "After timeout actor will cross the remaining lane_width",
  461. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ONE)
  462. # building the tree
  463. root.add_child(scenario_sequence)
  464. scenario_sequence.add_child(ActorTransformSetter(self.other_actors[0], self._other_actor_transform,
  465. name='TransformSetterTS4'))
  466. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], True))
  467. scenario_sequence.add_child(trigger_distance)
  468. scenario_sequence.add_child(HandBrakeVehicle(self.other_actors[0], False))
  469. scenario_sequence.add_child(actor_ego_sync)
  470. scenario_sequence.add_child(after_timer_actor)
  471. scenario_sequence.add_child(end_condition)
  472. scenario_sequence.add_child(ActorDestroy(self.other_actors[0]))
  473. actor_ego_sync.add_child(actor_velocity)
  474. actor_ego_sync.add_child(actor_traverse)
  475. after_timer_actor.add_child(post_timer_velocity_actor)
  476. after_timer_actor.add_child(post_timer_traverse_actor)
  477. return root
  478. def _create_test_criteria(self):
  479. """
  480. A list of all test criteria will be created that is later used
  481. in parallel behavior tree.
  482. """
  483. criteria = []
  484. collision_criterion = CollisionTest(self.ego_vehicles[0])
  485. criteria.append(collision_criterion)
  486. return criteria
  487. def __del__(self):
  488. """
  489. Remove all actors upon deletion
  490. """
  491. self.remove_all_actors()