|
5 | 5 | author: Atsushi Sakai (@Atsushi_twi) |
6 | 6 |
|
7 | 7 | """ |
| 8 | +import sys |
| 9 | +import pathlib |
| 10 | +sys.path.append(str(pathlib.Path(__file__).parent.parent.parent)) |
8 | 11 |
|
9 | 12 | import numpy as np |
10 | 13 | import matplotlib.pyplot as plt |
11 | | -import scipy.interpolate as scipy_interpolate |
| 14 | +import scipy.interpolate as interpolate |
12 | 15 |
|
| 16 | +from utils.plot import plot_curvature |
13 | 17 |
|
14 | | -def approximate_b_spline_path(x: list, y: list, n_path_points: int, |
15 | | - degree: int = 3) -> tuple: |
16 | | - """ |
17 | | - approximate points with a B-Spline path |
18 | 18 |
|
19 | | - :param x: x position list of approximated points |
20 | | - :param y: y position list of approximated points |
21 | | - :param n_path_points: number of path points |
22 | | - :param degree: (Optional) B Spline curve degree |
23 | | - :return: x and y position list of the result path |
| 19 | +def approximate_b_spline_path(x: list, |
| 20 | + y: list, |
| 21 | + n_path_points: int, |
| 22 | + degree: int = 3, |
| 23 | + s=None, |
| 24 | + ) -> tuple: |
24 | 25 | """ |
25 | | - t = range(len(x)) |
26 | | - x_tup = scipy_interpolate.splrep(t, x, k=degree) |
27 | | - y_tup = scipy_interpolate.splrep(t, y, k=degree) |
| 26 | + Approximate points with a B-Spline path |
| 27 | +
|
| 28 | + Parameters |
| 29 | + ---------- |
| 30 | + x : array_like |
| 31 | + x position list of approximated points |
| 32 | + y : array_like |
| 33 | + y position list of approximated points |
| 34 | + n_path_points : int |
| 35 | + number of path points |
| 36 | + degree : int, optional |
| 37 | + B Spline curve degree. Must be 2<= k <= 5. Default: 3. |
| 38 | + s : int, optional |
| 39 | + smoothing parameter. If this value is bigger, the path will be |
| 40 | + smoother, but it will be less accurate. If this value is smaller, |
| 41 | + the path will be more accurate, but it will be less smooth. |
| 42 | + When `s` is 0, it is equivalent to the interpolation. Default is None, |
| 43 | + in this case `s` will be `len(x)`. |
| 44 | +
|
| 45 | + Returns |
| 46 | + ------- |
| 47 | + x : array |
| 48 | + x positions of the result path |
| 49 | + y : array |
| 50 | + y positions of the result path |
| 51 | + heading : array |
| 52 | + heading of the result path |
| 53 | + curvature : array |
| 54 | + curvature of the result path |
28 | 55 |
|
29 | | - x_list = list(x_tup) |
30 | | - x_list[1] = x + [0.0, 0.0, 0.0, 0.0] |
31 | | - |
32 | | - y_list = list(y_tup) |
33 | | - y_list[1] = y + [0.0, 0.0, 0.0, 0.0] |
| 56 | + """ |
| 57 | + distances = _calc_distance_vector(x, y) |
34 | 58 |
|
35 | | - ipl_t = np.linspace(0.0, len(x) - 1, n_path_points) |
36 | | - rx = scipy_interpolate.splev(ipl_t, x_list) |
37 | | - ry = scipy_interpolate.splev(ipl_t, y_list) |
| 59 | + spl_i_x = interpolate.UnivariateSpline(distances, x, k=degree, s=s) |
| 60 | + spl_i_y = interpolate.UnivariateSpline(distances, y, k=degree, s=s) |
38 | 61 |
|
39 | | - return rx, ry |
| 62 | + sampled = np.linspace(0.0, distances[-1], n_path_points) |
| 63 | + return _evaluate_spline(sampled, spl_i_x, spl_i_y) |
40 | 64 |
|
41 | 65 |
|
42 | | -def interpolate_b_spline_path(x: list, y: list, n_path_points: int, |
| 66 | +def interpolate_b_spline_path(x, y, |
| 67 | + n_path_points: int, |
43 | 68 | degree: int = 3) -> tuple: |
44 | 69 | """ |
45 | | - interpolate points with a B-Spline path |
| 70 | + Interpolate x-y points with a B-Spline path |
| 71 | +
|
| 72 | + Parameters |
| 73 | + ---------- |
| 74 | + x : array_like |
| 75 | + x positions of interpolated points |
| 76 | + y : array_like |
| 77 | + y positions of interpolated points |
| 78 | + n_path_points : int |
| 79 | + number of path points |
| 80 | + degree : int, optional |
| 81 | + B-Spline degree. Must be 2<= k <= 5. Default: 3 |
| 82 | +
|
| 83 | + Returns |
| 84 | + ------- |
| 85 | + x : array |
| 86 | + x positions of the result path |
| 87 | + y : array |
| 88 | + y positions of the result path |
| 89 | + heading : array |
| 90 | + heading of the result path |
| 91 | + curvature : array |
| 92 | + curvature of the result path |
46 | 93 |
|
47 | | - :param x: x positions of interpolated points |
48 | | - :param y: y positions of interpolated points |
49 | | - :param n_path_points: number of path points |
50 | | - :param degree: B-Spline degree |
51 | | - :return: x and y position list of the result path |
52 | 94 | """ |
53 | | - ipl_t = np.linspace(0.0, len(x) - 1, len(x)) |
54 | | - spl_i_x = scipy_interpolate.make_interp_spline(ipl_t, x, k=degree) |
55 | | - spl_i_y = scipy_interpolate.make_interp_spline(ipl_t, y, k=degree) |
| 95 | + return approximate_b_spline_path(x, y, n_path_points, degree, s=0.0) |
56 | 96 |
|
57 | | - travel = np.linspace(0.0, len(x) - 1, n_path_points) |
58 | | - return spl_i_x(travel), spl_i_y(travel) |
| 97 | + |
| 98 | +def _calc_distance_vector(x, y): |
| 99 | + dx, dy = np.diff(x), np.diff(y) |
| 100 | + distances = np.cumsum([np.hypot(idx, idy) for idx, idy in zip(dx, dy)]) |
| 101 | + distances = np.concatenate(([0.0], distances)) |
| 102 | + distances /= distances[-1] |
| 103 | + return distances |
| 104 | + |
| 105 | + |
| 106 | +def _evaluate_spline(sampled, spl_i_x, spl_i_y): |
| 107 | + x = spl_i_x(sampled) |
| 108 | + y = spl_i_y(sampled) |
| 109 | + dx = spl_i_x.derivative(1)(sampled) |
| 110 | + dy = spl_i_y.derivative(1)(sampled) |
| 111 | + heading = np.arctan2(dy, dx) |
| 112 | + ddx = spl_i_x.derivative(2)(sampled) |
| 113 | + ddy = spl_i_y.derivative(2)(sampled) |
| 114 | + curvature = (ddy * dx - ddx * dy) / np.power(dx * dx + dy * dy, 2.0 / 3.0) |
| 115 | + return np.array(x), y, heading, curvature, |
59 | 116 |
|
60 | 117 |
|
61 | 118 | def main(): |
62 | 119 | print(__file__ + " start!!") |
63 | 120 | # way points |
64 | 121 | way_point_x = [-1.0, 3.0, 4.0, 2.0, 1.0] |
65 | 122 | way_point_y = [0.0, -3.0, 1.0, 1.0, 3.0] |
66 | | - n_course_point = 100 # sampling number |
| 123 | + n_course_point = 50 # sampling number |
67 | 124 |
|
68 | | - rax, ray = approximate_b_spline_path(way_point_x, way_point_y, |
69 | | - n_course_point) |
70 | | - rix, riy = interpolate_b_spline_path(way_point_x, way_point_y, |
71 | | - n_course_point) |
| 125 | + plt.subplots() |
| 126 | + rax, ray, heading, curvature = approximate_b_spline_path( |
| 127 | + way_point_x, way_point_y, n_course_point, s=0.5) |
| 128 | + plt.plot(rax, ray, '-r', label="Approximated B-Spline path") |
| 129 | + plot_curvature(rax, ray, heading, curvature) |
72 | 130 |
|
73 | | - # show results |
| 131 | + plt.title("B-Spline approximation") |
74 | 132 | plt.plot(way_point_x, way_point_y, '-og', label="way points") |
75 | | - plt.plot(rax, ray, '-r', label="Approximated B-Spline path") |
| 133 | + plt.grid(True) |
| 134 | + plt.legend() |
| 135 | + plt.axis("equal") |
| 136 | + |
| 137 | + plt.subplots() |
| 138 | + rix, riy, heading, curvature = interpolate_b_spline_path( |
| 139 | + way_point_x, way_point_y, n_course_point) |
76 | 140 | plt.plot(rix, riy, '-b', label="Interpolated B-Spline path") |
| 141 | + plot_curvature(rix, riy, heading, curvature) |
| 142 | + |
| 143 | + plt.title("B-Spline interpolation") |
| 144 | + plt.plot(way_point_x, way_point_y, '-og', label="way points") |
77 | 145 | plt.grid(True) |
78 | 146 | plt.legend() |
79 | 147 | plt.axis("equal") |
|
0 commit comments