Merge pull request #1198 from carla-simulator/pravinblaze-agent

Pravinblaze agent
This commit is contained in:
germanros1987 2019-01-30 13:55:47 -08:00 committed by GitHub
commit 39f8e34bcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 49 deletions

View File

@ -1,6 +1,8 @@
## Latest changes ## Latest changes
* Fixed global route planner to handle round about turns and made the code consistent with local planner * Fixed global route planner to handle round about turns and made the code consistent with local planner
* Basic agent integrated with global router
* Fixed local planner to avoid premature route pruning at path overlaps
* Upgraded to Unreal Engine 4.21 * Upgraded to Unreal Engine 4.21
* Upgraded Boost to 1.69.0 * Upgraded Boost to 1.69.0
* Added point transformation functionality for LibCarla and PythonAPI * Added point transformation functionality for LibCarla and PythonAPI

View File

@ -10,10 +10,17 @@
waypoints and avoiding other vehicles. waypoints and avoiding other vehicles.
The agent also responds to traffic lights. """ The agent also responds to traffic lights. """
import math
import numpy as np
import carla import carla
from agents.navigation.agent import * from agents.navigation.agent import *
from agents.navigation.local_planner import LocalPlanner from agents.navigation.local_planner import LocalPlanner
from agents.navigation.local_planner import compute_connection, RoadOption from agents.navigation.local_planner import compute_connection, RoadOption
from agents.navigation.global_route_planner import GlobalRoutePlanner
from agents.navigation.global_route_planner_dao import GlobalRoutePlannerDAO
from agents.tools.misc import vector
class BasicAgent(Agent): class BasicAgent(Agent):
""" """
@ -31,46 +38,85 @@ class BasicAgent(Agent):
self._proximity_threshold = 10.0 # meters self._proximity_threshold = 10.0 # meters
self._state = AgentState.NAVIGATING self._state = AgentState.NAVIGATING
self._local_planner = LocalPlanner(self._vehicle, opt_dict={'target_speed' : target_speed}) self._local_planner = LocalPlanner(self._vehicle, opt_dict={'target_speed' : target_speed})
self._hop_resolution = 2.0
# setting up global router # setting up global router
self._current_plan = None self._current_plan = None
def set_destination(self, location): def set_destination(self, location):
start_waypoint = self._map.get_waypoint(self._vehicle.get_location()) start_waypoint = self._map.get_waypoint(self._vehicle.get_location())
end_waypoint = self._map.get_waypoint(carla.Location(location[0], end_waypoint = self._map.get_waypoint(
location[1], carla.Location(location[0], location[1], location[2]))
location[2])) solution = []
# Setting up global router
dao = GlobalRoutePlannerDAO(self._vehicle.get_world().get_map())
grp = GlobalRoutePlanner(dao)
grp.setup()
# Obtain route plan
x1 = start_waypoint.transform.location.x
y1 = start_waypoint.transform.location.y
x2 = end_waypoint.transform.location.x
y2 = end_waypoint.transform.location.y
route = grp.plan_route((x1, y1), (x2, y2))
current_waypoint = start_waypoint current_waypoint = start_waypoint
active_list = [ [(current_waypoint, RoadOption.LANEFOLLOW)] ] route.append(RoadOption.VOID)
for action in route:
solution = [] # Generate waypoints to next junction
while not solution: wp_choice = current_waypoint.next(self._hop_resolution)
for _ in range(len(active_list)): while len(wp_choice) == 1:
trajectory = active_list.pop() current_waypoint = wp_choice[0]
if len(trajectory) > 1000: solution.append((current_waypoint, RoadOption.LANEFOLLOW))
continue wp_choice = current_waypoint.next(self._hop_resolution)
# Stop at destination
if current_waypoint.transform.location.distance(
end_waypoint.transform.location) < self._hop_resolution: break
if action == RoadOption.VOID: break
# expand this trajectory # Select appropriate path at the junction
current_waypoint, _ = trajectory[-1] if len(wp_choice) > 1:
next_waypoints = current_waypoint.next(5.0)
while len(next_waypoints) == 1:
next_option = compute_connection(current_waypoint, next_waypoints[0])
current_distance = next_waypoints[0].transform.location.distance(end_waypoint.transform.location)
if current_distance < 5.0:
solution = trajectory + [(end_waypoint, RoadOption.LANEFOLLOW)]
break
# keep adding nodes # Current heading vector
trajectory.append((next_waypoints[0], next_option)) current_transform = current_waypoint.transform
current_waypoint, _ = trajectory[-1] current_location = current_transform.location
next_waypoints = current_waypoint.next(5.0) projected_location = current_location + \
carla.Location(
x=math.cos(math.radians(current_transform.rotation.yaw)),
y=math.sin(math.radians(current_transform.rotation.yaw)))
v_current = vector(current_location, projected_location)
if not solution: direction = 0
# multiple choices if action == RoadOption.LEFT:
for waypoint in next_waypoints: direction = 1
next_option = compute_connection(current_waypoint, waypoint) elif action == RoadOption.RIGHT:
active_list.append(trajectory + [(waypoint, next_option)]) direction = -1
elif action == RoadOption.STRAIGHT:
direction = 0
select_criteria = float('inf')
# Choose correct path
for wp_select in wp_choice:
v_select = vector(
current_location, wp_select.transform.location)
cross = float('inf')
if direction == 0:
cross = abs(np.cross(v_current, v_select)[-1])
else:
cross = direction*np.cross(v_current, v_select)[-1]
if cross < select_criteria:
select_criteria = cross
current_waypoint = wp_select
# Generate all waypoints within the junction
# along selected path
solution.append((current_waypoint, action))
current_waypoint = current_waypoint.next(self._hop_resolution)[0]
while current_waypoint.is_intersection:
solution.append((current_waypoint, action))
current_waypoint = current_waypoint.next(self._hop_resolution)[0]
assert solution assert solution

