metrics_parser.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. #!/usr/bin/env python
  2. # Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma de
  3. # Barcelona (UAB).
  4. #
  5. # This work is licensed under the terms of the MIT license.
  6. # For a copy, see <https://opensource.org/licenses/MIT>.
  7. """
  8. Support class of the MetricsManager to parse the information of
  9. the CARLA recorder into a readable dictionary
  10. """
  11. import carla
  12. def parse_actor(info):
  13. """Returns a dictionary with the basic actor information"""
  14. actor = {
  15. "type_id": info[2],
  16. "location": carla.Location(
  17. x=float(info[5][1:-1]) / 100,
  18. y=float(info[6][:-1]) / 100,
  19. z=float(info[7][:-1]) / 100
  20. )
  21. }
  22. return actor
  23. def parse_transform(info):
  24. """Parses a list into a carla.Transform"""
  25. transform = carla.Transform(
  26. carla.Location(
  27. x=float(info[3][1:-1]) / 100,
  28. y=float(info[4][:-1]) / 100,
  29. z=float(info[5][:-1]) / 100,
  30. ),
  31. carla.Rotation(
  32. roll=float(info[7][1:-1]),
  33. pitch=float(info[8][:-1]),
  34. yaw=float(info[9][:-1])
  35. )
  36. )
  37. return transform
  38. def parse_control(info):
  39. """Parses a list into a carla.VehicleControl"""
  40. control = carla.VehicleControl(
  41. throttle=float(info[5]),
  42. steer=float(info[3]),
  43. brake=float(info[7]),
  44. hand_brake=bool(int(info[9])),
  45. reverse=int(info[11]) < 0,
  46. manual_gear_shift=False,
  47. gear=int(info[11]),
  48. )
  49. return control
  50. def parse_vehicle_lights(info):
  51. """Parses a list into a carla.VehicleLightState"""
  52. srt_to_vlight = {
  53. "None": carla.VehicleLightState.NONE,
  54. "Position": carla.VehicleLightState.Position,
  55. "LowBeam": carla.VehicleLightState.LowBeam,
  56. "HighBeam": carla.VehicleLightState.HighBeam,
  57. "Brake": carla.VehicleLightState.Brake,
  58. "RightBlinker": carla.VehicleLightState.RightBlinker,
  59. "LeftBlinker": carla.VehicleLightState.LeftBlinker,
  60. "Reverse": carla.VehicleLightState.Reverse,
  61. "Fog": carla.VehicleLightState.Fog,
  62. "Interior": carla.VehicleLightState.Interior,
  63. "Special1": carla.VehicleLightState.Special1,
  64. "Special2": carla.VehicleLightState.Special2,
  65. }
  66. lights = []
  67. for i in range(2, len(info)):
  68. lights.append(srt_to_vlight[info[i]])
  69. return lights
  70. def parse_traffic_light(info):
  71. """Parses a list into a dictionary with all the traffic light's information"""
  72. number_to_state = {
  73. "0": carla.TrafficLightState.Red,
  74. "1": carla.TrafficLightState.Yellow,
  75. "2": carla.TrafficLightState.Green,
  76. "3": carla.TrafficLightState.Off,
  77. "4": carla.TrafficLightState.Unknown,
  78. }
  79. traffic_light = {
  80. "state": number_to_state[info[3]],
  81. "frozen": bool(int(info[5])),
  82. "elapsed_time": float(info[7]),
  83. }
  84. return traffic_light
  85. def parse_velocity(info):
  86. """Parses a list into a carla.Vector3D with the velocity"""
  87. velocity = carla.Vector3D(
  88. x=float(info[3][1:-1]),
  89. y=float(info[4][:-1]),
  90. z=float(info[5][:-1])
  91. )
  92. return velocity
  93. def parse_angular_velocity(info):
  94. """Parses a list into a carla.Vector3D with the angular velocity"""
  95. velocity = carla.Vector3D(
  96. x=float(info[7][1:-1]),
  97. y=float(info[8][:-1]),
  98. z=float(info[9][:-1])
  99. )
  100. return velocity
  101. def parse_scene_lights(info):
  102. """Parses a list into a carla.VehicleLightState"""
  103. red = int(float(info[7][1:-1]) * 255)
  104. green = int(float(info[8][:-1]) * 255)
  105. blue = int(float(info[9][:-1]) * 255)
  106. scene_light = carla.LightState(
  107. intensity=int(float(info[5])),
  108. color=carla.Color(red, green, blue),
  109. group=carla.LightGroup.NONE,
  110. active=bool(info[3])
  111. )
  112. return scene_light
  113. def parse_bounding_box(info):
  114. """
  115. Parses a list into a carla.BoundingBox.
  116. Some actors like sensors might have 'nan' location and 'inf' extent, so filter those.
  117. """
  118. if 'nan' in info[3]:
  119. location = carla.Location()
  120. else:
  121. location = carla.Location(
  122. float(info[3][1:-1])/100,
  123. float(info[4][:-1])/100,
  124. float(info[5][:-1])/100,
  125. )
  126. if 'inf' in info[7]:
  127. extent = carla.Vector3D()
  128. else:
  129. extent = carla.Vector3D(
  130. float(info[7][1:-1])/100,
  131. float(info[8][:-1])/100,
  132. float(info[9][:-1])/100,
  133. )
  134. bbox = carla.BoundingBox(location, extent)
  135. return bbox
  136. def parse_state_times(info):
  137. """Parses a list into a dict containing the state times of the traffic lights"""
  138. state_times = {
  139. carla.TrafficLightState.Green: float(info[3]),
  140. carla.TrafficLightState.Yellow: float(info[5]),
  141. carla.TrafficLightState.Red: float(info[7]),
  142. }
  143. return state_times
  144. def parse_vector_list(info):
  145. """Parses a list of string into a list of Vector2D"""
  146. vector_list = []
  147. for i in range(0, len(info), 2):
  148. vector = carla.Vector2D(
  149. x=float(info[i][1:-1]),
  150. y=float(info[i+1][:-1]),
  151. )
  152. vector_list.append(vector)
  153. return vector_list
  154. def parse_gears_control(info):
  155. """Parses a list into a GearPhysicsControl"""
  156. gears_control = carla.GearPhysicsControl(
  157. ratio=float(info[3]),
  158. down_ratio=float(info[5]),
  159. up_ratio=float(info[7]),
  160. )
  161. return gears_control
  162. def parse_wheels_control(info):
  163. """Parses a list into a WheelsPhysicsControl"""
  164. wheels_control = carla.WheelPhysicsControl(
  165. tire_friction=float(info[3]),
  166. damping_rate=float(info[5]),
  167. max_steer_angle=float(info[7]),
  168. radius=float(info[9]),
  169. max_brake_torque=float(info[11]),
  170. max_handbrake_torque=float(info[13]),
  171. position=carla.Vector3D(
  172. x=float(info[17][1:-1]) / 100,
  173. y=float(info[17][:-1]) / 100,
  174. z=float(info[17][:-1]) / 100)
  175. )
  176. return wheels_control
  177. class MetricsParser(object):
  178. """
  179. Class used to parse the CARLA recorder into readable information
  180. """
  181. def __init__(self, recorder_info):
  182. self.recorder_info = recorder_info
  183. self.frame_list = None
  184. self.frame_row = None
  185. self.i = 0
  186. def get_row_elements(self, indent_num, split_string):
  187. """
  188. returns a list with the elements of the row
  189. """
  190. return self.frame_row[indent_num:].split(split_string)
  191. def next_row(self):
  192. """
  193. Gets the next row of the recorder
  194. """
  195. self.i += 1
  196. self.frame_row = self.frame_list[self.i]
  197. def parse_recorder_info(self):
  198. """
  199. Parses the recorder into readable information.
  200. Args:
  201. recorder_info (str): string given by the recorder
  202. """
  203. # Divide it into frames
  204. recorder_list = self.recorder_info.split("Frame")
  205. # Get general information
  206. header = recorder_list[0].split("\n")
  207. sim_map = header[1][5:]
  208. sim_date = header[2][6:]
  209. annex = recorder_list[-1].split("\n")
  210. sim_frames = int(annex[0][3:])
  211. sim_duration = float(annex[1][10:-8])
  212. recorder_list = recorder_list[1:-1]
  213. simulation_info = {
  214. "map": sim_map,
  215. "date:": sim_date,
  216. "total_frames": sim_frames,
  217. "duration": sim_duration
  218. }
  219. actors_info = {}
  220. frames_info = []
  221. for frame in recorder_list:
  222. # Divide the frame in lines
  223. self.frame_list = frame.split("\n")
  224. # Get the general frame information
  225. frame_info = self.frame_list[0].split(" ")
  226. frame_number = int(frame_info[1])
  227. frame_time = float(frame_info[3])
  228. try:
  229. prev_frame = frames_info[frame_number - 2]
  230. prev_time = prev_frame["frame"]["elapsed_time"]
  231. delta_time = round(frame_time - prev_time, 6)
  232. except IndexError:
  233. delta_time = 0
  234. # Variable to store all the information about the frame
  235. frame_state = {
  236. "frame": {
  237. "elapsed_time": frame_time,
  238. "delta_time": delta_time,
  239. "platform_time": None
  240. },
  241. "actors": {},
  242. "events":{
  243. "scene_lights": {},
  244. "physics_control": {},
  245. "traffic_light_state_time": {},
  246. "collisions": {}
  247. }
  248. }
  249. # Loop through all the other rows.
  250. self.i = 0
  251. self.next_row()
  252. while self.frame_row.startswith(' Create') or self.frame_row.startswith(' '):
  253. if self.frame_row.startswith(' Create'):
  254. elements = self.get_row_elements(1, " ")
  255. actor_id = int(elements[1][:-1])
  256. actor = parse_actor(elements)
  257. actors_info.update({actor_id: actor})
  258. actors_info[actor_id].update({"created": frame_number})
  259. else:
  260. elements = self.get_row_elements(2, " = ")
  261. actors_info[actor_id].update({elements[0]: elements[1]})
  262. self.next_row()
  263. while self.frame_row.startswith(' Destroy'):
  264. elements = self.get_row_elements(1, " ")
  265. actor_id = int(elements[1])
  266. actors_info[actor_id].update({"destroyed": frame_number})
  267. self.next_row()
  268. while self.frame_row.startswith(' Collision'):
  269. elements = self.get_row_elements(1, " ")
  270. actor_id = int(elements[4])
  271. other_id = int(elements[-1])
  272. if actor_id not in frame_state["events"]["collisions"]:
  273. frame_state["events"]["collisions"][actor_id] = [other_id]
  274. else:
  275. collisions = frame_state["events"]["collisions"][actor_id]
  276. collisions.append(other_id)
  277. frame_state["events"]["collisions"].update({actor_id: collisions})
  278. self.next_row()
  279. while self.frame_row.startswith(' Parenting'):
  280. elements = self.get_row_elements(1, " ")
  281. actor_id = int(elements[1])
  282. parent_id = int(elements[3])
  283. actors_info[actor_id].update({"parent": parent_id})
  284. self.next_row()
  285. if self.frame_row.startswith(' Positions'):
  286. self.next_row()
  287. while self.frame_row.startswith(' '):
  288. elements = self.get_row_elements(2, " ")
  289. actor_id = int(elements[1])
  290. transform = parse_transform(elements)
  291. frame_state["actors"].update({actor_id: {"transform": transform}})
  292. self.next_row()
  293. if self.frame_row.startswith(' State traffic lights'):
  294. self.next_row()
  295. while self.frame_row.startswith(' '):
  296. elements = self.get_row_elements(2, " ")
  297. actor_id = int(elements[1])
  298. traffic_light = parse_traffic_light(elements)
  299. frame_state["actors"].update({actor_id: traffic_light})
  300. self.next_row()
  301. if self.frame_row.startswith(' Vehicle animations'):
  302. self.next_row()
  303. while self.frame_row.startswith(' '):
  304. elements = self.get_row_elements(2, " ")
  305. actor_id = int(elements[1])
  306. control = parse_control(elements)
  307. frame_state["actors"][actor_id].update({"control": control})
  308. self.next_row()
  309. if self.frame_row.startswith(' Walker animations'):
  310. self.next_row()
  311. while self.frame_row.startswith(' '):
  312. elements = self.get_row_elements(2, " ")
  313. actor_id = int(elements[1])
  314. frame_state["actors"][actor_id].update({"speed": elements[3]})
  315. self.next_row()
  316. if self.frame_row.startswith(' Vehicle light animations'):
  317. self.next_row()
  318. while self.frame_row.startswith(' '):
  319. elements = self.get_row_elements(2, " ")
  320. actor_id = int(elements[1])
  321. lights = parse_vehicle_lights(elements)
  322. frame_state["actors"][actor_id].update({"lights": lights})
  323. self.next_row()
  324. if self.frame_row.startswith(' Scene light changes'):
  325. self.next_row()
  326. while self.frame_row.startswith(' '):
  327. elements = self.get_row_elements(2, " ")
  328. actor_id = int(elements[1])
  329. scene_light = parse_scene_lights(elements)
  330. frame_state["events"]["scene_lights"].update({actor_id: scene_light})
  331. self.next_row()
  332. if self.frame_row.startswith(' Dynamic actors'):
  333. self.next_row()
  334. while self.frame_row.startswith(' '):
  335. elements = self.get_row_elements(2, " ")
  336. actor_id = int(elements[1])
  337. velocity = parse_velocity(elements)
  338. frame_state["actors"][actor_id].update({"velocity": velocity})
  339. angular_v = parse_angular_velocity(elements)
  340. frame_state["actors"][actor_id].update({"angular_velocity": angular_v})
  341. if delta_time == 0:
  342. acceleration = carla.Vector3D(0, 0, 0)
  343. else:
  344. prev_velocity = frame_state["actors"][actor_id]["velocity"]
  345. acceleration = (velocity - prev_velocity) / delta_time
  346. frame_state["actors"][actor_id].update({"acceleration": acceleration})
  347. self.next_row()
  348. if self.frame_row.startswith(' Actor bounding boxes'):
  349. self.next_row()
  350. while self.frame_row.startswith(' '):
  351. elements = self.get_row_elements(2, " ")
  352. actor_id = int(elements[1])
  353. bbox = parse_bounding_box(elements)
  354. actors_info[actor_id].update({"bounding_box": bbox})
  355. self.next_row()
  356. if self.frame_row.startswith(' Actor trigger volumes'):
  357. self.next_row()
  358. while self.frame_row.startswith(' '):
  359. elements = self.get_row_elements(2, " ")
  360. actor_id = int(elements[1])
  361. trigvol = parse_bounding_box(elements)
  362. actors_info[actor_id].update({"trigger_volume": trigvol})
  363. self.next_row()
  364. if self.frame_row.startswith(' Current platform time'):
  365. elements = self.get_row_elements(1, " ")
  366. platform_time = float(elements[-1])
  367. frame_state["frame"]["platform_time"] = platform_time
  368. self.next_row()
  369. if self.frame_row.startswith(' Physics Control'):
  370. self.next_row()
  371. actor_id = None
  372. while self.frame_row.startswith(' '):
  373. elements = self.get_row_elements(2, " ")
  374. actor_id = int(elements[1])
  375. physics_control = carla.VehiclePhysicsControl()
  376. self.next_row()
  377. forward_gears = []
  378. wheels = []
  379. while self.frame_row.startswith(' '):
  380. if self.frame_row.startswith(' '):
  381. elements = self.get_row_elements(4, " ")
  382. if elements[0] == "gear":
  383. forward_gears.append(parse_gears_control(elements))
  384. elif elements[0] == "wheel":
  385. wheels.append(parse_wheels_control(elements))
  386. else:
  387. elements = self.get_row_elements(3, " = ")
  388. name = elements[0]
  389. if name == "center_of_mass":
  390. values = elements[1].split(" ")
  391. value = carla.Vector3D(
  392. float(values[0][1:-1]),
  393. float(values[1][:-1]),
  394. float(values[2][:-1]),
  395. )
  396. setattr(physics_control, name, value)
  397. elif name == "torque_curve" or name == "steering_curve":
  398. values = elements[1].split(" ")
  399. value = parse_vector_list(values)
  400. setattr(physics_control, name, value)
  401. elif name == "use_gear_auto_box":
  402. name = "use_gear_autobox"
  403. value = True if elements[1] == "true" else False
  404. setattr(physics_control, name, value)
  405. elif "forward_gears" in name or "wheels" in name:
  406. pass
  407. else:
  408. name = name.lower()
  409. value = float(elements[1])
  410. setattr(physics_control, name, value)
  411. self.next_row()
  412. setattr(physics_control, "forward_gears", forward_gears)
  413. setattr(physics_control, "wheels", wheels)
  414. frame_state["events"]["physics_control"].update({actor_id: physics_control})
  415. if self.frame_row.startswith(' Traffic Light time events'):
  416. self.next_row()
  417. while self.frame_row.startswith(' '):
  418. elements = self.get_row_elements(2, " ")
  419. actor_id = int(elements[1])
  420. state_times = parse_state_times(elements)
  421. frame_state["events"]["traffic_light_state_time"].update({actor_id: state_times})
  422. self.next_row()
  423. frames_info.append(frame_state)
  424. return simulation_info, actors_info, frames_info