Add attributes n_extension and circular. n_extensions specifies

number of waypoints to be added in the end in order to allow
for MPC control signals for last waypoints.
Add function _compute_length to get length of paths and be able to
get a waypoint based on the traveled distance s.
master
matssteinweg 2019-12-02 00:13:41 +01:00
parent 447bdf9f41
commit db90eb1055
1 changed files with 47 additions and 14 deletions

View File

@ -84,7 +84,7 @@ class Obstacle:
class ReferencePath: class ReferencePath:
def __init__(self, map, wp_x, wp_y, resolution, smoothing_distance, def __init__(self, map, wp_x, wp_y, resolution, smoothing_distance,
max_width): max_width, n_extension, circular):
""" """
Reference Path object. Create a reference trajectory from specified Reference Path object. Create a reference trajectory from specified
corner points with given resolution. Smoothing around corners can be corner points with given resolution. Smoothing around corners can be
@ -97,6 +97,9 @@ class ReferencePath:
:param smoothing_distance: number of waypoints used for smoothing the :param smoothing_distance: number of waypoints used for smoothing the
path by averaging neighborhood of waypoints path by averaging neighborhood of waypoints
:param max_width: maximum width of path to both sides in m :param max_width: maximum width of path to both sides in m
:param n_extension: number of samples used for path extension to allow
for MPC
:param circular: True if path circular
""" """
# Precision # Precision
@ -111,9 +114,18 @@ class ReferencePath:
# Look ahead distance for path averaging # Look ahead distance for path averaging
self.smoothing_distance = smoothing_distance self.smoothing_distance = smoothing_distance
# Number of waypoints used to extend path at the end
self.n_extension = n_extension
# Circular
self.circular = circular
# List of waypoint objects # List of waypoint objects
self.waypoints = self._construct_path(wp_x, wp_y) self.waypoints = self._construct_path(wp_x, wp_y)
# Length of path
self.length, self.segment_lengths = self._compute_length()
# Compute path width (attribute of each waypoint) # Compute path width (attribute of each waypoint)
self._compute_width(max_width=max_width) self._compute_width(max_width=max_width)
@ -142,6 +154,14 @@ class ReferencePath:
tolist() for i in range(len(wp_y) - 1)] tolist() for i in range(len(wp_y) - 1)]
wp_y = [wp for segment in wp_y for wp in segment] + [gp_y] wp_y = [wp for segment in wp_y for wp in segment] + [gp_y]
if self.n_extension is not None:
if self.circular:
wp_x += wp_x[:self.n_extension]
wp_y += wp_y[:self.n_extension]
else:
wp_x += wp_x[-self.n_extension:]
wp_y += wp_y[-self.n_extension:]
# Smooth path # Smooth path
wp_xs = [] wp_xs = []
wp_ys = [] wp_ys = []
@ -205,6 +225,17 @@ class ReferencePath:
return waypoints return waypoints
def _compute_length(self):
"""
Compute length of center-line path as sum of euclidean distance between
waypoints.
:return: length of center-line path in m
"""
segment_lengths = [0.0] + [self.waypoints[wp_id+1] - self.waypoints
[wp_id] for wp_id in range(len(self.waypoints)-self.n_extension-1)]
s = sum(segment_lengths)
return s, segment_lengths
def _compute_width(self, max_width): def _compute_width(self, max_width):
""" """
Compute the width of the path by checking the maximum free space to Compute the width of the path by checking the maximum free space to
@ -408,14 +439,14 @@ class ReferencePath:
vmax=1.0) vmax=1.0)
# Get x and y coordinates for all waypoints # Get x and y coordinates for all waypoints
wp_x = np.array([wp.x for wp in self.waypoints]) wp_x = np.array([wp.x for wp in self.waypoints][:-self.n_extension])
wp_y = np.array([wp.y for wp in self.waypoints]) wp_y = np.array([wp.y for wp in self.waypoints][:-self.n_extension])
# Get x and y locations of border cells for upper and lower bound # Get x and y locations of border cells for upper and lower bound
wp_ub_x = np.array([wp.border_cells[0][0] for wp in self.waypoints]) wp_ub_x = np.array([wp.border_cells[0][0] for wp in self.waypoints][:-self.n_extension])
wp_ub_y = np.array([wp.border_cells[0][1] for wp in self.waypoints]) wp_ub_y = np.array([wp.border_cells[0][1] for wp in self.waypoints][:-self.n_extension])
wp_lb_x = np.array([wp.border_cells[1][0] for wp in self.waypoints]) wp_lb_x = np.array([wp.border_cells[1][0] for wp in self.waypoints][:-self.n_extension])
wp_lb_y = np.array([wp.border_cells[1][1] for wp in self.waypoints]) wp_lb_y = np.array([wp.border_cells[1][1] for wp in self.waypoints][:-self.n_extension])
# Plot waypoints # Plot waypoints
plt.scatter(wp_x, wp_y, color=WAYPOINTS, s=3) plt.scatter(wp_x, wp_y, color=WAYPOINTS, s=3)
@ -431,16 +462,16 @@ class ReferencePath:
# Plot border of path # Plot border of path
bl_x = np.array([wp.border_cells[0][0] for wp in bl_x = np.array([wp.border_cells[0][0] for wp in
self.waypoints] + self.waypoints][:-self.n_extension] +
[self.waypoints[0].border_cells[0][0]]) [self.waypoints[0].border_cells[0][0]])
bl_y = np.array([wp.border_cells[0][1] for wp in bl_y = np.array([wp.border_cells[0][1] for wp in
self.waypoints] + self.waypoints][:-self.n_extension] +
[self.waypoints[0].border_cells[0][1]]) [self.waypoints[0].border_cells[0][1]])
br_x = np.array([wp.border_cells[1][0] for wp in br_x = np.array([wp.border_cells[1][0] for wp in
self.waypoints] + self.waypoints][:-self.n_extension] +
[self.waypoints[0].border_cells[1][0]]) [self.waypoints[0].border_cells[1][0]])
br_y = np.array([wp.border_cells[1][1] for wp in br_y = np.array([wp.border_cells[1][1] for wp in
self.waypoints] + self.waypoints][:-self.n_extension] +
[self.waypoints[0].border_cells[1][1]]) [self.waypoints[0].border_cells[1][1]])
# Smooth border # Smooth border
# bl_x = savgol_filter(bl_x, 15, 9) # bl_x = savgol_filter(bl_x, 15, 9)
@ -449,7 +480,7 @@ class ReferencePath:
# br_y = savgol_filter(br_y, 15, 9) # br_y = savgol_filter(br_y, 15, 9)
# If circular path, connect start and end point # If circular path, connect start and end point
if np.abs(self.waypoints[-1] - self.waypoints[0]) <= 2*self.resolution: if self.circular:
plt.plot(bl_x, bl_y, color=OBSTACLE) plt.plot(bl_x, bl_y, color=OBSTACLE)
plt.plot(br_x, br_y, color=OBSTACLE) plt.plot(br_x, br_y, color=OBSTACLE)
# If not circular, close path at start and end # If not circular, close path at start and end
@ -480,7 +511,8 @@ if __name__ == '__main__':
# Specify path resolution # Specify path resolution
path_resolution = 0.05 # m / wp path_resolution = 0.05 # m / wp
reference_path = ReferencePath(map, wp_x, wp_y, path_resolution, reference_path = ReferencePath(map, wp_x, wp_y, path_resolution,
smoothing_distance=5, max_width=0.22) smoothing_distance=5, max_width=0.22, n_extension=30,
circular=True)
# Add obstacles # Add obstacles
obs1 = Obstacle(cx=0.0, cy=0.0, radius=0.05) obs1 = Obstacle(cx=0.0, cy=0.0, radius=0.05)
obs2 = Obstacle(cx=-0.8, cy=-0.5, radius=0.05) obs2 = Obstacle(cx=-0.8, cy=-0.5, radius=0.05)
@ -500,7 +532,8 @@ if __name__ == '__main__':
# Specify path resolution # Specify path resolution
path_resolution = 0.20 # m / wp path_resolution = 0.20 # m / wp
reference_path = ReferencePath(map, wp_x, wp_y, path_resolution, reference_path = ReferencePath(map, wp_x, wp_y, path_resolution,
smoothing_distance=5, max_width=1.5) smoothing_distance=5, max_width=1.5,
n_extension=30, circular=False)
obs1 = Obstacle(cx=-6.3, cy=-11.1, radius=0.20) obs1 = Obstacle(cx=-6.3, cy=-11.1, radius=0.20)
obs2 = Obstacle(cx=-2.2, cy=-6.8, radius=0.25) obs2 = Obstacle(cx=-2.2, cy=-6.8, radius=0.25)
obs3 = Obstacle(cx=1.7, cy=-1.0, radius=0.15) obs3 = Obstacle(cx=1.7, cy=-1.0, radius=0.15)