View File

@ -46,13 +46,12 @@ class GlobalRoutePlanner(object):
The following function generates the route plan based on The following function generates the route plan based on
origin : tuple containing x, y of the route's start position origin : tuple containing x, y of the route's start position
destination : tuple containing x, y of the route's end position destination : tuple containing x, y of the route's end position
return : list of turn by turn navigation decisions as return : list of turn by turn navigation decisions as
NavEnum elements agents.navigation.local_planner.RoadOption elements
Possible values (for now) are START, GO_STRAIGHT, LEFT, RIGHT, STOP Possible values (for now) are STRAIGHT, LEFT, RIGHT, LANEFOLLOW, VOID
""" """
threshold = math.radians(5.0) threshold = math.radians(4.0)
route = self.path_search(origin, destination) route = self.path_search(origin, destination)
plan = [] plan = []
@ -99,10 +98,8 @@ class GlobalRoutePlanner(object):
""" """
This function finds the shortest path connecting origin and destination This function finds the shortest path connecting origin and destination
using A* search with distance heuristic. using A* search with distance heuristic.
origin : tuple containing x, y co-ordinates of start position origin : tuple containing x, y co-ordinates of start position
desitnation : tuple containing x, y co-ordinates of end position desitnation : tuple containing x, y co-ordinates of end position
return : path as list of node ids (as int) of the graph self._graph return : path as list of node ids (as int) of the graph self._graph
connecting origin and destination connecting origin and destination
""" """
@ -123,7 +120,6 @@ class GlobalRoutePlanner(object):
""" """
This function finds the road segment closest to (x, y) This function finds the road segment closest to (x, y)
x, y : co-ordinates of the point to be localized x, y : co-ordinates of the point to be localized
return : pair of points, tuple of tuples containing co-ordinates return : pair of points, tuple of tuples containing co-ordinates
of points that represents the road segment closest to x, y of points that represents the road segment closest to x, y
""" """
@ -156,7 +152,6 @@ class GlobalRoutePlanner(object):
net_vector - unit vector of the chord from entry to exit net_vector - unit vector of the chord from entry to exit
intersection - boolean indicating if the edge belongs to an intersection - boolean indicating if the edge belongs to an
intersection intersection
return : graph -> networkx graph representing the world map, return : graph -> networkx graph representing the world map,
id_map-> mapping from (x,y) to node id id_map-> mapping from (x,y) to node id
""" """
@ -194,10 +189,8 @@ class GlobalRoutePlanner(object):
def distance(self, point1, point2): def distance(self, point1, point2):
""" """
returns the distance between point1 and point2 returns the distance between point1 and point2
point1 : (x,y) of first point point1 : (x,y) of first point
point2 : (x,y) of second point point2 : (x,y) of second point
return : distance from point1 to point2 return : distance from point1 to point2
""" """
x1, y1 = point1 x1, y1 = point1
@ -207,10 +200,8 @@ class GlobalRoutePlanner(object):
def unit_vector(self, point1, point2): def unit_vector(self, point1, point2):
""" """
This function returns the unit vector from point1 to point2 This function returns the unit vector from point1 to point2
point1 : (x,y) of first point point1 : (x,y) of first point
point2 : (x,y) of second point point2 : (x,y) of second point
return : tuple containing x and y components of unit vector return : tuple containing x and y components of unit vector
from point1 to point2 from point1 to point2
""" """
@ -226,10 +217,8 @@ class GlobalRoutePlanner(object):
def dot(self, vector1, vector2): def dot(self, vector1, vector2):
""" """
This function returns the dot product of vector1 with vector2 This function returns the dot product of vector1 with vector2
vector1 : x, y components of first vector vector1 : x, y components of first vector
vector2 : x, y components of second vector vector2 : x, y components of second vector
return : dot porduct scalar between vector1 and vector2 return : dot porduct scalar between vector1 and vector2
""" """
return vector1[0] * vector2[0] + vector1[1] * vector2[1] return vector1[0] * vector2[0] + vector1[1] * vector2[1]

