text: #!/usr/bin/env python
  
  # Copyright (c) 2019 Computer Vision Center (CVC) at the Universitat Autonoma de
  # Barcelona (UAB).
  #
  
  # Copyright (c) 2021 FrostBit Software Lab
  
  # This work is licensed under the terms of the MIT license.
  # For a copy, see <https://opensource.org/licenses/MIT>.
  
  # ==============================================================================
  # -- imports -------------------------------------------------------------------
  # ==============================================================================
  
  import glob
  import os
  import sys
  from queue import Queue
  import numpy as np
  
  try:
      sys.path.append(glob.glob('../carla/dist/carla-*%d.%d-%s.egg' % (
          sys.version_info.major,
          sys.version_info.minor,
          'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0])
  except IndexError:
      pass
  
  import argparse
  import collections
  import datetime
  import logging
  import math
  import random
  import re
  import weakref
  import carla
  from carla import ColorConverter as cc
  import time
  
  # ==============================================================================
  # -- Global functions ----------------------------------------------------------
  # ==============================================================================
  
  def get_actor_display_name(actor, truncate=250):
      name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:])
      return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name
  
  # ==============================================================================
  # -- CollisionSensor -----------------------------------------------------------
  # ==============================================================================
  
  class CollisionSensor(object):
      def __init__(self, parent_actor, hud):
          self.sensor = None
          self.history = []
          self._parent = parent_actor
          self.hud = hud
          world = self._parent.get_world()
          bp = world.get_blueprint_library().find('sensor.other.collision')
          self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
          # We need to pass the lambda a weak reference to self to avoid circular reference.
          weak_self = weakref.ref(self)
          self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event))
  
      def get_collision_history(self):
          history = collections.defaultdict(int)
          for frame, intensity in self.history:
              history[frame] += intensity
          return history
  
      @staticmethod
      def _on_collision(weak_self, event):
          self = weak_self()
          if not self:
              return
          actor_type = get_actor_display_name(event.other_actor)
          self.hud.notification('Collision with %r' % actor_type)
          impulse = event.normal_impulse
          intensity = math.sqrt(impulse.x**2 + impulse.y**2 + impulse.z**2)
          self.history.append((event.frame, intensity))
          if len(self.history) > 4000:
              self.history.pop(0)
  
  # ==============================================================================
  # -- LaneInvasionSensor --------------------------------------------------------
  # ==============================================================================
  
  class LaneInvasionSensor(object):
      def __init__(self, parent_actor, hud):
          self.sensor = None
          self._parent = parent_actor
          self.hud = hud
          world = self._parent.get_world()
          bp = world.get_blueprint_library().find('sensor.other.lane_invasion')
          self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
          weak_self = weakref.ref(self)
          self.sensor.listen(lambda event: LaneInvasionSensor._on_invasion(weak_self, event))
  
      @staticmethod
      def _on_invasion(weak_self, event):
          self = weak_self()
          if not self:
              return
          lane_types = set(x.type for x in event.crossed_lane_markings)
          text = ['%r' % str(x).split()[-1] for x in lane_types]
          self.hud.notification('Crossed line %s' % ' and '.join(text))
  
  # ==============================================================================
  # -- GnssSensor ----------------------------------------------------------------
  # ==============================================================================
  
  class GnssSensor(object):
      def __init__(self, parent_actor):
          self.sensor = None
          self._parent = parent_actor
          self.lat = 0.0
          self.lon = 0.0
          world = self._parent.get_world()
          bp = world.get_blueprint_library().find('sensor.other.gnss')
          self.sensor = world.spawn_actor(bp, carla.Transform(carla.Location(x=1.0, z=2.8)), attach_to=self._parent)
          weak_self = weakref.ref(self)
          self.sensor.listen(lambda event: GnssSensor._on_gnss_event(weak_self, event))
  
      @staticmethod
      def _on_gnss_event(weak_self, event):
          self = weak_self()
          if not self:
              return
          self.lat = event.latitude
          self.lon = event.longitude
  
  # ==============================================================================
  # -- IMUSensor -----------------------------------------------------------------
  # ==============================================================================
  
  class IMUSensor(object):
      def __init__(self, parent_actor):
          self.sensor = None
          self._parent = parent_actor
          self.accelerometer = (0.0, 0.0, 0.0)
          self.gyroscope = (0.0, 0.0, 0.0)
          self.compass = 0.0
          world = self._parent.get_world()
          bp = world.get_blueprint_library().find('sensor.other.imu')
          self.sensor = world.spawn_actor(
              bp, carla.Transform(), attach_to=self._parent)
          weak_self = weakref.ref(self)
          self.sensor.listen(lambda sensor_data: IMUSensor._IMU_callback(weak_self, sensor_data))
  
      @staticmethod
      def _IMU_callback(weak_self, sensor_data):
          self = weak_self()
          if not self:
              return
          limits = (-99.9, 99.9)
          self.accelerometer = (
              max(limits[0], min(limits[1], sensor_data.accelerometer.x)),
              max(limits[0], min(limits[1], sensor_data.accelerometer.y)),
              max(limits[0], min(limits[1], sensor_data.accelerometer.z)))
          self.gyroscope = (
              max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.x))),
              max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.y))),
              max(limits[0], min(limits[1], math.degrees(sensor_data.gyroscope.z))))
          self.compass = math.degrees(sensor_data.compass)
          
  # ==============================================================================
  # -- RadarSensor ---------------------------------------------------------------
  # ==============================================================================
  
  class RadarSensor(object):
      def __init__(self, parent_actor):
          self.sensor = None
          self._parent = parent_actor
          self.velocity_range = 7.5 # m/s
  
      def spawn_radar(self):
          world = self._parent.get_world()
          self.debug = world.debug
          bp = world.get_blueprint_library().find('sensor.other.radar')
          bp.set_attribute('horizontal_fov', str(35))
          bp.set_attribute('vertical_fov', str(20))
          self.sensor = world.spawn_actor(bp,
              carla.Transform(carla.Location(x=2.8, z=1.0),
              carla.Rotation(pitch=5)),attach_to=self._parent)
          weak_self = weakref.ref(self)
          self.sensor.listen(lambda radar_data: RadarSensor._Radar_callback(weak_self, radar_data))
  
      @staticmethod
      def _Radar_callback(weak_self, radar_data):
          self = weak_self()
          if not self:
              return
  
          current_rot = radar_data.transform.rotation
          for detect in radar_data:
              azi = math.degrees(detect.azimuth)
              alt = math.degrees(detect.altitude)
              fw_vec = carla.Vector3D(x=detect.depth - 0.25)  # The 0.25 adjusts a bit the distance so the dots can be properly seen
              carla.Transform(carla.Location(), carla.Rotation(
                      pitch=current_rot.pitch + alt,
                      yaw=current_rot.yaw + azi,
                      roll=current_rot.roll)).transform(fw_vec)
  
              def clamp(min_v, max_v, value):
                  return max(min_v, min(value, max_v))
  
              norm_velocity = detect.velocity / self.velocity_range
              r = int(clamp(0.0, 1.0, 0.0 - norm_velocity) * 255.0)
              g = int(clamp(0.0, 0.0, 0.0 - abs(norm_velocity)) * 255.0)
              b = int(abs(clamp(- 1.0, 0.0, - 1.0 - norm_velocity)) * 255.0)
              dot_color = carla.Color(r, g, b)
              #dot_color = carla.Color(0, 0, 255)
  
              self.debug.draw_point(
                  radar_data.transform.location + fw_vec,
                  size=0.08,
                  life_time=0.17,
                  persistent_lines=False,
                  color=dot_color)
  
      def destroy_radar(self):
          self.sensor.stop()
          self.sensor.destroy()