Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,18 @@ We have tested OATomobile on Python 3.5.
1. To install the core libraries (including [CARLA], the backend simulator):

```bash
# The path to download CARLA 0.9.6.
# The path to download CARLA 0.9.10.
export CARLA_ROOT=...
mkdir -p $CARLA_ROOT

# Downloads hosted binaries.
wget http://carla-assets-internal.s3.amazonaws.com/Releases/Linux/CARLA_0.9.6.tar.gz
wget https://carla-releases.s3.eu-west-3.amazonaws.com/Linux/CARLA_0.9.10.tar.gz

# CARLA 0.9.6 installation.
tar -xvzf CARLA_0.9.6.tar.gz -C $CARLA_ROOT
# CARLA 0.9.10 installation.
tar -xvzf CARLA_0.9.10.tar.gz -C $CARLA_ROOT

# Installs CARLA 0.9.6 Python API.
easy_install $CARLA_ROOT/PythonAPI/carla/dist/carla-0.9.6-py3.5-linux-x86_64.egg
# Installs CARLA 0.9.10 Python API.
easy_install $CARLA_ROOT/PythonAPI/carla/dist/carla-0.9.10-py3.7-linux-x86_64.egg
```

1. To install the OATomobile core API:
Expand Down
257 changes: 16 additions & 241 deletions oatomobile/baselines/rulebased/autopilot/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@

import carla
import oatomobile
from oatomobile import envs
from oatomobile.simulators.carla import defaults
from oatomobile.utils import carla as cutil

