python-motion-planning 2.0__py3-none-any.whl → 2.0.dev2__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.
- python_motion_planning/__init__.py +1 -1
- python_motion_planning/common/utils/geometry.py +29 -18
- python_motion_planning/curve_generator/__init__.py +9 -0
- python_motion_planning/curve_generator/bezier_curve.py +131 -0
- python_motion_planning/curve_generator/bspline_curve.py +271 -0
- python_motion_planning/curve_generator/cubic_spline.py +128 -0
- python_motion_planning/curve_generator/curve.py +64 -0
- python_motion_planning/curve_generator/dubins_curve.py +348 -0
- python_motion_planning/curve_generator/fem_pos_smooth.py +114 -0
- python_motion_planning/curve_generator/polynomial_curve.py +226 -0
- python_motion_planning/curve_generator/reeds_shepp.py +736 -0
- python_motion_planning/path_planner/sample_search/rrt.py +5 -5
- python_motion_planning/path_planner/sample_search/rrt_connect.py +2 -2
- python_motion_planning/path_planner/sample_search/rrt_star.py +11 -31
- {python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/METADATA +15 -15
- {python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/RECORD +19 -21
- {python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/WHEEL +1 -1
- python_motion_planning/traj_optimizer/__init__.py +0 -2
- python_motion_planning/traj_optimizer/base_curve_generator.py +0 -53
- python_motion_planning/traj_optimizer/curve_generator/__init__.py +0 -2
- python_motion_planning/traj_optimizer/curve_generator/point_based/__init__.py +0 -2
- python_motion_planning/traj_optimizer/curve_generator/point_based/bspline.py +0 -256
- python_motion_planning/traj_optimizer/curve_generator/point_based/cubic_spline.py +0 -115
- python_motion_planning/traj_optimizer/curve_generator/pose_based/__init__.py +0 -4
- python_motion_planning/traj_optimizer/curve_generator/pose_based/bezier.py +0 -121
- python_motion_planning/traj_optimizer/curve_generator/pose_based/dubins.py +0 -355
- python_motion_planning/traj_optimizer/curve_generator/pose_based/polynomial.py +0 -197
- python_motion_planning/traj_optimizer/curve_generator/pose_based/reeds_shepp.py +0 -606
- {python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/licenses/LICENSE +0 -0
- {python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/top_level.txt +0 -0
|
@@ -1,606 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
@file: reeds_shepp.py
|
|
3
|
-
@author: Yang Haodong, Wu Maojia
|
|
4
|
-
@update: 2026.4.12
|
|
5
|
-
"""
|
|
6
|
-
from typing import List, Tuple, Dict, Any
|
|
7
|
-
import math
|
|
8
|
-
|
|
9
|
-
from python_motion_planning.traj_optimizer.base_curve_generator import BaseCurveGenerator
|
|
10
|
-
from python_motion_planning.common.utils.geometry import Geometry
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ReedsShepp(BaseCurveGenerator):
|
|
14
|
-
"""
|
|
15
|
-
Class for Reeds-Shepp curve generator.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
*args: see the parent class.
|
|
19
|
-
max_curv: The maximum curvature of the curve.
|
|
20
|
-
*args: see the parent class.
|
|
21
|
-
|
|
22
|
-
References:
|
|
23
|
-
[1] Optimal paths for a car that goes both forwards and backwards
|
|
24
|
-
|
|
25
|
-
Examples:
|
|
26
|
-
>>> import math
|
|
27
|
-
>>> generator = ReedsShepp(step=0.1, max_curv=1.0)
|
|
28
|
-
>>> points = [(0.0, 0.0, 0.0), (10.0, 10.0, -math.pi/2), (20.0, 5.0, math.pi/3)]
|
|
29
|
-
>>> path, curve_info = generator.generate(points)
|
|
30
|
-
>>> print(curve_info['success'])
|
|
31
|
-
True
|
|
32
|
-
"""
|
|
33
|
-
def __init__(self, *args,
|
|
34
|
-
max_curv: float = 1.0,
|
|
35
|
-
**kwargs) -> None:
|
|
36
|
-
super().__init__(*args, **kwargs)
|
|
37
|
-
self.max_curv = max_curv
|
|
38
|
-
|
|
39
|
-
def __str__(self) -> str:
|
|
40
|
-
return "Reeds Shepp Curve"
|
|
41
|
-
|
|
42
|
-
class _Path:
|
|
43
|
-
"""
|
|
44
|
-
Container for a single Reeds-Shepp path candidate.
|
|
45
|
-
"""
|
|
46
|
-
def __init__(self, lengths: List[float] = None, ctypes: List[str] = None):
|
|
47
|
-
self.lengths = lengths if lengths is not None else []
|
|
48
|
-
self.ctypes = ctypes if ctypes is not None else []
|
|
49
|
-
self.path_length = sum(abs(i) for i in self.lengths)
|
|
50
|
-
|
|
51
|
-
def generate(self, points: List[Tuple[float, float, float]]) -> Tuple[List[Tuple[float, float, float]], Dict[str, Any]]:
|
|
52
|
-
"""
|
|
53
|
-
Generate a concatenated Reeds-Shepp curve through a list of poses.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
points: A list of poses (x, y, yaw) in world frame.
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
path: A list of (x, y, yaw) waypoints of the generated curve in world frame.
|
|
60
|
-
curve_info: A dictionary containing the curve information (success, length).
|
|
61
|
-
"""
|
|
62
|
-
if len(points) < 2:
|
|
63
|
-
return [], {"success": False, "length": 0.0}
|
|
64
|
-
|
|
65
|
-
path: List[Tuple[float, float, float]] = []
|
|
66
|
-
total_length = 0.0
|
|
67
|
-
for i in range(len(points) - 1):
|
|
68
|
-
best_cost, _, x_list, y_list, yaw_list = self._generate_segment(
|
|
69
|
-
points[i], points[i + 1])
|
|
70
|
-
if best_cost is None:
|
|
71
|
-
return [], {"success": False, "length": 0.0}
|
|
72
|
-
total_length += best_cost
|
|
73
|
-
|
|
74
|
-
start = 1 if i > 0 else 0
|
|
75
|
-
for x, y, yaw in zip(x_list[start:], y_list[start:], yaw_list[start:]):
|
|
76
|
-
path.append((float(x), float(y), float(yaw)))
|
|
77
|
-
|
|
78
|
-
total_length = float(total_length)
|
|
79
|
-
|
|
80
|
-
return path, {"success": True, "length": total_length}
|
|
81
|
-
|
|
82
|
-
def _r(self, x: float, y: float) -> Tuple[float, float]:
|
|
83
|
-
"""
|
|
84
|
-
Convert (x, y) to polar coordinates (r, theta).
|
|
85
|
-
|
|
86
|
-
Args:
|
|
87
|
-
x: x-coordinate value.
|
|
88
|
-
y: y-coordinate value.
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
r, theta: Polar coordinates.
|
|
92
|
-
"""
|
|
93
|
-
return math.hypot(x, y), math.atan2(y, x)
|
|
94
|
-
|
|
95
|
-
def _sls(self, x: float, y: float, phi: float):
|
|
96
|
-
"""
|
|
97
|
-
Straight-Left-Straight generation mode.
|
|
98
|
-
"""
|
|
99
|
-
phi = Geometry.regularize_orient(phi)
|
|
100
|
-
|
|
101
|
-
if y > 0.0 and 0.0 < phi < math.pi * 0.99:
|
|
102
|
-
xd = -y / math.tan(phi) + x
|
|
103
|
-
t = xd - math.tan(phi / 2.0)
|
|
104
|
-
u = phi
|
|
105
|
-
v = math.sqrt((x - xd) ** 2 + y ** 2) - math.tan(phi / 2.0)
|
|
106
|
-
return True, t, u, v
|
|
107
|
-
if y < 0.0 and 0.0 < phi < math.pi * 0.99:
|
|
108
|
-
xd = -y / math.tan(phi) + x
|
|
109
|
-
t = xd - math.tan(phi / 2.0)
|
|
110
|
-
u = phi
|
|
111
|
-
v = -math.sqrt((x - xd) ** 2 + y ** 2) - math.tan(phi / 2.0)
|
|
112
|
-
return True, t, u, v
|
|
113
|
-
return False, 0.0, 0.0, 0.0
|
|
114
|
-
|
|
115
|
-
def _lrl(self, x: float, y: float, phi: float):
|
|
116
|
-
"""
|
|
117
|
-
Left-Right-Left generation mode (L+R-L-).
|
|
118
|
-
"""
|
|
119
|
-
r, theta = self._r(x - math.sin(phi), y - 1.0 + math.cos(phi))
|
|
120
|
-
|
|
121
|
-
if r <= 4.0:
|
|
122
|
-
u = -2.0 * math.asin(0.25 * r)
|
|
123
|
-
t = Geometry.regularize_orient(theta + 0.5 * u + math.pi)
|
|
124
|
-
v = Geometry.regularize_orient(phi - t + u)
|
|
125
|
-
if t >= 0.0 and u <= 0.0:
|
|
126
|
-
return True, t, u, v
|
|
127
|
-
return False, 0.0, 0.0, 0.0
|
|
128
|
-
|
|
129
|
-
def _lsl(self, x: float, y: float, phi: float):
|
|
130
|
-
"""
|
|
131
|
-
Left-Straight-Left generation mode (L+S+L+).
|
|
132
|
-
"""
|
|
133
|
-
u, t = self._r(x - math.sin(phi), y - 1.0 + math.cos(phi))
|
|
134
|
-
if t >= 0.0:
|
|
135
|
-
v = Geometry.regularize_orient(phi - t)
|
|
136
|
-
if v >= 0.0:
|
|
137
|
-
return True, t, u, v
|
|
138
|
-
return False, 0.0, 0.0, 0.0
|
|
139
|
-
|
|
140
|
-
def _lsr(self, x: float, y: float, phi: float):
|
|
141
|
-
"""
|
|
142
|
-
Left-Straight-Right generation mode (L+S+R+).
|
|
143
|
-
"""
|
|
144
|
-
r, theta = self._r(x + math.sin(phi), y - 1.0 - math.cos(phi))
|
|
145
|
-
r = r ** 2
|
|
146
|
-
if r >= 4.0:
|
|
147
|
-
u = math.sqrt(r - 4.0)
|
|
148
|
-
t = Geometry.regularize_orient(theta + math.atan2(2.0, u))
|
|
149
|
-
v = Geometry.regularize_orient(t - phi)
|
|
150
|
-
if t >= 0.0 and v >= 0.0:
|
|
151
|
-
return True, t, u, v
|
|
152
|
-
return False, 0.0, 0.0, 0.0
|
|
153
|
-
|
|
154
|
-
def _lrlrn(self, x: float, y: float, phi: float):
|
|
155
|
-
"""
|
|
156
|
-
Left-Right(beta)-Left(beta)-Right generation mode (L+R+L-R-).
|
|
157
|
-
"""
|
|
158
|
-
xi = x + math.sin(phi)
|
|
159
|
-
eta = y - 1.0 - math.cos(phi)
|
|
160
|
-
rho = 0.25 * (2.0 + math.sqrt(xi * xi + eta * eta))
|
|
161
|
-
|
|
162
|
-
if rho <= 1.0:
|
|
163
|
-
u = math.acos(rho)
|
|
164
|
-
t, v = self._cal_tau_omega(u, -u, xi, eta, phi)
|
|
165
|
-
if t >= 0.0 and v <= 0.0:
|
|
166
|
-
return True, t, u, v
|
|
167
|
-
return False, 0.0, 0.0, 0.0
|
|
168
|
-
|
|
169
|
-
def _lrlrp(self, x: float, y: float, phi: float):
|
|
170
|
-
"""
|
|
171
|
-
Left-Right(beta)-Left(beta)-Right generation mode (L+R-L-R+).
|
|
172
|
-
"""
|
|
173
|
-
xi = x + math.sin(phi)
|
|
174
|
-
eta = y - 1.0 - math.cos(phi)
|
|
175
|
-
rho = (20.0 - xi * xi - eta * eta) / 16.0
|
|
176
|
-
|
|
177
|
-
if 0.0 <= rho <= 1.0:
|
|
178
|
-
u = -math.acos(rho)
|
|
179
|
-
if u >= -0.5 * math.pi:
|
|
180
|
-
t, v = self._cal_tau_omega(u, u, xi, eta, phi)
|
|
181
|
-
if t >= 0.0 and v >= 0.0:
|
|
182
|
-
return True, t, u, v
|
|
183
|
-
return False, 0.0, 0.0, 0.0
|
|
184
|
-
|
|
185
|
-
def _lrsr(self, x: float, y: float, phi: float):
|
|
186
|
-
"""
|
|
187
|
-
Left-Right(pi/2)-Straight-Right generation mode (L+R-S-R-).
|
|
188
|
-
"""
|
|
189
|
-
xi = x + math.sin(phi)
|
|
190
|
-
eta = y - 1.0 - math.cos(phi)
|
|
191
|
-
rho, theta = self._r(-eta, xi)
|
|
192
|
-
|
|
193
|
-
if rho >= 2.0:
|
|
194
|
-
t = theta
|
|
195
|
-
u = 2.0 - rho
|
|
196
|
-
v = Geometry.regularize_orient(t + 0.5 * math.pi - phi)
|
|
197
|
-
if t >= 0.0 and u <= 0.0 and v <= 0.0:
|
|
198
|
-
return True, t, u, v
|
|
199
|
-
return False, 0.0, 0.0, 0.0
|
|
200
|
-
|
|
201
|
-
def _lrsl(self, x: float, y: float, phi: float):
|
|
202
|
-
"""
|
|
203
|
-
Left-Right(pi/2)-Straight-Left generation mode (L+R-S-L-).
|
|
204
|
-
"""
|
|
205
|
-
xi = x - math.sin(phi)
|
|
206
|
-
eta = y - 1.0 + math.cos(phi)
|
|
207
|
-
rho, theta = self._r(xi, eta)
|
|
208
|
-
|
|
209
|
-
if rho >= 2.0:
|
|
210
|
-
r = math.sqrt(rho * rho - 4.0)
|
|
211
|
-
u = 2.0 - r
|
|
212
|
-
t = Geometry.regularize_orient(theta + math.atan2(r, -2.0))
|
|
213
|
-
v = Geometry.regularize_orient(phi - 0.5 * math.pi - t)
|
|
214
|
-
if t >= 0.0 and u <= 0.0 and v <= 0.0:
|
|
215
|
-
return True, t, u, v
|
|
216
|
-
return False, 0.0, 0.0, 0.0
|
|
217
|
-
|
|
218
|
-
def _lrslr(self, x: float, y: float, phi: float):
|
|
219
|
-
"""
|
|
220
|
-
Left-Right(pi/2)-Straight-Left(pi/2)-Right generation mode (L+R-S-L-R+).
|
|
221
|
-
"""
|
|
222
|
-
xi = x + math.sin(phi)
|
|
223
|
-
eta = y - 1.0 - math.cos(phi)
|
|
224
|
-
r, _ = self._r(xi, eta)
|
|
225
|
-
|
|
226
|
-
if r >= 2.0:
|
|
227
|
-
u = 4.0 - math.sqrt(r * r - 4.0)
|
|
228
|
-
if u <= 0.0:
|
|
229
|
-
t = Geometry.regularize_orient(math.atan2((4.0 - u) * xi - 2.0 * eta, -2.0 * xi + (u - 4.0) * eta))
|
|
230
|
-
v = Geometry.regularize_orient(t - phi)
|
|
231
|
-
if t >= 0.0 and v >= 0.0:
|
|
232
|
-
return True, t, u, v
|
|
233
|
-
return False, 0.0, 0.0, 0.0
|
|
234
|
-
|
|
235
|
-
def _scs(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
236
|
-
"""
|
|
237
|
-
Straight-Circle-Straight generation mode family (using reflect).
|
|
238
|
-
"""
|
|
239
|
-
paths = []
|
|
240
|
-
|
|
241
|
-
flag, t, u, v = self._sls(x, y, phi)
|
|
242
|
-
if flag:
|
|
243
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["S", "L", "S"]))
|
|
244
|
-
|
|
245
|
-
flag, t, u, v = self._sls(x, -y, -phi)
|
|
246
|
-
if flag:
|
|
247
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["S", "R", "S"]))
|
|
248
|
-
|
|
249
|
-
return paths
|
|
250
|
-
|
|
251
|
-
def _ccc(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
252
|
-
"""
|
|
253
|
-
Circle-Circle-Circle generation mode family (using reflect, timeflip and backwards).
|
|
254
|
-
"""
|
|
255
|
-
paths = []
|
|
256
|
-
|
|
257
|
-
flag, t, u, v = self._lrl(x, y, phi)
|
|
258
|
-
if flag:
|
|
259
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["L", "R", "L"]))
|
|
260
|
-
|
|
261
|
-
flag, t, u, v = self._lrl(-x, y, -phi)
|
|
262
|
-
if flag:
|
|
263
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["L", "R", "L"]))
|
|
264
|
-
|
|
265
|
-
flag, t, u, v = self._lrl(x, -y, -phi)
|
|
266
|
-
if flag:
|
|
267
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["R", "L", "R"]))
|
|
268
|
-
|
|
269
|
-
flag, t, u, v = self._lrl(-x, -y, phi)
|
|
270
|
-
if flag:
|
|
271
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["R", "L", "R"]))
|
|
272
|
-
|
|
273
|
-
xb = x * math.cos(phi) + y * math.sin(phi)
|
|
274
|
-
yb = x * math.sin(phi) - y * math.cos(phi)
|
|
275
|
-
|
|
276
|
-
flag, t, u, v = self._lrl(xb, yb, phi)
|
|
277
|
-
if flag:
|
|
278
|
-
paths.append(self._Path(lengths=[v, u, t], ctypes=["L", "R", "L"]))
|
|
279
|
-
|
|
280
|
-
flag, t, u, v = self._lrl(-xb, yb, -phi)
|
|
281
|
-
if flag:
|
|
282
|
-
paths.append(self._Path(lengths=[-v, -u, -t], ctypes=["L", "R", "L"]))
|
|
283
|
-
|
|
284
|
-
flag, t, u, v = self._lrl(xb, -yb, -phi)
|
|
285
|
-
if flag:
|
|
286
|
-
paths.append(self._Path(lengths=[v, u, t], ctypes=["R", "L", "R"]))
|
|
287
|
-
|
|
288
|
-
flag, t, u, v = self._lrl(-xb, -yb, phi)
|
|
289
|
-
if flag:
|
|
290
|
-
paths.append(self._Path(lengths=[-v, -u, -t], ctypes=["R", "L", "R"]))
|
|
291
|
-
|
|
292
|
-
return paths
|
|
293
|
-
|
|
294
|
-
def _csc(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
295
|
-
"""
|
|
296
|
-
Circle-Straight-Circle generation mode family (using reflect, timeflip and backwards).
|
|
297
|
-
"""
|
|
298
|
-
paths = []
|
|
299
|
-
|
|
300
|
-
flag, t, u, v = self._lsl(x, y, phi)
|
|
301
|
-
if flag:
|
|
302
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["L", "S", "L"]))
|
|
303
|
-
|
|
304
|
-
flag, t, u, v = self._lsl(-x, y, -phi)
|
|
305
|
-
if flag:
|
|
306
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["L", "S", "L"]))
|
|
307
|
-
|
|
308
|
-
flag, t, u, v = self._lsl(x, -y, -phi)
|
|
309
|
-
if flag:
|
|
310
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["R", "S", "R"]))
|
|
311
|
-
|
|
312
|
-
flag, t, u, v = self._lsl(-x, -y, phi)
|
|
313
|
-
if flag:
|
|
314
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["R", "S", "R"]))
|
|
315
|
-
|
|
316
|
-
flag, t, u, v = self._lsr(x, y, phi)
|
|
317
|
-
if flag:
|
|
318
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["L", "S", "R"]))
|
|
319
|
-
|
|
320
|
-
flag, t, u, v = self._lsr(-x, y, -phi)
|
|
321
|
-
if flag:
|
|
322
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["L", "S", "R"]))
|
|
323
|
-
|
|
324
|
-
flag, t, u, v = self._lsr(x, -y, -phi)
|
|
325
|
-
if flag:
|
|
326
|
-
paths.append(self._Path(lengths=[t, u, v], ctypes=["R", "S", "L"]))
|
|
327
|
-
|
|
328
|
-
flag, t, u, v = self._lsr(-x, -y, phi)
|
|
329
|
-
if flag:
|
|
330
|
-
paths.append(self._Path(lengths=[-t, -u, -v], ctypes=["R", "S", "L"]))
|
|
331
|
-
|
|
332
|
-
return paths
|
|
333
|
-
|
|
334
|
-
def _cccc(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
335
|
-
"""
|
|
336
|
-
Circle-Circle(beta)-Circle(beta)-Circle generation mode family
|
|
337
|
-
(using reflect, timeflip and backwards).
|
|
338
|
-
"""
|
|
339
|
-
paths = []
|
|
340
|
-
|
|
341
|
-
flag, t, u, v = self._lrlrn(x, y, phi)
|
|
342
|
-
if flag:
|
|
343
|
-
paths.append(self._Path(lengths=[t, u, -u, v], ctypes=["L", "R", "L", "R"]))
|
|
344
|
-
|
|
345
|
-
flag, t, u, v = self._lrlrn(-x, y, -phi)
|
|
346
|
-
if flag:
|
|
347
|
-
paths.append(self._Path(lengths=[-t, -u, u, -v], ctypes=["L", "R", "L", "R"]))
|
|
348
|
-
|
|
349
|
-
flag, t, u, v = self._lrlrn(x, -y, -phi)
|
|
350
|
-
if flag:
|
|
351
|
-
paths.append(self._Path(lengths=[t, u, -u, v], ctypes=["R", "L", "R", "L"]))
|
|
352
|
-
|
|
353
|
-
flag, t, u, v = self._lrlrn(-x, -y, phi)
|
|
354
|
-
if flag:
|
|
355
|
-
paths.append(self._Path(lengths=[-t, -u, u, -v], ctypes=["R", "L", "R", "L"]))
|
|
356
|
-
|
|
357
|
-
flag, t, u, v = self._lrlrp(x, y, phi)
|
|
358
|
-
if flag:
|
|
359
|
-
paths.append(self._Path(lengths=[t, u, u, v], ctypes=["L", "R", "L", "R"]))
|
|
360
|
-
|
|
361
|
-
flag, t, u, v = self._lrlrp(-x, y, -phi)
|
|
362
|
-
if flag:
|
|
363
|
-
paths.append(self._Path(lengths=[-t, -u, -u, -v], ctypes=["L", "R", "L", "R"]))
|
|
364
|
-
|
|
365
|
-
flag, t, u, v = self._lrlrp(x, -y, -phi)
|
|
366
|
-
if flag:
|
|
367
|
-
paths.append(self._Path(lengths=[t, u, u, v], ctypes=["R", "L", "R", "L"]))
|
|
368
|
-
|
|
369
|
-
flag, t, u, v = self._lrlrp(-x, -y, phi)
|
|
370
|
-
if flag:
|
|
371
|
-
paths.append(self._Path(lengths=[-t, -u, -u, -v], ctypes=["R", "L", "R", "L"]))
|
|
372
|
-
|
|
373
|
-
return paths
|
|
374
|
-
|
|
375
|
-
def _ccsc(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
376
|
-
"""
|
|
377
|
-
Circle-Circle(pi/2)-Straight-Circle and Circle-Straight-Circle(pi/2)-Circle
|
|
378
|
-
generation mode family (using reflect, timeflip and backwards).
|
|
379
|
-
"""
|
|
380
|
-
paths = []
|
|
381
|
-
|
|
382
|
-
flag, t, u, v = self._lrsl(x, y, phi)
|
|
383
|
-
if flag:
|
|
384
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, v], ctypes=["L", "R", "S", "L"]))
|
|
385
|
-
|
|
386
|
-
flag, t, u, v = self._lrsl(-x, y, -phi)
|
|
387
|
-
if flag:
|
|
388
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, -v], ctypes=["L", "R", "S", "L"]))
|
|
389
|
-
|
|
390
|
-
flag, t, u, v = self._lrsl(x, -y, -phi)
|
|
391
|
-
if flag:
|
|
392
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, v], ctypes=["R", "L", "S", "R"]))
|
|
393
|
-
|
|
394
|
-
flag, t, u, v = self._lrsl(-x, -y, phi)
|
|
395
|
-
if flag:
|
|
396
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, -v], ctypes=["R", "L", "S", "R"]))
|
|
397
|
-
|
|
398
|
-
flag, t, u, v = self._lrsr(x, y, phi)
|
|
399
|
-
if flag:
|
|
400
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, v], ctypes=["L", "R", "S", "R"]))
|
|
401
|
-
|
|
402
|
-
flag, t, u, v = self._lrsr(-x, y, -phi)
|
|
403
|
-
if flag:
|
|
404
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, -v], ctypes=["L", "R", "S", "R"]))
|
|
405
|
-
|
|
406
|
-
flag, t, u, v = self._lrsr(x, -y, -phi)
|
|
407
|
-
if flag:
|
|
408
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, v], ctypes=["R", "L", "S", "L"]))
|
|
409
|
-
|
|
410
|
-
flag, t, u, v = self._lrsr(-x, -y, phi)
|
|
411
|
-
if flag:
|
|
412
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, -v], ctypes=["R", "L", "S", "L"]))
|
|
413
|
-
|
|
414
|
-
xb = x * math.cos(phi) + y * math.sin(phi)
|
|
415
|
-
yb = x * math.sin(phi) - y * math.cos(phi)
|
|
416
|
-
|
|
417
|
-
flag, t, u, v = self._lrsl(xb, yb, phi)
|
|
418
|
-
if flag:
|
|
419
|
-
paths.append(self._Path(lengths=[v, u, -0.5 * math.pi, t], ctypes=["L", "S", "R", "L"]))
|
|
420
|
-
|
|
421
|
-
flag, t, u, v = self._lrsl(-xb, yb, -phi)
|
|
422
|
-
if flag:
|
|
423
|
-
paths.append(self._Path(lengths=[-v, -u, 0.5 * math.pi, -t], ctypes=["L", "S", "R", "L"]))
|
|
424
|
-
|
|
425
|
-
flag, t, u, v = self._lrsl(xb, -yb, -phi)
|
|
426
|
-
if flag:
|
|
427
|
-
paths.append(self._Path(lengths=[v, u, -0.5 * math.pi, t], ctypes=["R", "S", "L", "R"]))
|
|
428
|
-
|
|
429
|
-
flag, t, u, v = self._lrsl(-xb, -yb, phi)
|
|
430
|
-
if flag:
|
|
431
|
-
paths.append(self._Path(lengths=[-v, -u, 0.5 * math.pi, -t], ctypes=["R", "S", "L", "R"]))
|
|
432
|
-
|
|
433
|
-
flag, t, u, v = self._lrsr(xb, yb, phi)
|
|
434
|
-
if flag:
|
|
435
|
-
paths.append(self._Path(lengths=[v, u, -0.5 * math.pi, t], ctypes=["R", "S", "R", "L"]))
|
|
436
|
-
|
|
437
|
-
flag, t, u, v = self._lrsr(-xb, yb, -phi)
|
|
438
|
-
if flag:
|
|
439
|
-
paths.append(self._Path(lengths=[-v, -u, 0.5 * math.pi, -t], ctypes=["R", "S", "R", "L"]))
|
|
440
|
-
|
|
441
|
-
flag, t, u, v = self._lrsr(xb, -yb, -phi)
|
|
442
|
-
if flag:
|
|
443
|
-
paths.append(self._Path(lengths=[v, u, -0.5 * math.pi, t], ctypes=["L", "S", "L", "R"]))
|
|
444
|
-
|
|
445
|
-
flag, t, u, v = self._lrsr(-xb, -yb, phi)
|
|
446
|
-
if flag:
|
|
447
|
-
paths.append(self._Path(lengths=[-v, -u, 0.5 * math.pi, -t], ctypes=["L", "S", "L", "R"]))
|
|
448
|
-
|
|
449
|
-
return paths
|
|
450
|
-
|
|
451
|
-
def _ccscc(self, x: float, y: float, phi: float) -> List["_Path"]:
|
|
452
|
-
"""
|
|
453
|
-
Circle-Circle(pi/2)-Straight-Circle(pi/2)-Circle generation mode family
|
|
454
|
-
(using reflect, timeflip and backwards).
|
|
455
|
-
"""
|
|
456
|
-
paths = []
|
|
457
|
-
|
|
458
|
-
flag, t, u, v = self._lrslr(x, y, phi)
|
|
459
|
-
if flag:
|
|
460
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, -0.5 * math.pi, v],
|
|
461
|
-
ctypes=["L", "R", "S", "L", "R"]))
|
|
462
|
-
|
|
463
|
-
flag, t, u, v = self._lrslr(-x, y, -phi)
|
|
464
|
-
if flag:
|
|
465
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, 0.5 * math.pi, -v],
|
|
466
|
-
ctypes=["L", "R", "S", "L", "R"]))
|
|
467
|
-
|
|
468
|
-
flag, t, u, v = self._lrslr(x, -y, -phi)
|
|
469
|
-
if flag:
|
|
470
|
-
paths.append(self._Path(lengths=[t, -0.5 * math.pi, u, -0.5 * math.pi, v],
|
|
471
|
-
ctypes=["R", "L", "S", "R", "L"]))
|
|
472
|
-
|
|
473
|
-
flag, t, u, v = self._lrslr(-x, -y, phi)
|
|
474
|
-
if flag:
|
|
475
|
-
paths.append(self._Path(lengths=[-t, 0.5 * math.pi, -u, 0.5 * math.pi, -v],
|
|
476
|
-
ctypes=["R", "L", "S", "R", "L"]))
|
|
477
|
-
|
|
478
|
-
return paths
|
|
479
|
-
|
|
480
|
-
def _interpolate(self, mode: str, length: float,
|
|
481
|
-
init_pose: Tuple[float, float, float]) -> Tuple[float, float, float]:
|
|
482
|
-
"""
|
|
483
|
-
Planning path interpolation.
|
|
484
|
-
|
|
485
|
-
Args:
|
|
486
|
-
mode: Motion type, one of {"L", "S", "R"}.
|
|
487
|
-
length: Single step motion path length.
|
|
488
|
-
init_pose: Initial pose (x, y, yaw).
|
|
489
|
-
|
|
490
|
-
Returns:
|
|
491
|
-
new_pose: New pose (new_x, new_y, new_yaw) after moving.
|
|
492
|
-
"""
|
|
493
|
-
x, y, yaw = init_pose
|
|
494
|
-
|
|
495
|
-
if mode == "S":
|
|
496
|
-
new_x = x + length / self.max_curv * math.cos(yaw)
|
|
497
|
-
new_y = y + length / self.max_curv * math.sin(yaw)
|
|
498
|
-
new_yaw = yaw
|
|
499
|
-
elif mode == "L":
|
|
500
|
-
new_x = x + (math.sin(yaw + length) - math.sin(yaw)) / self.max_curv
|
|
501
|
-
new_y = y - (math.cos(yaw + length) - math.cos(yaw)) / self.max_curv
|
|
502
|
-
new_yaw = yaw + length
|
|
503
|
-
elif mode == "R":
|
|
504
|
-
new_x = x - (math.sin(yaw - length) - math.sin(yaw)) / self.max_curv
|
|
505
|
-
new_y = y + (math.cos(yaw - length) - math.cos(yaw)) / self.max_curv
|
|
506
|
-
new_yaw = yaw - length
|
|
507
|
-
else:
|
|
508
|
-
raise NotImplementedError
|
|
509
|
-
|
|
510
|
-
return new_x, new_y, new_yaw
|
|
511
|
-
|
|
512
|
-
def _generate_segment(self, start_pose: Tuple[float, float, float],
|
|
513
|
-
goal_pose: Tuple[float, float, float]):
|
|
514
|
-
"""
|
|
515
|
-
Generate a single Reeds-Shepp curve segment between two poses.
|
|
516
|
-
|
|
517
|
-
Args:
|
|
518
|
-
start_pose: Initial pose (x, y, yaw).
|
|
519
|
-
goal_pose: Target pose (x, y, yaw).
|
|
520
|
-
|
|
521
|
-
Returns:
|
|
522
|
-
best_cost: Best planning path length in world units.
|
|
523
|
-
best_mode: Best motion modes.
|
|
524
|
-
x_list: Trajectory of x.
|
|
525
|
-
y_list: Trajectory of y.
|
|
526
|
-
yaw_list: Trajectory of yaw.
|
|
527
|
-
"""
|
|
528
|
-
sx, sy, syaw = start_pose
|
|
529
|
-
gx, gy, gyaw = goal_pose
|
|
530
|
-
|
|
531
|
-
dx, dy, dyaw = gx - sx, gy - sy, gyaw - syaw
|
|
532
|
-
x = (math.cos(syaw) * dx + math.sin(syaw) * dy) * self.max_curv
|
|
533
|
-
y = (-math.sin(syaw) * dx + math.cos(syaw) * dy) * self.max_curv
|
|
534
|
-
|
|
535
|
-
planners = [self._scs, self._ccc, self._csc, self._cccc, self._ccsc, self._ccscc]
|
|
536
|
-
best_path, best_cost = None, float("inf")
|
|
537
|
-
|
|
538
|
-
for planner in planners:
|
|
539
|
-
paths = planner(x, y, dyaw)
|
|
540
|
-
for path in paths:
|
|
541
|
-
if path.path_length < best_cost:
|
|
542
|
-
best_path, best_cost = path, path.path_length
|
|
543
|
-
|
|
544
|
-
if best_path is None:
|
|
545
|
-
return None, None, [], [], []
|
|
546
|
-
|
|
547
|
-
points_num = int(best_cost / self.step) + len(best_path.lengths) + 3
|
|
548
|
-
x_list = [0.0 for _ in range(points_num)]
|
|
549
|
-
y_list = [0.0 for _ in range(points_num)]
|
|
550
|
-
yaw_list = [0.0 for _ in range(points_num)]
|
|
551
|
-
|
|
552
|
-
i = 0
|
|
553
|
-
for mode_, seg_length in zip(best_path.ctypes, best_path.lengths):
|
|
554
|
-
d_length = self.step if seg_length > 0.0 else -self.step
|
|
555
|
-
current_x, current_y, current_yaw = x_list[i], y_list[i], yaw_list[i]
|
|
556
|
-
length = d_length
|
|
557
|
-
while abs(length) <= abs(seg_length):
|
|
558
|
-
i += 1
|
|
559
|
-
current_x, current_y, current_yaw = self._interpolate(
|
|
560
|
-
mode_, d_length, (current_x, current_y, current_yaw)
|
|
561
|
-
)
|
|
562
|
-
x_list[i], y_list[i], yaw_list[i] = current_x, current_y, current_yaw
|
|
563
|
-
length += d_length
|
|
564
|
-
|
|
565
|
-
i += 1
|
|
566
|
-
remainder = seg_length - (length - d_length)
|
|
567
|
-
x_list[i], y_list[i], yaw_list[i] = self._interpolate(
|
|
568
|
-
mode_, remainder, (x_list[i-1], y_list[i-1], yaw_list[i-1])
|
|
569
|
-
)
|
|
570
|
-
|
|
571
|
-
if len(x_list) <= 1:
|
|
572
|
-
return None, None, [], [], []
|
|
573
|
-
|
|
574
|
-
while len(x_list) >= 1 and x_list[-1] == 0.0:
|
|
575
|
-
x_list.pop()
|
|
576
|
-
y_list.pop()
|
|
577
|
-
yaw_list.pop()
|
|
578
|
-
|
|
579
|
-
x_list_ = [math.cos(-syaw) * ix + math.sin(-syaw) * iy + sx for (ix, iy) in zip(x_list, y_list)]
|
|
580
|
-
y_list_ = [-math.sin(-syaw) * ix + math.cos(-syaw) * iy + sy for (ix, iy) in zip(x_list, y_list)]
|
|
581
|
-
yaw_list_ = [Geometry.regularize_orient(iyaw + syaw) for iyaw in yaw_list]
|
|
582
|
-
|
|
583
|
-
return best_cost / self.max_curv, best_path.ctypes, x_list_, y_list_, yaw_list_
|
|
584
|
-
|
|
585
|
-
def _cal_tau_omega(self, u: float, v: float, xi: float, eta: float, phi: float) -> Tuple[float, float]:
|
|
586
|
-
"""
|
|
587
|
-
Helper to compute (tau, omega) for LRLR-family patterns.
|
|
588
|
-
|
|
589
|
-
Args:
|
|
590
|
-
u, v: Intermediate angular values from the base pattern.
|
|
591
|
-
xi, eta: Coordinates derived from the normalized goal pose.
|
|
592
|
-
phi: Normalized goal heading.
|
|
593
|
-
|
|
594
|
-
Returns:
|
|
595
|
-
tau, omega: Angular values used to complete the pattern.
|
|
596
|
-
"""
|
|
597
|
-
delta = Geometry.regularize_orient(u - v)
|
|
598
|
-
A = math.sin(u) - math.sin(delta)
|
|
599
|
-
B = math.cos(u) - math.cos(delta) - 1.0
|
|
600
|
-
|
|
601
|
-
t1 = math.atan2(eta * A - xi * B, xi * A + eta * B)
|
|
602
|
-
t2 = 2.0 * (math.cos(delta) - math.cos(v) - math.cos(u)) + 3.0
|
|
603
|
-
|
|
604
|
-
tau = Geometry.regularize_orient(t1 + math.pi) if t2 < 0 else Geometry.regularize_orient(t1)
|
|
605
|
-
omega = Geometry.regularize_orient(tau - u + v - phi)
|
|
606
|
-
return tau, omega
|
{python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{python_motion_planning-2.0.dist-info → python_motion_planning-2.0.dev2.dist-info}/top_level.txt
RENAMED
|
File without changes
|