openscenario_parser.py 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  1. #!/usr/bin/env python
  2. # Copyright (c) 2019-2021 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 a parser for scenario configuration files based on OpenSCENARIO
  8. """
  9. from __future__ import print_function
  10. import random
  11. from distutils.util import strtobool
  12. import re
  13. import copy
  14. import datetime
  15. import math
  16. import operator
  17. import random
  18. import py_trees
  19. import carla
  20. from srunner.scenariomanager.carla_data_provider import CarlaDataProvider
  21. from srunner.scenariomanager.weather_sim import Weather
  22. from srunner.scenariomanager.scenarioatomics.atomic_behaviors import (TrafficLightStateSetter,
  23. ActorTransformSetterToOSCPosition,
  24. RunScript,
  25. ChangeWeather,
  26. ChangeAutoPilot,
  27. ChangeRoadFriction,
  28. ChangeActorTargetSpeed,
  29. ChangeActorControl,
  30. ChangeActorWaypoints,
  31. ChangeActorLateralMotion,
  32. ChangeActorLaneOffset,
  33. SyncArrivalOSC,
  34. KeepLongitudinalGap,
  35. Idle,
  36. ChangeParameter)
  37. # pylint: disable=unused-import
  38. # For the following includes the pylint check is disabled, as these are accessed via globals()
  39. from srunner.scenariomanager.scenarioatomics.atomic_criteria import (CollisionTest,
  40. MaxVelocityTest,
  41. DrivenDistanceTest,
  42. AverageVelocityTest,
  43. KeepLaneTest,
  44. ReachedRegionTest,
  45. OnSidewalkTest,
  46. WrongLaneTest,
  47. InRadiusRegionTest,
  48. InRouteTest,
  49. RouteCompletionTest,
  50. RunningRedLightTest,
  51. RunningStopTest,
  52. OffRoadTest,
  53. EndofRoadTest)
  54. # pylint: enable=unused-import
  55. from srunner.scenariomanager.scenarioatomics.atomic_trigger_conditions import (InTriggerDistanceToVehicle,
  56. InTriggerDistanceToOSCPosition,
  57. InTimeToArrivalToOSCPosition,
  58. InTimeToArrivalToVehicle,
  59. DriveDistance,
  60. StandStill,
  61. OSCStartEndCondition,
  62. TriggerAcceleration,
  63. RelativeVelocityToOtherActor,
  64. TimeOfDayComparison,
  65. TriggerVelocity,
  66. WaitForTrafficLightState,
  67. CheckParameter)
  68. from srunner.scenariomanager.timer import TimeOut, SimulationTimeCondition
  69. from srunner.tools.py_trees_port import oneshot_behavior
  70. from srunner.tools.scenario_helper import get_offset_transform, get_troad_from_transform
  71. def oneshot_with_check(variable_name, behaviour, name=None):
  72. """
  73. Check if the blackboard contains already variable_name and
  74. return a oneshot_behavior for behaviour.
  75. """
  76. blackboard = py_trees.blackboard.Blackboard()
  77. # check if the variable_name already exists in the blackboard
  78. if blackboard.get(variable_name) is not None:
  79. print("Warning: {} is already used before. Check your XOSC for duplicated names".format(variable_name))
  80. return oneshot_behavior(variable_name, behaviour, name)
  81. class ParameterRef:
  82. """
  83. This class stores osc parameter reference in its original form.
  84. Returns the converted value whenever it is used.
  85. """
  86. def __init__(self, reference_text) -> None:
  87. # TODO: (for OSC1.1) add methods(lexer and math_interpreter) to
  88. # recognize and interpret math expression from reference_text
  89. self.reference_text = str(reference_text)
  90. def is_literal(self) -> bool:
  91. """
  92. Returns: True when text is a literal/number
  93. """
  94. return self._is_matching(pattern=r"(-)?\d+(\.\d*)?")
  95. def is_parameter(self) -> bool:
  96. """
  97. Returns: True when text is a parameter
  98. """
  99. return self._is_matching(pattern=r"[$][A-Za-z_][\w]*")
  100. def _is_matching(self, pattern: str) -> bool:
  101. """
  102. Returns: True when pattern is matching with text
  103. """
  104. match = re.search(pattern, self.reference_text)
  105. if match is not None:
  106. matching_string = match.group()
  107. return matching_string == self.reference_text
  108. return False
  109. def get_interpreted_value(self):
  110. """
  111. Returns: interpreted value from reference_text
  112. """
  113. if self.is_literal():
  114. value = self.reference_text
  115. elif self.is_parameter():
  116. value = CarlaDataProvider.get_osc_global_param_value(self.reference_text)
  117. if value is None:
  118. raise Exception("Parameter '{}' is not defined".format(self.reference_text[1:]))
  119. else:
  120. value = None
  121. return value
  122. def __float__(self) -> float:
  123. value = self.get_interpreted_value()
  124. if value is not None:
  125. return float(value)
  126. else:
  127. raise Exception("could not convert '{}' to float".format(self.reference_text))
  128. def __int__(self) -> int:
  129. value = self.get_interpreted_value()
  130. if value is not None:
  131. return int(float(value))
  132. else:
  133. raise Exception("could not convert '{}' to int".format(self.reference_text))
  134. def __str__(self) -> str:
  135. value = self.get_interpreted_value()
  136. return str(value) if value is not None else self.reference_text
  137. def __repr__(self):
  138. value = self.get_interpreted_value()
  139. return value if value is not None else self.reference_text
  140. def __radd__(self, other) -> bool:
  141. return other + self.__float__()
  142. def __add__(self, other) -> bool:
  143. return other + self.__float__()
  144. def __rsub__(self, other) -> bool:
  145. return other - self.__float__()
  146. def __sub__(self, other) -> bool:
  147. return self.__float__() - other
  148. def __rmul__(self, other) -> bool:
  149. return other * self.__float__()
  150. def __mul__(self, other) -> bool:
  151. return other * self.__float__()
  152. def __truediv__(self, other) -> bool:
  153. return self.__float__() / other
  154. def __rtruediv__(self, other) -> bool:
  155. return other / self.__float__()
  156. def __eq__(self, other) -> bool:
  157. return other == self.__float__()
  158. def __ne__(self, other) -> bool:
  159. return other != self.__float__()
  160. def __ge__(self, other) -> bool:
  161. return self.__float__() >= other
  162. def __le__(self, other) -> bool:
  163. return self.__float__() <= other
  164. def __gt__(self, other) -> bool:
  165. return self.__float__() > other
  166. def __lt__(self, other) -> bool:
  167. return self.__float__() < other
  168. def __GE__(self, other) -> bool: # pylint: disable=invalid-name
  169. return self.__float__() >= other
  170. def __LE__(self, other) -> bool: # pylint: disable=invalid-name
  171. return self.__float__() <= other
  172. def __GT__(self, other) -> bool: # pylint: disable=invalid-name
  173. return self.__float__() > other
  174. def __LT__(self, other) -> bool: # pylint: disable=invalid-name
  175. return self.__float__() < other
  176. def __iadd__(self, other) -> bool:
  177. return self.__float__() + other
  178. def __isub__(self, other) -> bool:
  179. return self.__float__() - other
  180. def __abs__(self):
  181. return abs(self.__float__())
  182. class OpenScenarioParser(object):
  183. """
  184. Pure static class providing conversions from OpenSCENARIO elements to ScenarioRunner elements
  185. """
  186. operators = {
  187. "greaterThan": operator.gt,
  188. "lessThan": operator.lt,
  189. "equalTo": operator.eq,
  190. "greaterOrEqual": operator.ge,
  191. "lessOrEqual": operator.le,
  192. "notEqualTo": operator.ne
  193. }
  194. actor_types = {
  195. "pedestrian": "walker",
  196. "vehicle": "vehicle",
  197. "miscellaneous": "miscellaneous"
  198. }
  199. tl_states = {
  200. "GREEN": carla.TrafficLightState.Green,
  201. "YELLOW": carla.TrafficLightState.Yellow,
  202. "RED": carla.TrafficLightState.Red,
  203. "OFF": carla.TrafficLightState.Off,
  204. }
  205. global_osc_parameters = {}
  206. use_carla_coordinate_system = False
  207. osc_filepath = None
  208. @staticmethod
  209. def get_traffic_light_from_osc_name(name):
  210. """
  211. Returns a carla.TrafficLight instance that matches the name given
  212. """
  213. traffic_light = None
  214. # Given by id
  215. if name.startswith("id="):
  216. tl_id = int(name[3:])
  217. for carla_tl in CarlaDataProvider.get_world().get_actors().filter('traffic.traffic_light'):
  218. if carla_tl.id == tl_id:
  219. traffic_light = carla_tl
  220. break
  221. # Given by position
  222. elif name.startswith("pos="):
  223. tl_pos = name[4:]
  224. pos = tl_pos.split(",")
  225. for carla_tl in CarlaDataProvider.get_world().get_actors().filter('traffic.traffic_light'):
  226. carla_tl_location = carla_tl.get_transform().location
  227. distance = carla_tl_location.distance(carla.Location(float(pos[0]),
  228. float(pos[1]),
  229. carla_tl_location.z))
  230. if distance < 2.0:
  231. traffic_light = carla_tl
  232. break
  233. if traffic_light is None:
  234. raise AttributeError("Unknown traffic light {}".format(name))
  235. return traffic_light
  236. @staticmethod
  237. def set_osc_filepath(filepath):
  238. """
  239. Set path of OSC file. This is required if for example custom commands are provided with
  240. relative paths.
  241. """
  242. OpenScenarioParser.osc_filepath = filepath
  243. @staticmethod
  244. def set_use_carla_coordinate_system():
  245. """
  246. CARLA internally uses a left-hand coordinate system (Unreal), but OpenSCENARIO and OpenDRIVE
  247. are intended for right-hand coordinate system. Hence, we need to invert the coordinates, if
  248. the scenario does not use CARLA coordinates, but instead right-hand coordinates.
  249. """
  250. OpenScenarioParser.use_carla_coordinate_system = True
  251. @staticmethod
  252. def set_parameters(xml_tree, additional_parameter_dict=None):
  253. """
  254. Parse the xml_tree, and replace all parameter references
  255. with the actual values.
  256. Note: Parameter names must not start with "$", however when referencing a parameter the
  257. reference has to start with "$".
  258. https://releases.asam.net/OpenSCENARIO/1.0.0/ASAM_OpenSCENARIO_BS-1-2_User-Guide_V1-0-0.html#_re_use_mechanisms
  259. Args:
  260. xml_tree: Containing all nodes that should be updated
  261. additional_parameter_dict (dictionary): Additional parameters as dict (key, value). Optional.
  262. returns:
  263. updated xml_tree, dictonary containing all parameters and their values
  264. """
  265. parameter_dict = {}
  266. parameters = xml_tree.find('ParameterDeclarations')
  267. if parameters is None and not parameter_dict:
  268. return xml_tree, parameter_dict
  269. if parameters is None:
  270. parameters = []
  271. for parameter in parameters:
  272. name = parameter.attrib.get('name')
  273. value = parameter.attrib.get('value')
  274. parameter_dict[name] = value
  275. # overwrite parameters in parameters_dict by additional_parameters_dict
  276. if additional_parameter_dict is not None:
  277. parameter_dict = dict(list(parameter_dict.items()) + list(additional_parameter_dict.items()))
  278. return xml_tree, parameter_dict
  279. @staticmethod
  280. def set_global_parameters(parameter_dict):
  281. """
  282. Set global_osc_parameter dictionary
  283. Args:
  284. parameter_dict (Dictionary): Input for global_osc_parameter
  285. """
  286. OpenScenarioParser.global_osc_parameters = parameter_dict
  287. CarlaDataProvider.update_osc_global_params(parameter_dict)
  288. @staticmethod
  289. def get_catalog_entry(catalogs, catalog_reference):
  290. """
  291. Get catalog entry referenced by catalog_reference included correct parameter settings
  292. Args:
  293. catalogs (Dictionary of dictionaries): List of all catalogs and their entries
  294. catalog_reference (XML ElementTree): Reference containing the exact catalog to be used
  295. returns:
  296. Catalog entry (XML ElementTree)
  297. """
  298. entry_name = str(ParameterRef(catalog_reference.attrib.get("entryName")))
  299. entry = catalogs[catalog_reference.attrib.get("catalogName")][entry_name]
  300. entry_copy = copy.deepcopy(entry)
  301. catalog_copy = copy.deepcopy(catalog_reference)
  302. entry = OpenScenarioParser.assign_catalog_parameters(entry_copy, catalog_copy)
  303. return entry
  304. @staticmethod
  305. def assign_catalog_parameters(entry_instance, catalog_reference):
  306. """
  307. Parse catalog_reference, and replace all parameter references
  308. in entry_instance by the values provided in catalog_reference.
  309. Not to be used from outside this class.
  310. Args:
  311. entry_instance (XML ElementTree): Entry to be updated
  312. catalog_reference (XML ElementTree): Reference containing the exact parameter values
  313. returns:
  314. updated entry_instance with updated parameter values
  315. """
  316. parameter_dict = {}
  317. for elem in entry_instance.iter():
  318. if elem.find('ParameterDeclarations') is not None:
  319. parameters = elem.find('ParameterDeclarations')
  320. for parameter in parameters:
  321. name = parameter.attrib.get('name')
  322. value = parameter.attrib.get('value')
  323. parameter_dict[name] = value
  324. for parameter_assignments in catalog_reference.iter("ParameterAssignments"):
  325. for parameter_assignment in parameter_assignments.iter("ParameterAssignment"):
  326. parameter = parameter_assignment.attrib.get("parameterRef")
  327. value = parameter_assignment.attrib.get("value")
  328. parameter_dict[parameter] = value
  329. for node in entry_instance.iter():
  330. for key in node.attrib:
  331. for param in sorted(parameter_dict, key=len, reverse=True):
  332. if "$" + param in node.attrib[key]:
  333. node.attrib[key] = node.attrib[key].replace("$" + param, parameter_dict[param])
  334. OpenScenarioParser.set_parameters(entry_instance, OpenScenarioParser.global_osc_parameters)
  335. return entry_instance
  336. @staticmethod
  337. def get_friction_from_env_action(xml_tree, catalogs):
  338. """
  339. Extract the CARLA road friction coefficient from an OSC EnvironmentAction
  340. Args:
  341. xml_tree: Containing the EnvironmentAction,
  342. or the reference to the catalog it is defined in.
  343. catalogs: XML Catalogs that could contain the EnvironmentAction
  344. returns:
  345. friction (float)
  346. """
  347. if xml_tree.findall('.//EnvironmentAction'):
  348. node = xml_tree.findall('.//EnvironmentAction')[0]
  349. set_environment = next(node.iter("EnvironmentAction"))
  350. else:
  351. return 1.0
  352. if sum(1 for _ in set_environment.iter("Weather")) != 0:
  353. environment = set_environment.find("Environment")
  354. elif set_environment.find("CatalogReference") is not None:
  355. catalog_reference = set_environment.find("CatalogReference")
  356. environment = OpenScenarioParser.get_catalog_entry(catalogs, catalog_reference)
  357. friction = 1.0
  358. road_condition = environment.iter("RoadCondition")
  359. for condition in road_condition:
  360. friction = condition.attrib.get('frictionScaleFactor')
  361. return friction
  362. @staticmethod
  363. def get_weather_from_env_action(xml_tree, catalogs):
  364. """
  365. Extract the CARLA weather parameters from an OSC EnvironmentAction
  366. Args:
  367. xml_tree: Containing the EnvironmentAction,
  368. or the reference to the catalog it is defined in.
  369. catalogs: XML Catalogs that could contain the EnvironmentAction
  370. returns:
  371. Weather (srunner.scenariomanager.weather_sim.Weather)
  372. """
  373. if xml_tree.findall('.//EnvironmentAction'):
  374. node = xml_tree.findall('.//EnvironmentAction')[0]
  375. set_environment = next(node.iter("EnvironmentAction"))
  376. else:
  377. return Weather(carla.WeatherParameters())
  378. if sum(1 for _ in set_environment.iter("Weather")) != 0:
  379. environment = set_environment.find("Environment")
  380. elif set_environment.find("CatalogReference") is not None:
  381. catalog_reference = set_environment.find("CatalogReference")
  382. environment = OpenScenarioParser.get_catalog_entry(catalogs, catalog_reference)
  383. weather = environment.find("Weather")
  384. sun = weather.find("Sun")
  385. carla_weather = carla.WeatherParameters()
  386. carla_weather.sun_azimuth_angle = math.degrees(float(sun.attrib.get('azimuth', 0)))
  387. carla_weather.sun_altitude_angle = math.degrees(float(sun.attrib.get('elevation', 0)))
  388. carla_weather.cloudiness = 100 - float(sun.attrib.get('intensity', 0)) * 100
  389. fog = weather.find("Fog")
  390. carla_weather.fog_distance = float(fog.attrib.get('visualRange', 'inf'))
  391. if carla_weather.fog_distance >=20:
  392. # carla_weather.fog_density=25-0.125*(float(carla_weather.fog_distance))
  393. carla_weather.fog_density=(200-float(carla_weather.fog_distance))/9
  394. else:
  395. # carla_weather.fog_density=100-2*(float(carla_weather.fog_distance))
  396. carla_weather.fog_density=100-4*(float(carla_weather.fog_distance))
  397. print(carla_weather.fog_distance,carla_weather.fog_density)
  398. carla_weather.precipitation = 0
  399. carla_weather.precipitation_deposits = 0
  400. carla_weather.wetness = 0
  401. carla_weather.wind_intensity = 30.0
  402. precepitation = weather.find("Precipitation")
  403. if precepitation.attrib.get('precipitationType') == "rain":
  404. precipitation = float(precepitation.attrib.get('intensity')) * 100
  405. if precipitation<=60:
  406. carla_weather.precipitation=precipitation*0.5
  407. else:
  408. # carla_weather.precipitation=precipitation*(4/3.0)-(100/3.0)
  409. carla_weather.precipitation=precipitation*(7/4.0)-75
  410. carla_weather.precipitation_deposits = carla_weather.precipitation # if it rains, make the road wet
  411. print(carla_weather.precipitation_deposits)
  412. #TODO
  413. carla_weather.wetness = carla_weather.precipitation
  414. elif precepitation.attrib.get('type') == "snow":
  415. raise AttributeError("CARLA does not support snow precipitation")
  416. time_of_day = environment.find("TimeOfDay")
  417. weather_animation = strtobool(time_of_day.attrib.get("animation"))
  418. time = time_of_day.attrib.get("dateTime")
  419. dtime = datetime.datetime.strptime(time, "%Y-%m-%dT%H:%M:%S")
  420. return Weather(carla_weather, dtime, weather_animation)
  421. @staticmethod
  422. def get_controller(xml_tree, catalogs):
  423. """
  424. Extract the object controller from the OSC XML or a catalog
  425. Args:
  426. xml_tree: Containing the controller information,
  427. or the reference to the catalog it is defined in.
  428. catalogs: XML Catalogs that could contain the EnvironmentAction
  429. returns:
  430. module: Python module containing the controller implementation
  431. args: Dictonary with (key, value) parameters for the controller
  432. """
  433. assign_action = next(xml_tree.iter("AssignControllerAction"))
  434. properties = None
  435. if assign_action.find('Controller') is not None:
  436. properties = assign_action.find('Controller').find('Properties')
  437. elif assign_action.find("CatalogReference") is not None:
  438. catalog_reference = assign_action.find("CatalogReference")
  439. properties = OpenScenarioParser.get_catalog_entry(catalogs, catalog_reference).find('Properties')
  440. module = None
  441. args = {}
  442. for prop in properties:
  443. if prop.attrib.get('name') == "module":
  444. module = prop.attrib.get('value')
  445. else:
  446. args[prop.attrib.get('name')] = prop.attrib.get('value')
  447. override_action = xml_tree.find('OverrideControllerValueAction')
  448. for child in override_action:
  449. if strtobool(child.attrib.get('active')):
  450. raise NotImplementedError("Controller override actions are not yet supported")
  451. return module, args
  452. @staticmethod
  453. def get_route(xml_tree, catalogs):
  454. """
  455. Extract the route from the OSC XML or a catalog
  456. Args:
  457. xml_tree: Containing the route information,
  458. or the reference to the catalog it is defined in.
  459. catalogs: XML Catalogs that could contain the Route
  460. returns:
  461. waypoints: List of route waypoints = (waypoint, routing strategy)
  462. where the strategy is a string indicating if the fastest/shortest/etc.
  463. route should be used.
  464. """
  465. route = None
  466. if xml_tree.find('Route') is not None:
  467. route = xml_tree.find('Route')
  468. elif xml_tree.find('CatalogReference') is not None:
  469. catalog_reference = xml_tree.find("CatalogReference")
  470. route = OpenScenarioParser.get_catalog_entry(catalogs, catalog_reference)
  471. else:
  472. raise AttributeError("Unknown private FollowRoute action")
  473. waypoints = []
  474. if route is not None:
  475. for waypoint in route.iter('Waypoint'):
  476. position = waypoint.find('Position')
  477. routing_option = str(waypoint.attrib.get('routeStrategy'))
  478. waypoints.append((position, routing_option))
  479. else:
  480. raise AttributeError("No waypoints has been set")
  481. return waypoints
  482. @staticmethod
  483. def get_trajectory(xml_tree, catalogs):
  484. """
  485. Extract the trajectory from the OSC XML or a catalog
  486. Args:
  487. xml_tree: Containing the trajectory information,
  488. or the reference to the catalog it is defined in.
  489. catalogs: XML Catalogs that could contain the trajectory
  490. returns:
  491. waypoints: List of trajectory waypoints and times.
  492. Only polylines are supported
  493. """
  494. trajectory = None
  495. waypoints = []
  496. times = []
  497. if xml_tree.find('Trajectory') is not None:
  498. trajectory = xml_tree.find('Trajectory')
  499. elif xml_tree.find('CatalogReference') is not None:
  500. catalog_reference = xml_tree.find("CatalogReference")
  501. trajectory = OpenScenarioParser.get_catalog_entry(catalogs, catalog_reference)
  502. else:
  503. raise AttributeError("Unknown private FollowTrajectory action")
  504. if trajectory is not None:
  505. shape = trajectory.find('Shape')
  506. if shape.find('Polyline') is not None:
  507. line = shape.find('Polyline')
  508. for vertex in line.iter('Vertex'):
  509. times.append(float(vertex.get('time')))
  510. waypoints.append(vertex.find('Position'))
  511. elif shape.find('Clothoid') is not None:
  512. raise AttributeError("Clothoid shapes are currently unsupported")
  513. elif shape.find('Nurbs') is not None:
  514. raise AttributeError("Nurbs shapes are currently unsupported")
  515. else:
  516. raise AttributeError("Requested shape {} isn't a valid shape".format(shape))
  517. else:
  518. raise AttributeError("No waypoints has been set")
  519. return waypoints, times
  520. @staticmethod
  521. def convert_position_to_transform(position, actor_list=None):
  522. """
  523. Convert an OpenScenario position into a CARLA transform
  524. Not supported: RoutePosition
  525. """
  526. if position.find('WorldPosition') is not None:
  527. world_pos = position.find('WorldPosition')
  528. x = float(ParameterRef(world_pos.attrib.get('x', 0)))
  529. y = float(ParameterRef(world_pos.attrib.get('y', 0)))
  530. z = float(ParameterRef(world_pos.attrib.get('z', 0)))
  531. yaw = math.degrees(float(ParameterRef(world_pos.attrib.get('h', 0))))
  532. pitch = math.degrees(float(ParameterRef(world_pos.attrib.get('p', 0))))
  533. roll = math.degrees(float(ParameterRef(world_pos.attrib.get('r', 0))))
  534. if not OpenScenarioParser.use_carla_coordinate_system:
  535. y = y * (-1.0)
  536. yaw = yaw * (-1.0)
  537. return carla.Transform(carla.Location(x=x, y=y, z=z), carla.Rotation(yaw=yaw, pitch=pitch, roll=roll))
  538. elif ((position.find('RelativeWorldPosition') is not None) or
  539. (position.find('RelativeObjectPosition') is not None) or
  540. (position.find('RelativeLanePosition') is not None) or
  541. (position.find('RelativeRoadPosition') is not None)):
  542. if position.find('RelativeWorldPosition') is not None:
  543. rel_pos = position.find('RelativeWorldPosition')
  544. if position.find('RelativeObjectPosition') is not None:
  545. rel_pos = position.find('RelativeObjectPosition')
  546. if position.find('RelativeLanePosition') is not None:
  547. rel_pos = position.find('RelativeLanePosition')
  548. if position.find('RelativeRoadPosition') is not None:
  549. rel_pos = position.find('RelativeRoadPosition')
  550. # get relative object and relative position
  551. obj = rel_pos.attrib.get('entityRef')
  552. obj_actor = None
  553. actor_transform = None
  554. if actor_list is not None:
  555. for actor in actor_list:
  556. if actor.rolename == obj:
  557. obj_actor = actor
  558. actor_transform = actor.transform
  559. else:
  560. for actor in CarlaDataProvider.get_world().get_actors():
  561. if 'role_name' in actor.attributes and actor.attributes['role_name'] == obj:
  562. obj_actor = actor
  563. actor_transform = obj_actor.get_transform()
  564. break
  565. if obj_actor is None or actor_transform is None:
  566. raise AttributeError("Object '{}' provided as position reference is not known".format(obj))
  567. # calculate orientation h, p, r
  568. is_absolute = False
  569. dyaw = 0
  570. dpitch = 0
  571. droll = 0
  572. if rel_pos.find('Orientation') is not None:
  573. orientation = rel_pos.find('Orientation')
  574. is_absolute = (orientation.attrib.get('type') == "absolute")
  575. dyaw = math.degrees(float(ParameterRef(orientation.attrib.get('h', 0))))
  576. dpitch = math.degrees(float(ParameterRef(orientation.attrib.get('p', 0))))
  577. droll = math.degrees(float(ParameterRef(orientation.attrib.get('r', 0))))
  578. if not OpenScenarioParser.use_carla_coordinate_system:
  579. dyaw = dyaw * (-1.0)
  580. yaw = actor_transform.rotation.yaw
  581. pitch = actor_transform.rotation.pitch
  582. roll = actor_transform.rotation.roll
  583. if not is_absolute:
  584. yaw = yaw + dyaw
  585. pitch = pitch + dpitch
  586. roll = roll + droll
  587. else:
  588. yaw = dyaw
  589. pitch = dpitch
  590. roll = droll
  591. # calculate location x, y, z
  592. # dx, dy, dz
  593. if ((position.find('RelativeWorldPosition') is not None) or
  594. (position.find('RelativeObjectPosition') is not None)):
  595. dx = float(ParameterRef(rel_pos.attrib.get('dx', 0)))
  596. dy = float(ParameterRef(rel_pos.attrib.get('dy', 0)))
  597. dz = float(ParameterRef(rel_pos.attrib.get('dz', 0)))
  598. if not OpenScenarioParser.use_carla_coordinate_system:
  599. dy = dy * (-1.0)
  600. x = actor_transform.location.x + dx
  601. y = actor_transform.location.y + dy
  602. z = actor_transform.location.z + dz
  603. transform = carla.Transform(carla.Location(x=x, y=y, z=z),
  604. carla.Rotation(yaw=yaw, pitch=pitch, roll=roll))
  605. elif position.find('RelativeLanePosition') is not None:
  606. dlane = float(ParameterRef(rel_pos.attrib.get('dLane')))
  607. ds = float(ParameterRef(rel_pos.attrib.get('ds')))
  608. offset = float(ParameterRef(rel_pos.attrib.get('offset', 0.0)))
  609. carla_map = CarlaDataProvider.get_map()
  610. relative_waypoint = carla_map.get_waypoint(actor_transform.location)
  611. road_id, ref_lane_id, ref_s = relative_waypoint.road_id, relative_waypoint.lane_id, relative_waypoint.s
  612. target_lane_id = int(ref_lane_id + dlane)
  613. waypoint = CarlaDataProvider.get_map().get_waypoint_xodr(road_id, target_lane_id, ref_s)
  614. if waypoint is not None:
  615. if ds < 0:
  616. ds = (-1.0) * ds
  617. waypoint = waypoint.previous(ds)[-1]
  618. else:
  619. waypoint = waypoint.next(ds)[-1]
  620. if waypoint is None:
  621. raise AttributeError("RelativeLanePosition " +
  622. "'roadId={} with ds={} and lane_id={}' does not exist".format(road_id,
  623. ds,
  624. target_lane_id))
  625. transform = waypoint.transform
  626. transform.rotation.yaw = yaw
  627. transform.rotation.pitch = pitch
  628. transform.rotation.roll = roll
  629. # Adapt transform according to offset
  630. if abs(offset) == waypoint.lane_width:
  631. # if the offset position is exactly on lane edge its difficult to find out which lane its on.
  632. # so, when offset is on lane edge/corner adjust it to stay inside the lane
  633. # if user wants to offset out of lane then make sure offset > waypoint.lane_width
  634. if offset > 0:
  635. offset = offset - 0.05
  636. elif offset < 0:
  637. offset = offset + 0.05
  638. transform = get_offset_transform(transform, offset)
  639. elif position.find('RelativeRoadPosition') is not None:
  640. ds = float(ParameterRef(rel_pos.attrib.get('ds')))
  641. dt = float(ParameterRef(rel_pos.attrib.get('dt', 0.0)))
  642. troad = get_troad_from_transform
  643. carla_map = CarlaDataProvider.get_map()
  644. relative_waypoint = carla_map.get_waypoint(actor_transform.location)
  645. road_id, ref_lane_id, ref_s = relative_waypoint.road_id, relative_waypoint.lane_id, relative_waypoint.s
  646. target_t, target_s = troad(relative_waypoint.transform) - troad(actor_transform) + dt, ref_s + ds
  647. waypoint = CarlaDataProvider.get_map().get_waypoint_xodr(road_id, ref_lane_id, target_s)
  648. if waypoint is None:
  649. raise AttributeError("RelativeRoadPosition 'roadId={} with s={} and t={}' does not exist".format(
  650. road_id, target_s, target_t))
  651. transform = waypoint.transform
  652. transform.rotation.yaw = yaw
  653. transform.rotation.pitch = pitch
  654. transform.rotation.roll = roll
  655. transform = get_offset_transform(transform, target_t)
  656. return transform
  657. elif position.find('RoadPosition') is not None:
  658. road_pos = position.find('RoadPosition')
  659. road_id = int(ParameterRef(road_pos.attrib.get('roadId', 0)))
  660. t = float(ParameterRef(road_pos.attrib.get('t', 0)))
  661. s = float(ParameterRef(road_pos.attrib.get('s', 0)))
  662. waypoint = CarlaDataProvider.get_map().get_waypoint_xodr(road_id, 0, s)
  663. if waypoint is None:
  664. raise AttributeError("RoadPosition 'roadId={} with s={} and t={}' does not exist".format(road_id, s, t))
  665. transform = waypoint.transform
  666. if road_pos.find('Orientation') is not None:
  667. orientation = road_pos.find('Orientation')
  668. dyaw = math.degrees(float(ParameterRef(orientation.attrib.get('h', 0))))
  669. dpitch = math.degrees(float(ParameterRef(orientation.attrib.get('p', 0))))
  670. droll = math.degrees(float(ParameterRef(orientation.attrib.get('r', 0))))
  671. if not OpenScenarioParser.use_carla_coordinate_system:
  672. dyaw = dyaw * (-1.0)
  673. transform.rotation.yaw = transform.rotation.yaw + dyaw
  674. transform.rotation.pitch = transform.rotation.pitch + dpitch
  675. transform.rotation.roll = transform.rotation.roll + droll
  676. if not OpenScenarioParser.use_carla_coordinate_system:
  677. # multiply -1 because unlike offset t road is -ve for right side
  678. t = -1*t
  679. transform = get_offset_transform(transform, t)
  680. return transform
  681. elif position.find('LanePosition') is not None:
  682. lane_pos = position.find('LanePosition')
  683. road_id = int(ParameterRef(lane_pos.attrib.get('roadId', 0)))
  684. lane_id = int(ParameterRef(lane_pos.attrib.get('laneId', 0)))
  685. offset = float(ParameterRef(lane_pos.attrib.get('offset', 0)))
  686. s = float(ParameterRef(lane_pos.attrib.get('s', 0)))
  687. waypoint = CarlaDataProvider.get_map().get_waypoint_xodr(road_id, lane_id, s)
  688. if waypoint is None:
  689. raise AttributeError("LanePosition 'roadId={}, laneId={}, s={}, offset={}' does not exist".format(
  690. road_id, lane_id, s, offset))
  691. transform = waypoint.transform
  692. if lane_pos.find('Orientation') is not None:
  693. orientation = lane_pos.find('Orientation')
  694. dyaw = math.degrees(float(ParameterRef(orientation.attrib.get('h', 0))))
  695. dpitch = math.degrees(float(ParameterRef(orientation.attrib.get('p', 0))))
  696. droll = math.degrees(float(ParameterRef(orientation.attrib.get('r', 0))))
  697. if not OpenScenarioParser.use_carla_coordinate_system:
  698. dyaw = dyaw * (-1.0)
  699. transform.rotation.yaw = transform.rotation.yaw + dyaw
  700. transform.rotation.pitch = transform.rotation.pitch + dpitch
  701. transform.rotation.roll = transform.rotation.roll + droll
  702. if offset != 0:
  703. forward_vector = transform.rotation.get_forward_vector()
  704. orthogonal_vector = carla.Vector3D(x=-forward_vector.y, y=forward_vector.x, z=forward_vector.z)
  705. transform.location.x = transform.location.x + offset * orthogonal_vector.x
  706. transform.location.y = transform.location.y + offset * orthogonal_vector.y
  707. return transform
  708. elif position.find('RoutePosition') is not None:
  709. raise NotImplementedError("Route positions are not yet supported")
  710. else:
  711. raise AttributeError("Unknown position")
  712. @staticmethod
  713. def convert_condition_to_atomic(condition, actor_list):
  714. """
  715. Convert an OpenSCENARIO condition into a Behavior/Criterion atomic
  716. If there is a delay defined in the condition, then the condition is checked after the delay time
  717. passed by, e.g. <Condition name="" delay="5">.
  718. Note: Not all conditions are currently supported.
  719. """
  720. atomic = None
  721. delay_atomic = None
  722. condition_name = condition.attrib.get('name')
  723. if condition.attrib.get('delay') is not None and float(condition.attrib.get('delay')) != 0:
  724. delay = float(condition.attrib.get('delay'))
  725. delay_atomic = TimeOut(delay)
  726. if condition.find('ByEntityCondition') is not None:
  727. trigger_actor = None # A-priori validation ensures that this will be not None
  728. triggered_actor = None
  729. for triggering_entities in condition.find('ByEntityCondition').iter('TriggeringEntities'):
  730. for entity in triggering_entities.iter('EntityRef'):
  731. for actor in actor_list:
  732. if actor is not None and entity.attrib.get('entityRef', None) == actor.attributes['role_name']:
  733. trigger_actor = actor
  734. break
  735. for entity_condition in condition.find('ByEntityCondition').iter('EntityCondition'):
  736. if entity_condition.find('EndOfRoadCondition') is not None:
  737. end_road_condition = entity_condition.find('EndOfRoadCondition')
  738. condition_duration = ParameterRef(end_road_condition.attrib.get('duration'))
  739. atomic_cls = py_trees.meta.inverter(EndofRoadTest)
  740. atomic = atomic_cls(trigger_actor, condition_duration, terminate_on_failure=True,
  741. name=condition_name)
  742. elif entity_condition.find('CollisionCondition') is not None:
  743. collision_condition = entity_condition.find('CollisionCondition')
  744. if collision_condition.find('EntityRef') is not None:
  745. collision_entity = collision_condition.find('EntityRef')
  746. for actor in actor_list:
  747. if collision_entity.attrib.get('entityRef', None) == actor.attributes['role_name']:
  748. triggered_actor = actor
  749. break
  750. if triggered_actor is None:
  751. raise AttributeError("Cannot find actor '{}' for condition".format(
  752. collision_condition.attrib.get('entityRef', None)))
  753. atomic_cls = py_trees.meta.inverter(CollisionTest)
  754. atomic = atomic_cls(trigger_actor, other_actor=triggered_actor, terminate_on_failure=True,
  755. name=condition_name)
  756. elif collision_condition.find('ByType') is not None:
  757. collision_type = collision_condition.find('ByType').attrib.get('type', None)
  758. triggered_type = OpenScenarioParser.actor_types[collision_type]
  759. atomic_cls = py_trees.meta.inverter(CollisionTest)
  760. atomic = atomic_cls(trigger_actor, other_actor_type=triggered_type, terminate_on_failure=True,
  761. name=condition_name)
  762. else:
  763. atomic_cls = py_trees.meta.inverter(CollisionTest)
  764. atomic = atomic_cls(trigger_actor, terminate_on_failure=True, name=condition_name)
  765. elif entity_condition.find('OffroadCondition') is not None:
  766. off_condition = entity_condition.find('OffroadCondition')
  767. condition_duration = ParameterRef(off_condition.attrib.get('duration'))
  768. atomic_cls = py_trees.meta.inverter(OffRoadTest)
  769. atomic = atomic_cls(trigger_actor, condition_duration, terminate_on_failure=True,
  770. name=condition_name)
  771. elif entity_condition.find('TimeHeadwayCondition') is not None:
  772. headtime_condition = entity_condition.find('TimeHeadwayCondition')
  773. condition_value = ParameterRef(headtime_condition.attrib.get('value'))
  774. condition_rule = headtime_condition.attrib.get('rule')
  775. condition_operator = OpenScenarioParser.operators[condition_rule]
  776. condition_freespace = strtobool(headtime_condition.attrib.get('freespace', False))
  777. condition_along_route = strtobool(headtime_condition.attrib.get('alongRoute', False))
  778. for actor in actor_list:
  779. if headtime_condition.attrib.get('entityRef', None) == actor.attributes['role_name']:
  780. triggered_actor = actor
  781. break
  782. if triggered_actor is None:
  783. raise AttributeError("Cannot find actor '{}' for condition".format(
  784. headtime_condition.attrib.get('entityRef', None)))
  785. atomic = InTimeToArrivalToVehicle(
  786. trigger_actor, triggered_actor, condition_value, condition_freespace,
  787. condition_along_route, condition_operator, condition_name
  788. )
  789. elif entity_condition.find('TimeToCollisionCondition') is not None:
  790. ttc_condition = entity_condition.find('TimeToCollisionCondition')
  791. condition_rule = ttc_condition.attrib.get('rule')
  792. condition_operator = OpenScenarioParser.operators[condition_rule]
  793. condition_value = ParameterRef(ttc_condition.attrib.get('value'))
  794. condition_target = ttc_condition.find('TimeToCollisionConditionTarget')
  795. entity_ref_ = condition_target.find('EntityRef')
  796. condition_freespace = strtobool(ttc_condition.attrib.get('freespace', False))
  797. condition_along_route = strtobool(ttc_condition.attrib.get('alongRoute', False))
  798. if condition_target.find('Position') is not None:
  799. position = condition_target.find('Position')
  800. atomic = InTimeToArrivalToOSCPosition(
  801. trigger_actor, position, condition_value, condition_along_route, condition_operator)
  802. else:
  803. for actor in actor_list:
  804. if entity_ref_.attrib.get('entityRef', None) == actor.attributes['role_name']:
  805. triggered_actor = actor
  806. break
  807. if triggered_actor is None:
  808. raise AttributeError("Cannot find actor '{}' for condition".format(
  809. entity_ref_.attrib.get('entityRef', None)))
  810. atomic = InTimeToArrivalToVehicle(
  811. trigger_actor, triggered_actor, condition_value, condition_freespace,
  812. condition_along_route, condition_operator, condition_name)
  813. elif entity_condition.find('AccelerationCondition') is not None:
  814. accel_condition = entity_condition.find('AccelerationCondition')
  815. condition_value = ParameterRef(accel_condition.attrib.get('value'))
  816. condition_rule = accel_condition.attrib.get('rule')
  817. condition_operator = OpenScenarioParser.operators[condition_rule]
  818. atomic = TriggerAcceleration(
  819. trigger_actor, condition_value, condition_operator, condition_name)
  820. elif entity_condition.find('StandStillCondition') is not None:
  821. ss_condition = entity_condition.find('StandStillCondition')
  822. duration = ParameterRef(ss_condition.attrib.get('duration'))
  823. atomic = StandStill(trigger_actor, condition_name, duration)
  824. elif entity_condition.find('SpeedCondition') is not None:
  825. spd_condition = entity_condition.find('SpeedCondition')
  826. condition_value = ParameterRef(spd_condition.attrib.get('value'))
  827. condition_rule = spd_condition.attrib.get('rule')
  828. condition_operator = OpenScenarioParser.operators[condition_rule]
  829. atomic = TriggerVelocity(
  830. trigger_actor, condition_value, condition_operator, condition_name)
  831. elif entity_condition.find('RelativeSpeedCondition') is not None:
  832. relspd_condition = entity_condition.find('RelativeSpeedCondition')
  833. condition_value = ParameterRef(relspd_condition.attrib.get('value'))
  834. condition_rule = relspd_condition.attrib.get('rule')
  835. condition_operator = OpenScenarioParser.operators[condition_rule]
  836. for actor in actor_list:
  837. if relspd_condition.attrib.get('entityRef', None) == actor.attributes['role_name']:
  838. triggered_actor = actor
  839. break
  840. if triggered_actor is None:
  841. raise AttributeError("Cannot find actor '{}' for condition".format(
  842. relspd_condition.attrib.get('entityRef', None)))
  843. atomic = RelativeVelocityToOtherActor(
  844. trigger_actor, triggered_actor, condition_value, condition_operator, condition_name)
  845. elif entity_condition.find('TraveledDistanceCondition') is not None:
  846. distance_condition = entity_condition.find('TraveledDistanceCondition')
  847. distance_value = ParameterRef(distance_condition.attrib.get('value'))
  848. atomic = DriveDistance(trigger_actor, distance_value, name=condition_name)
  849. elif entity_condition.find('ReachPositionCondition') is not None:
  850. rp_condition = entity_condition.find('ReachPositionCondition')
  851. distance_value = ParameterRef(rp_condition.attrib.get('tolerance'))
  852. position = rp_condition.find('Position')
  853. atomic = InTriggerDistanceToOSCPosition(
  854. trigger_actor, position, distance_value, name=condition_name)
  855. elif entity_condition.find('DistanceCondition') is not None:
  856. distance_condition = entity_condition.find('DistanceCondition')
  857. distance_value = ParameterRef(distance_condition.attrib.get('value'))
  858. distance_rule = distance_condition.attrib.get('rule')
  859. distance_operator = OpenScenarioParser.operators[distance_rule]
  860. distance_freespace = strtobool(distance_condition.attrib.get('freespace', False))
  861. if distance_freespace:
  862. raise NotImplementedError(
  863. "DistanceCondition: freespace attribute is currently not implemented")
  864. distance_along_route = strtobool(distance_condition.attrib.get('alongRoute', False))
  865. if distance_condition.find('Position') is not None:
  866. position = distance_condition.find('Position')
  867. atomic = InTriggerDistanceToOSCPosition(
  868. trigger_actor, position, distance_value, distance_along_route,
  869. distance_operator, name=condition_name)
  870. elif entity_condition.find('RelativeDistanceCondition') is not None:
  871. distance_condition = entity_condition.find('RelativeDistanceCondition')
  872. distance_value = ParameterRef(distance_condition.attrib.get('value'))
  873. distance_freespace = distance_condition.attrib.get('freespace', "false") == "true"
  874. rel_dis_type = distance_condition.attrib.get('relativeDistanceType')
  875. for actor in actor_list:
  876. if distance_condition.attrib.get('entityRef', None) == actor.attributes['role_name']:
  877. triggered_actor = actor
  878. break
  879. if triggered_actor is None:
  880. raise AttributeError("Cannot find actor '{}' for condition".format(
  881. distance_condition.attrib.get('entityRef', None)))
  882. condition_rule = distance_condition.attrib.get('rule')
  883. condition_operator = OpenScenarioParser.operators[condition_rule]
  884. atomic = InTriggerDistanceToVehicle(triggered_actor, trigger_actor, distance_value,
  885. condition_operator, distance_type=rel_dis_type,
  886. freespace=distance_freespace, name=condition_name)
  887. elif condition.find('ByValueCondition') is not None:
  888. value_condition = condition.find('ByValueCondition')
  889. if value_condition.find('ParameterCondition') is not None:
  890. parameter_condition = value_condition.find('ParameterCondition')
  891. arg_name = parameter_condition.attrib.get('parameterRef')
  892. value = ParameterRef(parameter_condition.attrib.get('value'))
  893. rule = parameter_condition.attrib.get('rule')
  894. if condition_name.startswith('criteria_'):
  895. if str(value) != '':
  896. arg_value = float(value)
  897. else:
  898. arg_value = 0
  899. class_name = condition_name[9:]
  900. if class_name in globals():
  901. criterion_instance = globals()[class_name]
  902. else:
  903. raise AttributeError(
  904. "The condition {} cannot be mapped to a criterion atomic".format(class_name))
  905. atomic = py_trees.composites.Parallel("Evaluation Criteria for multiple ego vehicles")
  906. for triggered_actor in actor_list:
  907. if arg_name != '':
  908. atomic.add_child(criterion_instance(triggered_actor, arg_value))
  909. else:
  910. atomic.add_child(criterion_instance(triggered_actor))
  911. else:
  912. atomic = CheckParameter(arg_name, value, OpenScenarioParser.operators[rule], name=condition_name)
  913. elif value_condition.find('SimulationTimeCondition') is not None:
  914. simtime_condition = value_condition.find('SimulationTimeCondition')
  915. value = ParameterRef(simtime_condition.attrib.get('value'))
  916. rule = OpenScenarioParser.operators[simtime_condition.attrib.get('rule')]
  917. atomic = SimulationTimeCondition(value, comparison_operator=rule)
  918. elif value_condition.find('TimeOfDayCondition') is not None:
  919. tod_condition = value_condition.find('TimeOfDayCondition')
  920. condition_date = tod_condition.attrib.get('dateTime')
  921. condition_rule = tod_condition.attrib.get('rule')
  922. condition_operator = OpenScenarioParser.operators[condition_rule]
  923. atomic = TimeOfDayComparison(condition_date, condition_operator, condition_name)
  924. elif value_condition.find('StoryboardElementStateCondition') is not None:
  925. state_condition = value_condition.find('StoryboardElementStateCondition')
  926. element_name = state_condition.attrib.get('storyboardElementRef')
  927. element_type = state_condition.attrib.get('storyboardElementType')
  928. state = state_condition.attrib.get('state')
  929. if state == "startTransition":
  930. atomic = OSCStartEndCondition(element_type, element_name, rule="START", name=state + "Condition")
  931. elif state in ["stopTransition", "endTransition", "completeState"]:
  932. atomic = OSCStartEndCondition(element_type, element_name, rule="END", name=state + "Condition")
  933. else:
  934. raise NotImplementedError(
  935. "Only start, stop, endTransitions and completeState are currently supported")
  936. elif value_condition.find('UserDefinedValueCondition') is not None:
  937. raise NotImplementedError("ByValue UserDefinedValue conditions are not yet supported")
  938. elif value_condition.find('TrafficSignalCondition') is not None:
  939. tl_condition = value_condition.find('TrafficSignalCondition')
  940. name_condition = tl_condition.attrib.get('name')
  941. traffic_light = OpenScenarioParser.get_traffic_light_from_osc_name(name_condition)
  942. tl_state = tl_condition.attrib.get('state').upper()
  943. if tl_state not in OpenScenarioParser.tl_states:
  944. raise KeyError("CARLA only supports Green, Red, Yellow or Off")
  945. state_condition = OpenScenarioParser.tl_states[tl_state]
  946. atomic = WaitForTrafficLightState(
  947. traffic_light, state_condition, name=condition_name)
  948. elif value_condition.find('TrafficSignalControllerCondition') is not None:
  949. raise NotImplementedError("ByValue TrafficSignalController conditions are not yet supported")
  950. else:
  951. raise AttributeError("Unknown ByValue condition")
  952. else:
  953. raise AttributeError("Unknown condition")
  954. if delay_atomic is not None and atomic is not None:
  955. new_atomic = py_trees.composites.Sequence("delayed sequence")
  956. new_atomic.add_child(delay_atomic)
  957. new_atomic.add_child(atomic)
  958. else:
  959. new_atomic = atomic
  960. return new_atomic
  961. @staticmethod
  962. def convert_maneuver_to_atomic(action, actor, actor_list, catalogs):
  963. """
  964. Convert an OpenSCENARIO maneuver action into a Behavior atomic
  965. Note not all OpenSCENARIO actions are currently supported
  966. """
  967. maneuver_name = action.attrib.get('name', 'unknown')
  968. if action.find('GlobalAction') is not None:
  969. global_action = action.find('GlobalAction')
  970. if global_action.find('InfrastructureAction') is not None:
  971. infrastructure_action = global_action.find('InfrastructureAction').find('TrafficSignalAction')
  972. if infrastructure_action.find('TrafficSignalStateAction') is not None:
  973. traffic_light_action = infrastructure_action.find('TrafficSignalStateAction')
  974. name_condition = traffic_light_action.attrib.get('name')
  975. traffic_light = OpenScenarioParser.get_traffic_light_from_osc_name(name_condition)
  976. tl_state = traffic_light_action.attrib.get('state').upper()
  977. if tl_state not in OpenScenarioParser.tl_states:
  978. raise KeyError("CARLA only supports Green, Red, Yellow or Off")
  979. traffic_light_state = OpenScenarioParser.tl_states[tl_state]
  980. atomic = TrafficLightStateSetter(
  981. traffic_light, traffic_light_state, name=maneuver_name + "_" + str(traffic_light.id))
  982. else:
  983. raise NotImplementedError("TrafficLights can only be influenced via TrafficSignalStateAction")
  984. elif global_action.find('EnvironmentAction') is not None:
  985. weather_behavior = ChangeWeather(
  986. OpenScenarioParser.get_weather_from_env_action(global_action, catalogs))
  987. friction_behavior = ChangeRoadFriction(
  988. OpenScenarioParser.get_friction_from_env_action(global_action, catalogs))
  989. env_behavior = py_trees.composites.Parallel(
  990. policy=py_trees.common.ParallelPolicy.SUCCESS_ON_ALL, name=maneuver_name)
  991. env_behavior.add_child(
  992. oneshot_with_check(variable_name=maneuver_name + ">WeatherUpdate", behaviour=weather_behavior))
  993. env_behavior.add_child(
  994. oneshot_with_check(variable_name=maneuver_name + ">FrictionUpdate", behaviour=friction_behavior))
  995. return env_behavior
  996. elif global_action.find('ParameterAction') is not None:
  997. parameter_action = global_action.find('ParameterAction')
  998. parameter_ref = parameter_action.attrib.get('parameterRef')
  999. if parameter_action.find('ModifyAction') is not None:
  1000. action_rule = parameter_action.find('ModifyAction').find("Rule")
  1001. if action_rule.find("AddValue") is not None:
  1002. rule, value = '+', action_rule.find("AddValue").attrib.get('value')
  1003. else:
  1004. rule, value = '*', action_rule.find("MultiplyByValue").attrib.get('value')
  1005. else:
  1006. rule, value = None, parameter_action.find('SetAction').attrib.get('value')
  1007. atomic = ChangeParameter(parameter_ref, value=ParameterRef(value), rule=rule, name=maneuver_name)
  1008. else:
  1009. raise NotImplementedError("Global actions are not yet supported")
  1010. elif action.find('UserDefinedAction') is not None:
  1011. user_defined_action = action.find('UserDefinedAction')
  1012. if user_defined_action.find('CustomCommandAction') is not None:
  1013. command = user_defined_action.find('CustomCommandAction').attrib.get('type')
  1014. atomic = RunScript(command, base_path=OpenScenarioParser.osc_filepath, name=maneuver_name)
  1015. elif action.find('PrivateAction') is not None:
  1016. private_action = action.find('PrivateAction')
  1017. if private_action.find('LongitudinalAction') is not None:
  1018. private_action = private_action.find('LongitudinalAction')
  1019. if private_action.find('SpeedAction') is not None:
  1020. long_maneuver = private_action.find('SpeedAction')
  1021. # duration and distance
  1022. distance = float('inf')
  1023. duration = float('inf')
  1024. dimension = long_maneuver.find("SpeedActionDynamics").attrib.get('dynamicsDimension')
  1025. if dimension == "distance":
  1026. distance = ParameterRef(long_maneuver.find("SpeedActionDynamics").attrib.get(
  1027. 'value', float("inf")))
  1028. else:
  1029. duration = ParameterRef(long_maneuver.find("SpeedActionDynamics").attrib.get(
  1030. 'value', float("inf")))
  1031. # absolute velocity with given target speed
  1032. if long_maneuver.find("SpeedActionTarget").find("AbsoluteTargetSpeed") is not None:
  1033. target_speed = ParameterRef(long_maneuver.find("SpeedActionTarget").find(
  1034. "AbsoluteTargetSpeed").attrib.get('value', 0))
  1035. atomic = ChangeActorTargetSpeed(
  1036. actor, float(target_speed), distance=distance, duration=duration, name=maneuver_name)
  1037. # relative velocity to given actor
  1038. if long_maneuver.find("SpeedActionTarget").find("RelativeTargetSpeed") is not None:
  1039. relative_speed = long_maneuver.find("SpeedActionTarget").find("RelativeTargetSpeed")
  1040. obj = relative_speed.attrib.get('entityRef')
  1041. value = ParameterRef(relative_speed.attrib.get('value', 0))
  1042. value_type = relative_speed.attrib.get('speedTargetValueType')
  1043. continuous = bool(strtobool(relative_speed.attrib.get('continuous')))
  1044. for traffic_actor in actor_list:
  1045. if (traffic_actor is not None and 'role_name' in traffic_actor.attributes and
  1046. traffic_actor.attributes['role_name'] == obj):
  1047. obj_actor = traffic_actor
  1048. atomic = ChangeActorTargetSpeed(actor,
  1049. target_speed=0.0,
  1050. relative_actor=obj_actor,
  1051. value=value,
  1052. value_type=value_type,
  1053. continuous=continuous,
  1054. distance=distance,
  1055. duration=duration,
  1056. name=maneuver_name)
  1057. elif private_action.find('LongitudinalDistanceAction') is not None:
  1058. long_dist_action = private_action.find("LongitudinalDistanceAction")
  1059. obj = long_dist_action.attrib.get('entityRef')
  1060. for traffic_actor in actor_list:
  1061. if (traffic_actor is not None and 'role_name' in traffic_actor.attributes and
  1062. traffic_actor.attributes['role_name'] == obj):
  1063. obj_actor = traffic_actor
  1064. if "distance" in long_dist_action.attrib and "timeGap" not in long_dist_action.attrib:
  1065. gap_type, gap = 'distance', ParameterRef(long_dist_action.attrib.get('distance'))
  1066. elif "timeGap" in long_dist_action.attrib and "distance" not in long_dist_action.attrib:
  1067. raise NotImplementedError("LongitudinalDistanceAction: timeGap is not implemented")
  1068. else:
  1069. raise ValueError("LongitudinalDistanceAction: " +
  1070. "Please specify any one attribute of [distance, timeGap]")
  1071. constraints = long_dist_action.find('DynamicConstraints')
  1072. max_speed = constraints.attrib.get('maxSpeed', None) if constraints is not None else None
  1073. continues = bool(strtobool(long_dist_action.attrib.get('continuous')))
  1074. freespace = bool(strtobool(long_dist_action.attrib.get('freespace')))
  1075. atomic = KeepLongitudinalGap(actor, reference_actor=obj_actor, gap=gap, gap_type=gap_type,
  1076. max_speed=max_speed, continues=continues, freespace=freespace,
  1077. name=maneuver_name)
  1078. else:
  1079. raise AttributeError("Unknown longitudinal action")
  1080. elif private_action.find('LateralAction') is not None:
  1081. private_action = private_action.find('LateralAction')
  1082. if private_action.find('LaneChangeAction') is not None:
  1083. # Note: LaneChangeActions are currently only supported for RelativeTargetLane
  1084. lat_maneuver = private_action.find('LaneChangeAction')
  1085. target_lane_rel = ParameterRef(lat_maneuver.find("LaneChangeTarget").find(
  1086. "RelativeTargetLane").attrib.get('value', 0))
  1087. direction = "left" if target_lane_rel > 0 else "right"
  1088. lane_changes = abs(target_lane_rel)
  1089. # duration and distance
  1090. distance = float('inf')
  1091. duration = float('inf')
  1092. dimension = lat_maneuver.find("LaneChangeActionDynamics").attrib.get('dynamicsDimension')
  1093. if dimension == "distance":
  1094. distance = ParameterRef(
  1095. lat_maneuver.find("LaneChangeActionDynamics").attrib.get('value', float("inf")))
  1096. else:
  1097. duration = ParameterRef(
  1098. lat_maneuver.find("LaneChangeActionDynamics").attrib.get('value', float("inf")))
  1099. atomic = ChangeActorLateralMotion(actor, direction=direction,
  1100. distance_lane_change=distance,
  1101. distance_other_lane=10,
  1102. lane_changes=lane_changes,
  1103. name=maneuver_name)
  1104. elif private_action.find('LaneOffsetAction') is not None:
  1105. lat_maneuver = private_action.find('LaneOffsetAction')
  1106. continuous = bool(strtobool(lat_maneuver.attrib.get('continuous', "true")))
  1107. # Parsing of the different Dynamic shapes is missing
  1108. lane_target_offset = lat_maneuver.find('LaneOffsetTarget')
  1109. if lane_target_offset.find('AbsoluteTargetLaneOffset') is not None:
  1110. absolute_offset = ParameterRef(
  1111. lane_target_offset.find('AbsoluteTargetLaneOffset').attrib.get('value', 0))
  1112. atomic = ChangeActorLaneOffset(
  1113. actor, absolute_offset, continuous=continuous, name=maneuver_name)
  1114. elif lane_target_offset.find('RelativeTargetLaneOffset') is not None:
  1115. relative_target_offset = lane_target_offset.find('RelativeTargetLaneOffset')
  1116. relative_offset = ParameterRef(relative_target_offset.attrib.get('value', 0))
  1117. relative_actor = None
  1118. relative_actor_name = relative_target_offset.attrib.get('entityRef', None)
  1119. for _actor in actor_list:
  1120. if _actor is not None and 'role_name' in _actor.attributes:
  1121. if relative_actor_name == _actor.attributes['role_name']:
  1122. relative_actor = _actor
  1123. break
  1124. if relative_actor is None:
  1125. raise AttributeError("Cannot find actor '{}' for condition".format(relative_actor_name))
  1126. atomic = ChangeActorLaneOffset(actor, relative_offset, relative_actor,
  1127. continuous=continuous, name=maneuver_name)
  1128. else:
  1129. raise AttributeError("Unknown target offset")
  1130. else:
  1131. raise AttributeError("Unknown lateral action")
  1132. elif private_action.find('VisibilityAction') is not None:
  1133. raise NotImplementedError("Visibility actions are not yet supported")
  1134. elif private_action.find('SynchronizeAction') is not None:
  1135. sync_action = private_action.find('SynchronizeAction')
  1136. master_actor = None
  1137. for actor_ins in actor_list:
  1138. if actor_ins is not None and 'role_name' in actor_ins.attributes:
  1139. if sync_action.attrib.get('masterEntityRef', None) == actor_ins.attributes['role_name']:
  1140. master_actor = actor_ins
  1141. break
  1142. if master_actor is None:
  1143. raise AttributeError("Cannot find actor '{}' for condition".format(
  1144. sync_action.attrib.get('masterEntityRef', None)))
  1145. master_position = OpenScenarioParser.convert_position_to_transform(
  1146. sync_action.find('TargetPositionMaster'))
  1147. position = OpenScenarioParser.convert_position_to_transform(sync_action.find('TargetPosition'))
  1148. if sync_action.find("FinalSpeed").find("AbsoluteSpeed") is not None:
  1149. final_speed = ParameterRef(sync_action.find("FinalSpeed").find(
  1150. "AbsoluteSpeed").attrib.get('value', 0))
  1151. atomic = SyncArrivalOSC(
  1152. actor, master_actor, position, master_position, final_speed, name=maneuver_name)
  1153. # relative velocity to given actor
  1154. elif sync_action.find("FinalSpeed").find("RelativeSpeedToMaster") is not None:
  1155. relative_speed = sync_action.find("FinalSpeed").find("RelativeSpeedToMaster")
  1156. final_speed = ParameterRef(relative_speed.attrib.get('value', 0))
  1157. relative_type = relative_speed.attrib.get('speedTargetValueType')
  1158. atomic = SyncArrivalOSC(
  1159. actor, master_actor, position, master_position, final_speed,
  1160. relative_to_master=True, relative_type=relative_type, name=maneuver_name)
  1161. else:
  1162. raise AttributeError("Unknown speed action")
  1163. elif private_action.find('ActivateControllerAction') is not None:
  1164. private_action = private_action.find('ActivateControllerAction')
  1165. activate = strtobool(private_action.attrib.get('longitudinal'))
  1166. atomic = ChangeAutoPilot(actor, activate, name=maneuver_name)
  1167. elif private_action.find('ControllerAction') is not None:
  1168. controller_action = private_action.find('ControllerAction')
  1169. module, args = OpenScenarioParser.get_controller(controller_action, catalogs)
  1170. atomic = ChangeActorControl(actor, control_py_module=module, args=args,
  1171. scenario_file_path=OpenScenarioParser.osc_filepath)
  1172. elif private_action.find('TeleportAction') is not None:
  1173. teleport_action = private_action.find('TeleportAction')
  1174. position = teleport_action.find('Position')
  1175. atomic = ActorTransformSetterToOSCPosition(actor, position, name=maneuver_name)
  1176. elif private_action.find('RoutingAction') is not None:
  1177. private_action = private_action.find('RoutingAction')
  1178. if private_action.find('AssignRouteAction') is not None:
  1179. # @TODO: How to handle relative positions here? This might chance at runtime?!
  1180. route_action = private_action.find('AssignRouteAction')
  1181. waypoints = OpenScenarioParser.get_route(route_action, catalogs)
  1182. atomic = ChangeActorWaypoints(actor, waypoints=waypoints, name=maneuver_name)
  1183. elif private_action.find('FollowTrajectoryAction') is not None:
  1184. trajectory_action = private_action.find('FollowTrajectoryAction')
  1185. waypoints, times = OpenScenarioParser.get_trajectory(trajectory_action, catalogs)
  1186. atomic = ChangeActorWaypoints(actor, waypoints=list(zip(waypoints, ['shortest'] * len(waypoints))),
  1187. times=times, name=maneuver_name)
  1188. elif private_action.find('AcquirePositionAction') is not None:
  1189. route_action = private_action.find('AcquirePositionAction')
  1190. osc_position = route_action.find('Position')
  1191. waypoints = [(osc_position, 'fastest')]
  1192. atomic = ChangeActorWaypoints(actor, waypoints=waypoints, name=maneuver_name)
  1193. else:
  1194. raise AttributeError("Unknown private routing action")
  1195. else:
  1196. raise AttributeError("Unknown private action")
  1197. else:
  1198. if list(action):
  1199. raise AttributeError("Unknown action: {}".format(maneuver_name))
  1200. else:
  1201. return Idle(duration=0, name=maneuver_name)
  1202. return atomic