python-motion-planning 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. python_motion_planning/__init__.py +4 -0
  2. python_motion_planning/curve_generation/__init__.py +9 -0
  3. python_motion_planning/curve_generation/bezier_curve.py +131 -0
  4. python_motion_planning/curve_generation/bspline_curve.py +271 -0
  5. python_motion_planning/curve_generation/cubic_spline.py +128 -0
  6. python_motion_planning/curve_generation/curve.py +64 -0
  7. python_motion_planning/curve_generation/dubins_curve.py +348 -0
  8. python_motion_planning/curve_generation/fem_pos_smooth.py +114 -0
  9. python_motion_planning/curve_generation/polynomial_curve.py +226 -0
  10. python_motion_planning/curve_generation/reeds_shepp.py +736 -0
  11. python_motion_planning/global_planner/__init__.py +3 -0
  12. python_motion_planning/global_planner/evolutionary_search/__init__.py +4 -0
  13. python_motion_planning/global_planner/evolutionary_search/aco.py +186 -0
  14. python_motion_planning/global_planner/evolutionary_search/evolutionary_search.py +87 -0
  15. python_motion_planning/global_planner/evolutionary_search/pso.py +356 -0
  16. python_motion_planning/global_planner/graph_search/__init__.py +28 -0
  17. python_motion_planning/global_planner/graph_search/a_star.py +124 -0
  18. python_motion_planning/global_planner/graph_search/d_star.py +291 -0
  19. python_motion_planning/global_planner/graph_search/d_star_lite.py +188 -0
  20. python_motion_planning/global_planner/graph_search/dijkstra.py +77 -0
  21. python_motion_planning/global_planner/graph_search/gbfs.py +78 -0
  22. python_motion_planning/global_planner/graph_search/graph_search.py +87 -0
  23. python_motion_planning/global_planner/graph_search/jps.py +165 -0
  24. python_motion_planning/global_planner/graph_search/lazy_theta_star.py +114 -0
  25. python_motion_planning/global_planner/graph_search/lpa_star.py +230 -0
  26. python_motion_planning/global_planner/graph_search/s_theta_star.py +133 -0
  27. python_motion_planning/global_planner/graph_search/theta_star.py +171 -0
  28. python_motion_planning/global_planner/graph_search/voronoi.py +200 -0
  29. python_motion_planning/global_planner/sample_search/__init__.py +6 -0
  30. python_motion_planning/global_planner/sample_search/informed_rrt.py +152 -0
  31. python_motion_planning/global_planner/sample_search/rrt.py +151 -0
  32. python_motion_planning/global_planner/sample_search/rrt_connect.py +147 -0
  33. python_motion_planning/global_planner/sample_search/rrt_star.py +77 -0
  34. python_motion_planning/global_planner/sample_search/sample_search.py +135 -0
  35. python_motion_planning/local_planner/__init__.py +19 -0
  36. python_motion_planning/local_planner/apf.py +144 -0
  37. python_motion_planning/local_planner/ddpg.py +630 -0
  38. python_motion_planning/local_planner/dqn.py +687 -0
  39. python_motion_planning/local_planner/dwa.py +212 -0
  40. python_motion_planning/local_planner/local_planner.py +262 -0
  41. python_motion_planning/local_planner/lqr.py +146 -0
  42. python_motion_planning/local_planner/mpc.py +214 -0
  43. python_motion_planning/local_planner/pid.py +158 -0
  44. python_motion_planning/local_planner/rpp.py +147 -0
  45. python_motion_planning/utils/__init__.py +19 -0
  46. python_motion_planning/utils/agent/__init__.py +0 -0
  47. python_motion_planning/utils/agent/agent.py +135 -0
  48. python_motion_planning/utils/environment/__init__.py +0 -0
  49. python_motion_planning/utils/environment/env.py +134 -0
  50. python_motion_planning/utils/environment/node.py +85 -0
  51. python_motion_planning/utils/environment/point2d.py +96 -0
  52. python_motion_planning/utils/environment/pose2d.py +91 -0
  53. python_motion_planning/utils/helper/__init__.py +3 -0
  54. python_motion_planning/utils/helper/math_helper.py +65 -0
  55. python_motion_planning/utils/planner/__init__.py +0 -0
  56. python_motion_planning/utils/planner/control_factory.py +31 -0
  57. python_motion_planning/utils/planner/curve_factory.py +29 -0
  58. python_motion_planning/utils/planner/planner.py +40 -0
  59. python_motion_planning/utils/planner/search_factory.py +51 -0
  60. python_motion_planning/utils/plot/__init__.py +0 -0
  61. python_motion_planning/utils/plot/plot.py +274 -0
  62. python_motion_planning-0.1.dist-info/LICENSE +674 -0
  63. python_motion_planning-0.1.dist-info/METADATA +873 -0
  64. python_motion_planning-0.1.dist-info/RECORD +66 -0
  65. python_motion_planning-0.1.dist-info/WHEEL +5 -0
  66. python_motion_planning-0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,4 @@
