Skip to content

Commit b97420d

Browse files
committed
flesh out PurePursuit class
1 parent 67ab7f6 commit b97420d

File tree

1 file changed

+77
-7
lines changed

1 file changed

+77
-7
lines changed

roboticstoolbox/mobile/drivers.py

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -301,21 +301,91 @@ def _new_goal(self):
301301

302302

303303
class PurePursuit(VehicleDriverBase):
304-
def __init__(self, speed=1, radius=1):
305-
pass
304+
def __init__(self, path, lookahead=1, linemarkerstyle=None, **kwargs):
305+
"""
306+
Driving agent for pure pursuit
307+
308+
:param path: path as a set of waypoints
309+
:type path: array_like(2,n) one column per point, optional
310+
:param lookahead: lookahead distance, defaults to 1
311+
:type lookahead: float, optional
312+
"""
313+
super().__init__(**kwargs)
314+
self._path = path
315+
self._lookahead = lookahead
316+
self._linemarkerstyle = linemarkerstyle
306317

307318
def __str__(self):
308-
pass
319+
"""Convert to string
309320
310-
def init(self):
311-
pass
321+
:return: driver parameters and state in in a compact human readable format
322+
:rtype: str
323+
"""
324+
325+
s = "PurePursuit driver object\n"
326+
s += (
327+
f" X {self._workspace[0]} : {self._workspace[1]}; Y {self._workspace[0]} :"
328+
f" {self._workspace[1]}, lookahead={self._lookahead}\n"
329+
)
330+
return s
331+
332+
def init(self, ax=None):
333+
if ax is not None:
334+
h = plt.plot(
335+
self._path[0, :],
336+
self._path[1, :],
337+
**self._linemarkerstyle,
338+
label="waypoints",
339+
)[0]
340+
self._current_waypint = None
312341

313342
def demand(self):
314-
pass
343+
344+
cp = self._veh._x[0:2] # current point
345+
346+
# find closest point on the path to current point
347+
d = np.linalg.norm(self._path.T - cp, axis=1) # rely on implicit expansion
348+
i = np.argmin(d)
349+
350+
# find all points on the path at least lookahead distance away
351+
(k,) = np.where(d[i + 1 :] >= self._lookahead) # find all points beyond horizon
352+
if len(k) == 0:
353+
# no such points, we must be near the end, goal is the end
354+
goal = self._path[:, -1]
355+
k = -1
356+
else:
357+
# many such points, take the first one
358+
k = k[0] + 1 # first point beyond look ahead distance
359+
goal = self._path[:, k + i]
360+
k += i
361+
362+
if self._waypoint_marker is not None:
363+
pass
364+
for marker in self._waypoint_marker:
365+
marker.set_color("blue")
366+
self._waypoint_marker[k].set_color("red")
367+
368+
return self.driveto(goal)
315369

316370

317371
# ========================================================================= #
318372

319373
if __name__ == "__main__":
320374

321-
import unittest
375+
# import unittest
376+
377+
import roboticstoolbox as rtb
378+
379+
# veh = rtb.Bicycle(control=rtb.RandomPath(workspace=10), animation="car")
380+
# print(veh.control)
381+
# veh.run(20, animate=True)
382+
383+
# create the path
384+
path = np.array([[10.0, 10], [10, 60], [80, 80], [50, 10]]).T
385+
veh = rtb.Bicycle(
386+
control=rtb.PurePursuit(path, speed=4, lookahead=5, workspace=[0, 100]),
387+
animation="car",
388+
)
389+
print(veh)
390+
print(veh.control)
391+
veh.run(60, animate=True)

0 commit comments

Comments
 (0)