add throttler to planner

This commit is contained in:
Michael Fogleman 2018-03-12 22:05:28 -04:00
parent 6ff92b3a4f
commit b0dc60fec0
1 changed files with 77 additions and 3 deletions

View File

@ -90,6 +90,9 @@ class Point(_Point):
def distance(self, other): def distance(self, other):
return hypot(self.x - other.x, self.y - other.y) return hypot(self.x - other.x, self.y - other.y)
def distance_squared(self, other):
return (self.x - other.x) ** 2 + (self.y - other.y) ** 2
def add(self, other): def add(self, other):
return Point(self.x + other.x, self.y + other.y) return Point(self.x + other.x, self.y + other.y)
@ -106,6 +109,18 @@ class Point(_Point):
v = other.sub(self).normalize() v = other.sub(self).normalize()
return self.add(v.mul(s)) return self.add(v.mul(s))
def segment_distance(self, v, w):
p = self
l2 = v.distance_squared(w)
if l2 == 0:
return p.distance(v)
t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2
t = max(0, min(1, t))
x = v.x + t * (w.x - v.x)
y = v.y + t * (w.y - v.y)
q = Point(x, y)
return p.distance(q)
Triangle = namedtuple('Triangle', Triangle = namedtuple('Triangle',
['s1', 's2', 't1', 't2', 'vmax', 'p1', 'p2', 'p3']) ['s1', 's2', 't1', 't2', 'vmax', 'p1', 'p2', 'p3'])
@ -158,18 +173,77 @@ class Segment(object):
self.entry_velocity = 0 self.entry_velocity = 0
self.blocks = [] self.blocks = []
class Throttler(object):
def __init__(self, points, vmax, dt, threshold):
self.points = points
self.vmax = vmax
self.dt = dt
self.threshold = threshold
self.distances = []
prev = points[0]
d = 0
for point in points:
d += prev.distance(point)
self.distances.append(d)
prev = point
def lookup(self, d):
return bisect(self.distances, d) - 1
def is_feasible(self, i0, v):
d = v * self.dt
x0 = self.distances[i0]
x1 = x0 + d
i1 = self.lookup(x1)
if i0 == i1:
return True
p0 = self.points[i0]
p10 = self.points[i1]
try:
p11 = self.points[i1+1]
except IndexError:
p11 = p10
s = x1 - self.distances[i1]
p1 = p10.lerps(p11, s)
i = i0 + 1
while i <= i1:
p = self.points[i]
if p.segment_distance(p0, p1) > self.threshold:
return False
i += 1
return True
def compute_max_velocity(self, index):
if self.is_feasible(index, self.vmax):
return self.vmax
lo = 0
hi = self.vmax
for _ in range(16):
v = (lo + hi) / 2
if self.is_feasible(index, v):
lo = v
else:
hi = v
v = lo
return v
def compute_max_velocities(self):
return [self.compute_max_velocity(i) for i in range(len(self.points))]
def constant_acceleration_plan(points, a, vmax, cf): def constant_acceleration_plan(points, a, vmax, cf):
# make sure points are Point objects # make sure points are Point objects
points = [Point(x, y) for x, y in points] points = [Point(x, y) for x, y in points]
# the throttler reduces speeds based on the discrete timeslicing nature of
# the device
# TODO: expose parameters
throttler = Throttler(points, vmax, 0.02, 0.001)
max_velocities = throttler.compute_max_velocities()
# create segments for each consecutive pair of points # create segments for each consecutive pair of points
segments = [Segment(p1, p2) for p1, p2 in zip(points, points[1:])] segments = [Segment(p1, p2) for p1, p2 in zip(points, points[1:])]
# compute a max_entry_velocity for each segment # compute a max_entry_velocity for each segment
# based on the angle formed by the two segments at the vertex # based on the angle formed by the two segments at the vertex
for s1, s2 in zip(segments, segments[1:]): for v, s1, s2 in zip(max_velocities, segments, segments[1:]):
v = corner_velocity(s1, s2, vmax, a, cf) s1.max_entry_velocity = min(s1.max_entry_velocity, v)
s2.max_entry_velocity = v s2.max_entry_velocity = corner_velocity(s1, s2, vmax, a, cf)
# add a dummy segment at the end to force a final velocity of zero # add a dummy segment at the end to force a final velocity of zero
segments.append(Segment(points[-1], points[-1])) segments.append(Segment(points[-1], points[-1]))