1
+ from .utils import *
2
+ from .global_planner import *
3
+ from .local_planner import *
4
+ from .curve_generation import *
@@ -0,0 +1,9 @@
1
+ from .polynomial_curve import Polynomial
2
+ from .bezier_curve import Bezier
3
+ from .bspline_curve import BSpline
4
+ from .dubins_curve import Dubins
5
+ from .reeds_shepp import ReedsShepp
6
+ from .cubic_spline import CubicSpline
7
+ from .fem_pos_smooth import FemPosSmoother
8
+
9
+ __all__ = ["Polynomial", "Dubins", "ReedsShepp", "Bezier", "CubicSpline", "BSpline", "FemPosSmoother"]
@@ -0,0 +1,131 @@
1
+ """
2
+ @file: bezier_curve.py
3
+ @breif: Bezier curve generation
4
+ @author: Winter
5
+ @update: 2023.7.25
6
+ """
7
+ import numpy as np
8
+
9
+ from scipy.special import comb
10
+ from python_motion_planning.utils import Plot
11
+ from .curve import Curve
12
+
13
+ class Bezier(Curve):
14
+ """
15
+ Class for Bezier curve generation.
16
+
17
+ Parameters:
18
+ step (float): Simulation or interpolation size
19
+ offset (float): The offset of control points
20
+
21
+ Examples:
22
+ >>> from python_motion_planning.curve_generation import Bezier
23
+ >>> points = [(0, 0, 0), (10, 10, -90), (20, 5, 60)]
24
+ >>> generator = Bezier(step, offset)
25
+ >>> generator.run(points)
26
+ """
27
+ def __init__(self, step: float, offset: float) -> None:
28
+ super().__init__(step)
29
+ self.offset = offset
30
+
31
+ def __str__(self) -> str:
32
+ return "Bezier Curve"
33
+
34
+ def generation(self, start_pose: tuple, goal_pose: tuple):
35
+ """
36
+ Generate the Bezier Curve.
37
+
38
+ Parameters:
39
+ start_pose (tuple): Initial pose (x, y, yaw)
40
+ goal_pose (tuple): Target pose (x, y, yaw)
41
+
42
+ Returns:
43
+ x_list (list): x of the trajectory
44
+ y_list (list): y of the trajectory
45
+ yaw_list (list): yaw of the trajectory
46
+ """
47
+ sx, sy, _ = start_pose
48
+ gx, gy, _ = goal_pose
49
+ n_points = int(np.hypot(sx - gx, sy - gy) / self.step)
50
+ control_points = self.getControlPoints(start_pose, goal_pose)
51
+
52
+ return [self.bezier(t, control_points) for t in np.linspace(0, 1, n_points)], \
53
+ control_points
54
+
55
+ def bezier(self, t: float, control_points: list) ->np.ndarray:
56
+ """
57
+ Calculate the Bezier curve point.
58
+
59
+ Parameters:
60
+ t (float): scale factor
61
+ control_points (list[tuple]): control points
62
+
63
+ Returns:
64
+ point (np.array): point in Bezier curve with t
65
+ """
66
+ n = len(control_points) - 1
67
+ control_points = np.array(control_points)
68
+ return np.sum([comb(n, i) * t ** i * (1 - t) ** (n - i) *
69
+ control_points[i] for i in range(n + 1)], axis=0)
70
+
71
+ def getControlPoints(self, start_pose: tuple, goal_pose: tuple):
72
+ """
73
+ Calculate control points heuristically.
74
+
75
+ Parameters:
76
+ start_pose (tuple): Initial pose (x, y, yaw)
77
+ goal_pose (tuple): Target pose (x, y, yaw)
78
+
79
+ Returns:
80
+ control_points (list[tuple]): Control points
81
+ """
82
+ sx, sy, syaw = start_pose
83
+ gx, gy, gyaw = goal_pose
84
+
85
+ dist = np.hypot(sx - gx, sy - gy) / self.offset
86
+ return [(sx, sy),
87
+ (sx + dist * np.cos(syaw), sy + dist * np.sin(syaw)),
88
+ (gx - dist * np.cos(gyaw), gy - dist * np.sin(gyaw)),
89
+ (gx, gy)]
90
+
91
+ def run(self, points: list):
92
+ """
93
+ Running both generation and animation.
94
+
95
+ Parameters:
96
+ points (list[tuple]): path points
97
+ """
98
+ assert len(points) >= 2, "Number of points should be at least 2."
99
+ import matplotlib.pyplot as plt
100
+
101
+ # generation
102
+ path_x, path_y = [], []
103
+ path_control_x, path_control_y = [], []
104
+ for i in range(len(points) - 1):
105
+ path, control_points = self.generation(
106
+ (points[i][0], points[i][1], np.deg2rad(points[i][2])),
107
+ (points[i + 1][0], points[i + 1][1], np.deg2rad(points[i + 1][2])))
108
+
109
+ for pt in path:
110
+ path_x.append(pt[0])
111
+ path_y.append(pt[1])
112
+
113
+ path_control_x.append(points[i][0])
114
+ path_control_y.append(points[i][1])
115
+
116
+ for pt in control_points:
117
+ path_control_x.append(pt[0])
118
+ path_control_y.append(pt[1])
119
+
120
+ # animation
121
+ plt.figure("curve generation")
122
+ plt.plot(path_x, path_y, linewidth=2, c="#1f77b4")
123
+ plt.plot(path_control_x, path_control_y, '--o', c='#dddddd', label="Control Points")
124
+ for x, y, theta in points:
125
+ Plot.plotArrow(x, y, np.deg2rad(theta), 2, 'blueviolet')
126
+
127
+ plt.axis("equal")
128
+ plt.legend()
129
+ plt.title(str(self))
130
+ plt.show()
131
+
@@ -0,0 +1,271 @@
1
+ """
2
+ @file: bspline_curve.py
3
+ @breif: B-Spline curve generation
4
+ @author: Winter
5
+ @update: 2023.7.29
6
+ """
7
+ import math
8
+ import numpy as np
9
+
10
+ from .curve import Curve
11
+
12
+ class BSpline(Curve):
13
+ """
14
+ Class for B-Spline curve generation.
15
+
16
+ Parameters:
17
+ step (float): Simulation or interpolation size
18
+ k (int): Degree of curve
19
+
20
+ Examples:
21
+ >>> from python_motion_planning.curve_generation import BSpline
22
+ >>> points = [(0, 0, 0), (10, 10, -90), (20, 5, 60)]
23
+ >>> generator = BSpline(step, k)
24
+ >>> generator.run(points)
25
+ """
26
+ def __init__(self, step: float, k: int, param_mode: str="centripetal",
27
+ spline_mode: str="interpolation") -> None:
28
+ super().__init__(step)
29
+ self.k = k
30
+
31
+ assert param_mode == "centripetal" or param_mode == "chord_length" \
32
+ or param_mode == "uniform_spaced", "Parameter selection mode error!"
33
+ self.param_mode = param_mode
34
+
35
+ assert spline_mode == "interpolation" or spline_mode == "approximation", \
36
+ "Spline mode selection error!"
37
+ self.spline_mode = spline_mode
38
+
39
+ def __str__(self) -> str:
40
+ return "B-Spline Curve"
41
+
42
+ def baseFunction(self, i: int, k: int, t: float, knot: list):
43
+ """
44
+ Calculate base function using Cox-deBoor function.
45
+
46
+ Parameters:
47
+ i (int): The index of base function
48
+ k (int): The degree of curve
49
+ t (float): parameter
50
+ knot (list[float]): knot vector
51
+
52
+ Returns:
53
+ Nik_t (float): The value of base function Nik(t)
54
+ """
55
+ Nik_t = 0
56
+ if k == 0:
57
+ Nik_t = 1.0 if t >= knot[i] and t < knot[i + 1] else 0.0
58
+ else:
59
+ length1 = knot[i + k] - knot[i]
60
+ length2 = knot[i + k + 1] - knot[i + 1]
61
+ if not length1 and not length2:
62
+ Nik_t = 0
63
+ elif not length1:
64
+ Nik_t = (knot[i + k + 1] - t) / length2 * self.baseFunction(i + 1, k - 1, t, knot)
65
+ elif not length2:
66
+ Nik_t = (t - knot[i]) / length1 * self.baseFunction(i, k - 1, t, knot)
67
+ else:
68
+ Nik_t = (t - knot[i]) / length1 * self.baseFunction(i, k - 1, t, knot) + \
69
+ (knot[i + k + 1] - t) / length2 * self.baseFunction(i + 1, k - 1, t, knot)
70
+ return Nik_t
71
+
72
+ def paramSelection(self, points: list):
73
+ """
74
+ Calculate parameters using the `uniform spaced` or `chrod length`
75
+ or `centripetal` method.
76
+
77
+ Parameters:
78
+ points (list[tuple]): path points
79
+
80
+ Returns:
81
+ Parameters (list[float]): The parameters of given points
82
+ """
83
+ n = len(points)
84
+ x_list = [pt[0] for pt in points]
85
+ y_list = [pt[1] for pt in points]
86
+ dx, dy = np.diff(x_list), np.diff(y_list)
87
+
88
+ if self.param_mode == "uniform_spaced":
89
+ return np.linspace(0, 1, n).tolist()
90
+
91
+ elif self.param_mode == "chord_length":
92
+ parameters = np.zeros(n)
93
+ s = np.cumsum([math.hypot(idx, idy) for (idx, idy) in zip(dx, dy)])
94
+ for i in range(1, n):
95
+ parameters[i] = s[i - 1] / s[-1]
96
+ return parameters.tolist()
97
+
98
+ elif self.param_mode == "centripetal":
99
+ alpha = 0.5
100
+ s = np.cumsum([math.pow(math.hypot(idx, idy), alpha) for (idx, idy) in zip(dx, dy)])
101
+ parameters = np.zeros(n)
102
+ for i in range(1, n):
103
+ parameters[i] = s[i - 1] / s[-1]
104
+ return parameters.tolist()
105
+
106
+ def knotGeneration(self, param: list, n: int):
107
+ """
108
+ Generate knot vector.
109
+
110
+ Parameters:
111
+ param (list[float]): The parameters of given points
112
+ n (int): The number of data points
113
+
114
+ Returns:
115
+ knot (list[float]): The knot vector
116
+ """
117
+ m = n + self.k + 1
118
+ knot = np.zeros(m)
119
+ for i in range(self.k + 1):
120
+ knot[i] = 0
121
+ for i in range(n, m):
122
+ knot[i] = 1
123
+ for i in range(self.k + 1, n):
124
+ for j in range(i - self.k, i):
125
+ knot[i] = knot[i] + param[j]
126
+ knot[i] = knot[i] / self.k
127
+ return knot.tolist()
128
+
129
+ def interpolation(self, points: list, param: list, knot: list):
130
+ """
131
+ Given a set of N data points, D0, D1, ..., Dn and a degree k,
132
+ find a B-spline curve of degree k defined by N control points
133
+ that passes all data points in the given order.
134
+
135
+ Parameters:
136
+ points (list[tuple]): path points
137
+ param (list[float]): The parameters of given points
138
+ knot (list[float]): The knot vector
139
+
140
+ Returns:
141
+ control_points (np.ndarray): The control points
142
+ """
143
+ n = len(points)
144
+ N = np.zeros((n, n))
145
+
146
+ for i in range(n):
147
+ for j in range(n):
148
+ N[i][j] = self.baseFunction(j, self.k, param[i], knot)
149
+ N[n-1][n-1] = 1
150
+ N_inv = np.linalg.inv(N)
151
+
152
+ D = np.array(points)
153
+
154
+ return N_inv @ D
155
+
156
+ def approximation(self, points: list, param: list, knot: list):
157
+ """
158
+ Given a set of N data points, D0, D1, ..., Dn, a degree k,
159
+ and a number H, where N > H > k >= 1, find a B-spline curve
160
+ of degree k defined by H control points that satisfies the
161
+ following conditions:
162
+ 1. this curve contains the first and last data points;
163
+ 2. this curve approximates the data polygon in the sense
164
+ of least square
165
+
166
+ Parameters:
167
+ points (list[tuple]): path points
168
+ param (list[float]): The parameters of given points
169
+ knot (list[float]): The knot vector
170
+
171
+ Returns:
172
+ control_points (np.ndarray): The control points
173
+ """
174
+ n = len(points)
175
+ D = np.array(points)
176
+
177
+ # heuristically setting the number of control points
178
+ h = n - 1
179
+
180
+ N = np.zeros((n, h))
181
+ for i in range(n):
182
+ for j in range(h):
183
+ N[i][j] = self.baseFunction(j, self.k, param[i], knot)
184
+ N_ = N[1 : n - 1, 1 : h - 1]
185
+
186
+ qk = np.zeros((n - 2, 2))
187
+ for i in range(1, n - 1):
188
+ qk[i - 1] = D[i, :] - N[i][0] * D[0, :] - N[i][h - 1] * D[-1, :]
189
+ Q = N_.T @ qk
190
+
191
+ P = np.linalg.inv(N_.T @ N_) @ Q
192
+ P = np.insert(P, 0, D[0, :], axis=0)
193
+ P = np.insert(P, len(P), D[-1, :], axis=0)
194
+
195
+ return P
196
+
197
+ def generation(self, t, k, knot, control_pts):
198
+ """
199
+ Generate the B-spline curve.
200
+
201
+ Parameters:
202
+ t (np.ndarray): The parameter values
203
+ k (int): The degree of the B-spline curve
204
+ knot (list[float]): The knot vector
205
+ control_pts (np.ndarray): The control points
206
+
207
+ Returns:
208
+ curve (np.ndarray): The B-spline curve
209
+ """
210
+ N = np.zeros((len(t), len(control_pts)))
211
+
212
+ for i in range(len(t)):
213
+ for j in range(len(control_pts)):
214
+ N[i][j] = self.baseFunction(j, k, t[i], knot)
215
+ N[len(t) - 1][len(control_pts) - 1] = 1
216
+
217
+ return N @ control_pts
218
+
219
+ def run(self, points: list, display: bool = True):
220
+ """
221
+ Running both generation and animation.
222
+
223
+ Parameters:
224
+ points (list[tuple]): path points
225
+ """
226
+ assert len(points) >= 2, "Number of points should be at least 2."
227
+ import matplotlib.pyplot as plt
228
+
229
+ if len(points[0]) > 2:
230
+ points = [(points[i][0], points[i][1]) for i in range(len(points))]
231
+
232
+ t = np.linspace(0, 1, int(1 / self.step))
233
+ params = self.paramSelection(points)
234
+ knot = self.knotGeneration(params, len(points))
235
+
236
+ if self.spline_mode == "interpolation":
237
+ control_pts = self.interpolation(points, params, knot)
238
+ elif self.spline_mode == "approximation":
239
+ control_pts = self.approximation(points, params, knot)
240
+ h = len(control_pts)
241
+ new_points = [(control_pts[i][0], control_pts[i][1])
242
+ for i in range(h)]
243
+ params = self.paramSelection(new_points)
244
+ knot = self.knotGeneration(params, h)
245
+ else:
246
+ raise NotImplementedError
247
+
248
+ control_x = control_pts[:, 0].tolist()
249
+ control_y = control_pts[:, 1].tolist()
250
+
251
+ path = self.generation(t, self.k, knot, control_pts)
252
+ path_x = path[:, 0].tolist()
253
+ path_y = path[:, 1].tolist()
254
+
255
+ if display:
256
+ # animation
257
+ plt.figure("curve generation")
258
+
259
+ # static
260
+ plt.figure("curve generation")
261
+ plt.plot(path_x, path_y, linewidth=2, c="#1f77b4")
262
+ plt.plot(control_x, control_y, '--o', c='#dddddd', label="Control Points")
263
+ for x, y in points:
264
+ plt.plot(x, y, "xr", linewidth=2)
265
+ plt.axis("equal")
266
+ plt.legend()
267
+ plt.title(str(self))
268
+
269
+ plt.show()
270
+
271
+ return [(ix, iy) for (ix, iy) in zip(path_x, path_y)]
@@ -0,0 +1,128 @@
1
+ """
2
+ @file: cubic_spline.py
3
+ @breif: Cubic spline generation
4
+ @author: Winter
5
+ @update: 2023.7.28
6
+ """
7
+ import math
8
+ import bisect
9
+ import numpy as np
10
+
11
+ from .curve import Curve
12
+
13
+ class CubicSpline(Curve):
14
+ """
15
+ Class for cubic spline generation.
16
+
17
+ Parameters:
18
+ step (float): Simulation or interpolation size
19
+
20
+ Examples:
21
+ >>> from python_motion_planning.curve_generation import CubicSpline
22
+ >>> points = [(0, 0, 0), (10, 10, -90), (20, 5, 60)]
23
+ >>> generator = CubicSpline(step)
24
+ >>> generator.run(points)
25
+ """
26
+ def __init__(self, step: float) -> None:
27
+ super().__init__(step)
28
+
29
+ def __str__(self) -> str:
30
+ return "Cubic Spline"
31
+
32
+ def spline(self, x_list: list, y_list: list, t: list):
33
+ """
34
+ Running both generation and animation.
35
+
36
+ Parameters:
37
+ x_list (list[tuple]): path points x-direction
38
+ y_list (list[tuple]): path points y-direction
39
+ t (list): parameter
40
+
41
+ Returns:
42
+ p (list): The (x, y) of curve with given t
43
+ dp (list): The derivative (dx, dy) of curve with given t
44
+ """
45
+ # cubic polynomial functions
46
+ a, b, c, d = y_list, [], [], []
47
+ h = np.diff(x_list)
48
+ num = len(x_list)
49
+
50
+ # calculate coefficient matrix
51
+ A = np.zeros((num, num))
52
+ for i in range(1, num - 1):
53
+ A[i, i - 1] = h[i - 1]
54
+ A[i, i] = 2.0 * (h[i - 1] + h[i])
55
+ A[i, i + 1] = h[i]
56
+ A[0, 0] = 1.0
57
+ A[num - 1, num - 1] = 1.0
58
+
59
+ B = np.zeros(num)
60
+ for i in range(1, num - 1):
61
+ B[i] = 3.0 * (a[i + 1] - a[i]) / h[i] - \
62
+ 3.0 * (a[i] - a[i - 1]) / h[i - 1]
63
+
64
+ c = np.linalg.solve(A, B)
65
+ for i in range(num - 1):
66
+ d.append((c[i + 1] - c[i]) / (3.0 * h[i]))
67
+ b.append((a[i + 1] - a[i]) / h[i] - h[i] * (c[i + 1] + 2.0 * c[i]) / 3.0)
68
+
69
+ # calculate spline value and its derivative
70
+ p, dp = [], []
71
+ for it in t:
72
+ if it < x_list[0] or it > x_list[-1]:
73
+ continue
74
+ i = bisect.bisect(x_list, it) - 1
75
+ dx = it - x_list[i]
76
+ p.append(a[i] + b[i] * dx + c[i] * dx**2 + d[i] * dx**3)
77
+ dp.append(b[i] + 2.0 * c[i] * dx + 3.0 * d[i] * dx**2)
78
+
79
+ return p, dp
80
+
81
+ def generation(self, start_pose: tuple, goal_pose: tuple):
82
+ pass
83
+
84
+ def run(self, points: list):
85
+ """
86
+ Running both generation and animation.
87
+
88
+ Parameters:
89
+ points (list[tuple]): path points
90
+ """
91
+ assert len(points) >= 2, "Number of points should be at least 2."
92
+ import matplotlib.pyplot as plt
93
+
94
+ if len(points[0]) == 2:
95
+ x_list = [ix for (ix, _) in points]
96
+ y_list = [iy for (_, iy) in points]
97
+ elif len(points[0]) == 3:
98
+ x_list = [ix for (ix, _, _) in points]
99
+ y_list = [iy for (_, iy, _) in points]
100
+ else:
101
+ raise NotImplementedError
102
+
103
+ dx, dy = np.diff(x_list), np.diff(y_list)
104
+ ds = [math.hypot(idx, idy) for (idx, idy) in zip(dx, dy)]
105
+ s = [0]
106
+ s.extend(np.cumsum(ds))
107
+ t = np.arange(0, s[-1], self.step)
108
+
109
+ path_x, d_path_x = self.spline(s, x_list, t)
110
+ path_y, d_path_y = self.spline(s, y_list, t)
111
+ path_yaw = [math.atan2(d_path_y[i], d_path_x[i]) for i in range(len(d_path_x))]
112
+
113
+ # animation
114
+ plt.figure("curve generation")
115
+
116
+ # static
117
+ plt.figure("curve generation")
118
+ plt.plot(path_x, path_y, linewidth=2, c="#1f77b4")
119
+ for x, y, _ in points:
120
+ plt.plot(x, y, "xr", linewidth=2)
121
+ plt.axis("equal")
122
+ plt.title(str(self))
123
+
124
+ plt.figure("yaw")
125
+ plt.plot(t, [math.degrees(iyaw) for iyaw in path_yaw], "-r")
126
+ plt.title("yaw curve")
127
+
128
+ plt.show()
@@ -0,0 +1,64 @@
1
+ """
2
+ @file: curve.py
3
+ @breif: Trajectory generation
4
+ @author: Winter
5
+ @update: 2023.5.31
6
+ """
7
+ import math
8
+ from abc import ABC, abstractmethod
9
+
10
+ class Curve(ABC):
11
+ def __init__(self, step: float) -> None:
12
+ """
13
+ Base class for curve generation.
14
+
15
+ Parameters:
16
+ step (float): Simulation or interpolation size
17
+ """
18
+ self.step = step
19
+
20
+ @abstractmethod
21
+ def run(self, points: list):
22
+ """
23
+ Running both generation and animation.
24
+ """
25
+ pass
26
+
27
+ @abstractmethod
28
+ def generation(self, start_pose: tuple, goal_pose: tuple):
29
+ """
30
+ Generate the curve.
31
+ """
32
+ pass
33
+
34
+ def trigonometric(self, alpha: float, beta: float):
35
+ """
36
+ Calculate some useful trigonometric value with angles.
37
+ """
38
+ return math.sin(alpha), math.sin(beta), math.cos(alpha), math.cos(beta), \
39
+ math.sin(alpha - beta), math.cos(alpha - beta)
40
+
41
+ def pi2pi(self, theta: float) -> float:
42
+ """
43
+ Truncate the angle to the interval of -π to π.
44
+ """
45
+ while theta > math.pi:
46
+ theta -= 2.0 * math.pi
47
+ while theta < -math.pi:
48
+ theta += 2.0 * math.pi
49
+ return theta
50
+
51
+ def mod2pi(self, theta: float) -> float:
52
+ """
53
+ Perform modulus operation on 2π.
54
+ """
55
+ return theta - 2.0 * math.pi * math.floor(theta / math.pi / 2.0)
56
+
57
+ def length(self, path: list) -> float:
58
+ """
59
+ Calculate path or trajectory length with `path` format [(ix, iy)] (i from 0 to N)
60
+ """
61
+ dist = 0
62
+ for i in range(len(path) - 1):
63
+ dist = dist + math.hypot(path[i + 1][0] - path[i][0], path[i + 1][1] - path[i][1])
64
+ return dist