View File

@ -14,7 +14,6 @@ import random
import carla import carla
from agents.navigation.controller import VehiclePIDController from agents.navigation.controller import VehiclePIDController
from agents.navigation.global_route_planner import NavEnum
from agents.tools.misc import distance_vehicle, draw_waypoints from agents.tools.misc import distance_vehicle, draw_waypoints
class RoadOption(Enum): class RoadOption(Enum):
@ -72,9 +71,11 @@ class LocalPlanner(object):
self._vehicle_controller = None self._vehicle_controller = None
self._global_plan = None self._global_plan = None
# queue with tuples of (waypoint, RoadOption) # queue with tuples of (waypoint, RoadOption)
self._waypoints_queue = deque(maxlen=200) self._waypoints_queue = deque(maxlen=600)
self._buffer_size = 5
self._waypoint_buffer = deque(maxlen=self._buffer_size)
# # initializing controller
self.init_controller(opt_dict) self.init_controller(opt_dict)
def __del__(self): def __del__(self):
@ -202,10 +203,19 @@ class LocalPlanner(object):
return control return control
# Buffering the waypoints
if not self._waypoint_buffer:
for i in range(self._buffer_size):
if self._waypoints_queue:
self._waypoint_buffer.append(
self._waypoints_queue.popleft())
else:
break
# current vehicle waypoint # current vehicle waypoint
self._current_waypoint = self._map.get_waypoint(self._vehicle.get_location()) self._current_waypoint = self._map.get_waypoint(self._vehicle.get_location())
# target waypoint # target waypoint
self._target_waypoint, self._target_road_option = self._waypoints_queue[0] self._target_waypoint, self._target_road_option = self._waypoint_buffer[0]
# move using PID controllers # move using PID controllers
control = self._vehicle_controller.run_step(self._target_speed, self._target_waypoint) control = self._vehicle_controller.run_step(self._target_speed, self._target_waypoint)
@ -213,13 +223,13 @@ class LocalPlanner(object):
vehicle_transform = self._vehicle.get_transform() vehicle_transform = self._vehicle.get_transform()
max_index = -1 max_index = -1
for i, (waypoint, _) in enumerate(self._waypoints_queue): for i, (waypoint, _) in enumerate(self._waypoint_buffer):
if distance_vehicle( if distance_vehicle(
waypoint, vehicle_transform) < self._min_distance: waypoint, vehicle_transform) < self._min_distance:
max_index = i max_index = i
if max_index >= 0: if max_index >= 0:
for i in range(max_index + 1): for i in range(max_index + 1):
self._waypoints_queue.popleft() self._waypoint_buffer.popleft()
if debug: if debug:
draw_waypoints(self._vehicle.get_world(), [self._target_waypoint], self._vehicle.get_location().z + 1.0) draw_waypoints(self._vehicle.get_world(), [self._target_waypoint], self._vehicle.get_location().z + 1.0)

View File

@ -88,3 +88,15 @@ def distance_vehicle(waypoint, vehicle_transform):
dy = waypoint.transform.location.y - loc.y dy = waypoint.transform.location.y - loc.y
return math.sqrt(dx * dx + dy * dy) return math.sqrt(dx * dx + dy * dy)
def vector(location_1, location_2):
"""
Returns the unit vector from location_1 to location_2
location_1, location_2 : carla.Location objects
"""
x = location_2.x - location_1.x
y = location_2.y - location_1.y
z = location_2.z - location_1.z
norm = np.linalg.norm([x, y, z])
return [x/norm, y/norm, z/norm]