try:
from agents.navigation.local_planner import \
LocalPlanner # pylint: disable=import-error
from agents.tools.misc import \
compute_magnitude_angle # pylint: disable=import-error
from agents.tools.misc import \
is_within_distance_ahead # pylint: disable=import-error
from agents.navigation.behavior_agent import BehaviorAgent
except ImportError:
raise ImportError("Missing CARLA installation, "
"make sure the environment variable CARLA_ROOT is provided "
Expand All @@ -45,19 +41,13 @@ class AutopilotAgent(oatomobile.Agent):
`carla.PythonAPI.agents.navigation.basic_agent.BasicAgent`"""

def __init__(self,
environment: oatomobile.envs.CARLAEnv,
environment: envs.CARLAEnv,
*,
proximity_tlight_threshold: float = 5.0,
proximity_vehicle_threshold: float = 10.0,
noise: float = 0.1) -> None:
noise: float = 0.0) -> None: # TODO(farzad) why should we have noise=0.1 for autopilot?
"""Constructs an autopilot agent.

Args:
environment: The navigation environment to spawn the agent.
proximity_tlight_threshold: The threshold (in metres) to
the traffic light.
proximity_vehicle_threshold: The threshold (in metres) to
the front vehicle.
noise: The percentage of random actions.
"""
super(AutopilotAgent, self).__init__(environment=environment)
Expand All @@ -66,36 +56,18 @@ def __init__(self,
self._vehicle = self._environment.simulator.hero
self._world = self._vehicle.get_world()
self._map = self._world.get_map()

# Agent hyperparametres.
self._proximity_tlight_threshold = proximity_tlight_threshold
self._proximity_vehicle_threshold = proximity_vehicle_threshold
self._hop_resolution = 2.0
self._path_seperation_hop = 2
self._path_seperation_threshold = 0.5
self._target_speed = defaults.TARGET_SPEED
self._agent = BehaviorAgent(self._vehicle, behavior='normal')
self._noise = noise

# The internal state of the agent.
self._last_traffic_light = None
spawn_points = self._map.get_spawn_points()
random.shuffle(spawn_points)

# Local planner, including the PID controllers.
dt = self._vehicle.get_world().get_settings().fixed_delta_seconds
lateral_control_dict = defaults.LATERAL_PID_CONTROLLER_CONFIG.copy()
lateral_control_dict.update({"dt": dt})
# TODO(filangel): tune the parameters for FPS != 20
self._local_planner = LocalPlanner(
self._vehicle,
opt_dict=dict(
target_speed=self._target_speed,
dt=dt,
),
)
if spawn_points[0].location != self._agent.vehicle.get_location():
destination = spawn_points[0].location
else:
destination = spawn_points[1].location

# Set agent's dsestination.
if hasattr(self._environment.unwrapped.simulator, "destination"):
self._set_destination(
self._environment.unwrapped.simulator.destination.location)
self._agent.set_destination(self._agent.vehicle.get_location(), destination, clean=True)

def act(
self,
Expand Down Expand Up @@ -123,209 +95,12 @@ def _run_step(
) -> carla.VehicleControl: # pylint: disable=no-member
"""Executes one step of navigation."""

# is there an obstacle in front of us?
hazard_detected = False

# retrieve relevant elements for safe navigation, i.e.: traffic lights
# and other vehicles
actor_list = self._world.get_actors()
vehicle_list = actor_list.filter("*vehicle*")
lights_list = actor_list.filter("*traffic_light*")

# check possible obstacles
vehicle_state, vehicle = self._is_vehicle_hazard(vehicle_list)
if vehicle_state:
if debug:
logging.debug('!!! VEHICLE BLOCKING AHEAD [{}])'.format(vehicle.id))

hazard_detected = True

# check for the state of the traffic lights
light_state, traffic_light = self._is_light_red(lights_list)
if light_state:
if debug:
logging.debug('=== RED LIGHT AHEAD [{}])'.format(traffic_light.id))
self._agent.update_information()

hazard_detected = True
speed_limit = self._vehicle.get_speed_limit()
self._agent.get_local_planner().set_speed(speed_limit)

if hazard_detected:
control = carla.VehicleControl() # pylint: disable=no-member
control.steer = 0.0
control.throttle = 0.0
control.brake = 1.0
control.hand_brake = False
else:
# standard local planner behavior
control = self._local_planner.run_step(debug=debug)
control = self._agent.run_step()

return control

def _set_destination(
self,
destination: carla.Location, # pylint: disable=no-member
) -> None:
"""Generates the global plan for the agent.

Args:
destination: The location of the new destination.
"""
# Set vehicle's current location as start for the plan.
origin = self._vehicle.get_location()
start_waypoint = self._map.get_waypoint(origin).transform.location
end_waypoint = self._map.get_waypoint(destination).transform.location
# Calculate the plan.
waypoints, roadoptions, _ = cutil.global_plan(
world=self._world,
origin=start_waypoint,
destination=end_waypoint,
)
# Mutate the local planner's global plan.
self._local_planner.set_global_plan(list(zip(waypoints, roadoptions)))

def _is_vehicle_hazard(
self,
vehicle_list,
) -> Tuple[bool, Optional[carla.Vehicle]]: # pylint: disable=no-member
"""It detects if a vehicle in the scene can be dangerous for the ego
vehicle's current plan.

Args:
vehicle_list: List of potential vehicles (obstancles) to check.

Returns:
vehicle_ahead: If True a vehicle ahead blocking us and False otherwise.
vehicle: The blocker vehicle itself.
"""

ego_vehicle_location = self._vehicle.get_location()
ego_vehicle_waypoint = self._map.get_waypoint(ego_vehicle_location)

for target_vehicle in vehicle_list:
# do not account for the ego vehicle.
if target_vehicle.id == self._vehicle.id:
continue

# if the object is not in our lane it's not an obstacle.
target_vehicle_waypoint = self._map.get_waypoint(
target_vehicle.get_location())
if target_vehicle_waypoint.road_id != ego_vehicle_waypoint.road_id or \
target_vehicle_waypoint.lane_id != ego_vehicle_waypoint.lane_id:
continue

loc = target_vehicle.get_location()
if is_within_distance_ahead(
loc,
ego_vehicle_location,
self._vehicle.get_transform().rotation.yaw,
self._proximity_vehicle_threshold,
):
return (True, target_vehicle)

return (False, None)

def _is_light_red(
self,
lights_list,
) -> Tuple[bool, Any]: # pylint: disable=no-member
"""It detects if the light in the scene is red.

Args:
lights_list: The list containing TrafficLight objects.

Returns:
light_ahead: If True a traffic light ahead is read and False otherwise.
traffic_light: The traffic light object ahead itself.
"""
if self._map.name == 'Town01' or self._map.name == 'Town02':
return self._is_light_red_europe_style(lights_list)
else:
return self._is_light_red_us_style(lights_list)

def _is_light_red_europe_style(self, lights_list):
"""This method is specialized to check European style traffic lights."""
ego_vehicle_location = self._vehicle.get_location()
ego_vehicle_waypoint = self._map.get_waypoint(ego_vehicle_location)

for traffic_light in lights_list:
object_waypoint = self._map.get_waypoint(traffic_light.get_location())
if object_waypoint.road_id != ego_vehicle_waypoint.road_id or \
object_waypoint.lane_id != ego_vehicle_waypoint.lane_id:
continue

loc = traffic_light.get_location()
if is_within_distance_ahead(
loc,
ego_vehicle_location,
self._vehicle.get_transform().rotation.yaw,
self._proximity_tlight_threshold,
):
if traffic_light.state == carla.TrafficLightState.Red: # pylint: disable=no-member
return (True, traffic_light)

return (False, None)

def _is_light_red_us_style(self, lights_list, debug=False):
"""This method is specialized to check US style traffic lights."""
ego_vehicle_location = self._vehicle.get_location()
ego_vehicle_waypoint = self._map.get_waypoint(ego_vehicle_location)

if ego_vehicle_waypoint.is_junction:
# It is too late. Do not block the intersection! Keep going!
return (False, None)

if self._local_planner.target_waypoint is not None:
if self._local_planner.target_waypoint.is_junction:
min_angle = 180.0
sel_magnitude = 0.0
sel_traffic_light = None
for traffic_light in lights_list:
loc = traffic_light.get_location()
magnitude, angle = compute_magnitude_angle(
loc, ego_vehicle_location,
self._vehicle.get_transform().rotation.yaw)
if magnitude < 60.0 and angle < min(25.0, min_angle):
sel_magnitude = magnitude
sel_traffic_light = traffic_light
min_angle = angle

if sel_traffic_light is not None:
if debug:
logging.debug('=== Magnitude = {} | Angle = {} | ID = {}'.format(
sel_magnitude, min_angle, sel_traffic_light.id))

if self._last_traffic_light is None:
self._last_traffic_light = sel_traffic_light

if self._last_traffic_light.state == carla.TrafficLightState.Red: # pylint: disable=no-member
return (True, self._last_traffic_light)
else:
self._last_traffic_light = None

return (False, None)

def _get_trafficlight_trigger_location(
self,
traffic_light,
) -> carla.Location: # pylint: disable=no-member
"""Calculates the yaw of the waypoint that represents the trigger volume of
the traffic light."""

def rotate_point(point, radians):
"""Rotates a given point by a given angle."""
rotated_x = math.cos(radians) * point.x - math.sin(radians) * point.y
rotated_y = math.sin(radians) * point.x - math.cos(radians) * point.y

return carla.Vector3D(rotated_x, rotated_y, point.z) # pylint: disable=no-member

base_transform = traffic_light.get_transform()
base_rot = base_transform.rotation.yaw
area_loc = base_transform.transform(traffic_light.trigger_volume.location)
area_ext = traffic_light.trigger_volume.extent

point = rotate_point(
carla.Vector3D(0, 0, area_ext.z), # pylint: disable=no-member
math.radians(base_rot),
)
point_location = area_loc + carla.Location(x=point.x, y=point.y) # pylint: disable=no-member

return carla.Location(point_location.x, point_location.y, point_location.z) # pylint: disable=no-member
12 changes: 10 additions & 2 deletions oatomobile/baselines/rulebased/autopilot/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@
default=False,
help="If True it spawn the `PyGame` display.",
)

flags.DEFINE_bool(
name="off_screen",
default=False,
help="If True it runs the Carla server in off-screen mode",
)

def main(argv):
# Debugging purposes.
Expand All @@ -80,13 +84,15 @@ def main(argv):
max_episode_steps = FLAGS.max_episode_steps
output_dir = FLAGS.output_dir
render = FLAGS.render
off_screen = FLAGS.off_screen

try:
# Setups the environment.
env = oatomobile.envs.CARLAEnv(
town=town,
fps=20,
sensors=sensors,
off_screen=off_screen
)
if max_episode_steps is not None:
env = oatomobile.FiniteHorizonWrapper(
Expand All @@ -95,7 +101,9 @@ def main(argv):
)
if output_dir is not None:
env = oatomobile.SaveToDiskWrapper(env, output_dir=output_dir)
env = oatomobile.MonitorWrapper(env, output_fname="tmp/yoo.gif")

# MonitorWrapper is incompatible with render_mode = human. Either it or --render should be used at the same time.
env = oatomobile.MonitorWrapper(env, output_fname="carla_dataset/carla_dataset.gif")

# Runs the environment loop.
oatomobile.EnvironmentLoop(
Expand Down
9 changes: 7 additions & 2 deletions oatomobile/baselines/rulebased/blind/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@
default=False,
help="If True it spawn the `PyGame` display.",
)

flags.DEFINE_bool(
name="off_screen",
default=False,
help="If True it runs the Carla server in off-screen mode",
)

def main(argv):
# Debugging purposes.
Expand All @@ -83,7 +87,7 @@ def main(argv):
max_episode_steps = FLAGS.max_episode_steps
output_dir = FLAGS.output_dir
render = FLAGS.render

off_screen = FLAGS.off_screen
try:
# Setups the environment.
env = oatomobile.envs.CARLANavEnv(
Expand All @@ -92,6 +96,7 @@ def main(argv):
destination=25,
fps=20,
sensors=sensors,
off_screen=off_screen
)
if max_episode_steps is not None:
env = oatomobile.FiniteHorizonWrapper(
Expand Down
Loading