forked from gustavokcouto/carla_gym
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroute_manipulation.py
158 lines (124 loc) · 5.2 KB
/
route_manipulation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python
# Copyright (c) 2018-2019 Intel Labs.
# authors: German Ros ([email protected]), Felipe Codevilla ([email protected])
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
"""
Module to manipulate the routes, by making then more or less dense (Up to a certain parameter).
It also contains functions to convert the CARLA world location do GPS coordinates.
"""
import math
import xml.etree.ElementTree as ET
from agents.navigation.global_route_planner import GlobalRoutePlanner
from agents.navigation.global_route_planner_dao import GlobalRoutePlannerDAO
from agents.navigation.local_planner import RoadOption
def _location_to_gps(lat_ref, lon_ref, location):
"""
Convert from world coordinates to GPS coordinates
:param lat_ref: latitude reference for the current map
:param lon_ref: longitude reference for the current map
:param location: location to translate
:return: dictionary with lat, lon and height
"""
EARTH_RADIUS_EQUA = 6378137.0 # pylint: disable=invalid-name
scale = math.cos(lat_ref * math.pi / 180.0)
mx = scale * lon_ref * math.pi * EARTH_RADIUS_EQUA / 180.0
my = scale * EARTH_RADIUS_EQUA * math.log(math.tan((90.0 + lat_ref) * math.pi / 360.0))
mx += location.x
my -= location.y
lon = mx * 180.0 / (math.pi * EARTH_RADIUS_EQUA * scale)
lat = 360.0 * math.atan(math.exp(my / (EARTH_RADIUS_EQUA * scale))) / math.pi - 90.0
z = location.z
return {'lat': lat, 'lon': lon, 'z': z}
def location_route_to_gps(route, lat_ref, lon_ref):
"""
Locate each waypoint of the route into gps, (lat long ) representations.
:param route:
:param lat_ref:
:param lon_ref:
:return:
"""
gps_route = []
for transform, connection in route:
gps_point = _location_to_gps(lat_ref, lon_ref, transform.location)
gps_route.append((gps_point, connection))
return gps_route
def _get_latlon_ref(world):
"""
Convert from waypoints world coordinates to CARLA GPS coordinates
:return: tuple with lat and lon coordinates
"""
xodr = world.get_map().to_opendrive()
tree = ET.ElementTree(ET.fromstring(xodr))
# default reference
lat_ref = 42.0
lon_ref = 2.0
for opendrive in tree.iter("OpenDRIVE"):
for header in opendrive.iter("header"):
for georef in header.iter("geoReference"):
if georef.text:
str_list = georef.text.split(' ')
for item in str_list:
if '+lat_0' in item:
lat_ref = float(item.split('=')[1])
if '+lon_0' in item:
lon_ref = float(item.split('=')[1])
return lat_ref, lon_ref
def downsample_route(route, sample_factor):
"""
Downsample the route by some factor.
:param route: the trajectory , has to contain the waypoints and the road options
:param sample_factor: Maximum distance between samples
:return: returns the ids of the final route that can
"""
ids_to_sample = []
prev_option = None
dist = 0
for i, point in enumerate(route):
curr_option = point[1]
# Lane changing
if curr_option in (RoadOption.CHANGELANELEFT, RoadOption.CHANGELANERIGHT):
ids_to_sample.append(i)
dist = 0
# When road option changes
elif prev_option != curr_option and prev_option not in (RoadOption.CHANGELANELEFT, RoadOption.CHANGELANERIGHT):
ids_to_sample.append(i)
dist = 0
# After a certain max distance
elif dist > sample_factor:
ids_to_sample.append(i)
dist = 0
# At the end
elif i == len(route) - 1:
ids_to_sample.append(i)
dist = 0
# Compute the distance traveled
else:
curr_location = point[0].location
prev_location = route[i-1][0].location
dist += curr_location.distance(prev_location)
prev_option = curr_option
return ids_to_sample
def interpolate_trajectory(world, waypoints_trajectory, hop_resolution=1.0):
"""
Given some raw keypoints interpolate a full dense trajectory to be used by the user.
returns the full interpolated route both in GPS coordinates and also in its original form.
Args:
- world: an reference to the CARLA world so we can use the planner
- waypoints_trajectory: the current coarse trajectory
- hop_resolution: is the resolution, how dense is the provided trajectory going to be made
"""
dao = GlobalRoutePlannerDAO(world.get_map(), hop_resolution)
grp = GlobalRoutePlanner(dao)
grp.setup()
# Obtain route plan
route = []
for i in range(len(waypoints_trajectory) - 1): # Goes until the one before the last.
waypoint = waypoints_trajectory[i]
waypoint_next = waypoints_trajectory[i + 1]
interpolated_trace = grp.trace_route(waypoint, waypoint_next)
for wp_tuple in interpolated_trace:
route.append((wp_tuple[0].transform, wp_tuple[1]))
lat_ref, lon_ref = _get_latlon_ref(world)
return location_route_to_gps(route, lat_ref, lon_ref), route