blob: f398d199de4947b14f208b0636a156c29a88c746 [file] [log] [blame]
Austin Schuh35d19872018-11-30 15:50:47 +11001#!/usr/bin/python
2
3from __future__ import print_function
4
Austin Schuh35d19872018-11-30 15:50:47 +11005from matplotlib import pylab
Austin Schuh35d19872018-11-30 15:50:47 +11006import gflags
Austin Schuh387a6872018-12-01 19:14:33 +11007import glog
8import numpy
9import scipy
10import scipy.integrate
11import sys
Austin Schuh35d19872018-11-30 15:50:47 +110012
Austin Schuh44aa9142018-12-03 21:07:23 +110013from frc971.control_loops.python import polydrivetrain
14import y2018.control_loops.python.drivetrain
15
Austin Schuh387a6872018-12-01 19:14:33 +110016"""This file is my playground for implementing spline following.
17
18All splines here are cubic bezier splines. See
19 https://en.wikipedia.org/wiki/B%C3%A9zier_curve for more details.
20"""
Austin Schuh35d19872018-11-30 15:50:47 +110021
22FLAGS = gflags.FLAGS
23
24
25def spline(alpha, control_points):
Austin Schuh387a6872018-12-01 19:14:33 +110026 """Computes a Cubic Bezier curve.
Austin Schuh35d19872018-11-30 15:50:47 +110027
28 Args:
29 alpha: scalar or list of spline parameters to calculate the curve at.
30 control_points: n x 4 matrix of control points. n[:, 0] is the
31 starting point, and n[:, 3] is the ending point.
32
33 Returns:
34 n x m matrix of spline points. n is the dimension of the control
35 points, and m is the number of points in 'alpha'.
36 """
37 if numpy.isscalar(alpha):
38 alpha = [alpha]
39 alpha_matrix = [[(1.0 - a)**3.0, 3.0 * (1.0 - a)**2.0 * a,
40 3.0 * (1.0 - a) * a**2.0, a**3.0] for a in alpha]
41
42 return control_points * numpy.matrix(alpha_matrix).T
43
44
45def dspline(alpha, control_points):
Austin Schuh387a6872018-12-01 19:14:33 +110046 """Computes the derivative of a Cubic Bezier curve wrt alpha.
Austin Schuh35d19872018-11-30 15:50:47 +110047
48 Args:
49 alpha: scalar or list of spline parameters to calculate the curve at.
50 control_points: n x 4 matrix of control points. n[:, 0] is the
51 starting point, and n[:, 3] is the ending point.
52
53 Returns:
54 n x m matrix of spline point derivatives. n is the dimension of the
55 control points, and m is the number of points in 'alpha'.
56 """
57 if numpy.isscalar(alpha):
58 alpha = [alpha]
59 dalpha_matrix = [[
60 -3.0 * (1.0 - a)**2.0, 3.0 * (1.0 - a)**2.0 + -2.0 * 3.0 *
61 (1.0 - a) * a, -3.0 * a**2.0 + 2.0 * 3.0 * (1.0 - a) * a, 3.0 * a**2.0
62 ] for a in alpha]
63
64 return control_points * numpy.matrix(dalpha_matrix).T
65
66
67def ddspline(alpha, control_points):
Austin Schuh387a6872018-12-01 19:14:33 +110068 """Computes the second derivative of a Cubic Bezier curve wrt alpha.
Austin Schuh35d19872018-11-30 15:50:47 +110069
70 Args:
71 alpha: scalar or list of spline parameters to calculate the curve at.
72 control_points: n x 4 matrix of control points. n[:, 0] is the
73 starting point, and n[:, 3] is the ending point.
74
75 Returns:
76 n x m matrix of spline point second derivatives. n is the dimension of
77 the control points, and m is the number of points in 'alpha'.
78 """
79 if numpy.isscalar(alpha):
80 alpha = [alpha]
81 ddalpha_matrix = [[
82 2.0 * 3.0 * (1.0 - a),
83 -2.0 * 3.0 * (1.0 - a) + -2.0 * 3.0 * (1.0 - a) + 2.0 * 3.0 * a,
84 -2.0 * 3.0 * a + 2.0 * 3.0 * (1.0 - a) - 2.0 * 3.0 * a,
85 2.0 * 3.0 * a
86 ] for a in alpha]
87
88 return control_points * numpy.matrix(ddalpha_matrix).T
89
90
91def dddspline(alpha, control_points):
Austin Schuh387a6872018-12-01 19:14:33 +110092 """Computes the third derivative of a Cubic Bezier curve wrt alpha.
Austin Schuh35d19872018-11-30 15:50:47 +110093
94 Args:
95 alpha: scalar or list of spline parameters to calculate the curve at.
96 control_points: n x 4 matrix of control points. n[:, 0] is the
97 starting point, and n[:, 3] is the ending point.
98
99 Returns:
100 n x m matrix of spline point second derivatives. n is the dimension of
101 the control points, and m is the number of points in 'alpha'.
102 """
103 if numpy.isscalar(alpha):
104 alpha = [alpha]
105 ddalpha_matrix = [[
106 -2.0 * 3.0,
107 2.0 * 3.0 + 2.0 * 3.0 + 2.0 * 3.0,
108 -2.0 * 3.0 - 2.0 * 3.0 - 2.0 * 3.0,
109 2.0 * 3.0
110 ] for a in alpha]
111
112 return control_points * numpy.matrix(ddalpha_matrix).T
113
114
115def spline_theta(alpha, control_points, dspline_points=None):
Austin Schuh387a6872018-12-01 19:14:33 +1100116 """Computes the heading of a robot following a Cubic Bezier curve at alpha.
Austin Schuh35d19872018-11-30 15:50:47 +1100117
118 Args:
119 alpha: scalar or list of spline parameters to calculate the heading at.
120 control_points: n x 4 matrix of control points. n[:, 0] is the
121 starting point, and n[:, 3] is the ending point.
122
123 Returns:
124 m array of spline point headings. m is the number of points in 'alpha'.
125 """
126 if dspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100127 dspline_points = dspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100128
129 return numpy.arctan2(
130 numpy.array(dspline_points)[1, :], numpy.array(dspline_points)[0, :])
131
132
Austin Schuh387a6872018-12-01 19:14:33 +1100133def dspline_theta(alpha,
Austin Schuh35d19872018-11-30 15:50:47 +1100134 control_points,
135 dspline_points=None,
136 ddspline_points=None):
Austin Schuh387a6872018-12-01 19:14:33 +1100137 """Computes the derivative of the heading at alpha.
Austin Schuh35d19872018-11-30 15:50:47 +1100138
Austin Schuh387a6872018-12-01 19:14:33 +1100139 This is the derivative of spline_theta wrt alpha.
Austin Schuh35d19872018-11-30 15:50:47 +1100140
141 Args:
142 alpha: scalar or list of spline parameters to calculate the derivative
143 of the heading at.
144 control_points: n x 4 matrix of control points. n[:, 0] is the
145 starting point, and n[:, 3] is the ending point.
146
147 Returns:
148 m array of spline point heading derivatives. m is the number of points
149 in 'alpha'.
150 """
151 if dspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100152 dspline_points = dspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100153
154 if ddspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100155 ddspline_points = ddspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100156
157 dx = numpy.array(dspline_points)[0, :]
158 dy = numpy.array(dspline_points)[1, :]
159
160 ddx = numpy.array(ddspline_points)[0, :]
161 ddy = numpy.array(ddspline_points)[1, :]
162
163 return 1.0 / (dx**2.0 + dy**2.0) * (dx * ddy - dy * ddx)
164
165
Austin Schuh387a6872018-12-01 19:14:33 +1100166def ddspline_theta(alpha,
Austin Schuh35d19872018-11-30 15:50:47 +1100167 control_points,
168 dspline_points=None,
169 ddspline_points=None,
170 dddspline_points=None):
Austin Schuh387a6872018-12-01 19:14:33 +1100171 """Computes the second derivative of the heading at alpha.
Austin Schuh35d19872018-11-30 15:50:47 +1100172
Austin Schuh387a6872018-12-01 19:14:33 +1100173 This is the second derivative of spline_theta wrt alpha.
Austin Schuh35d19872018-11-30 15:50:47 +1100174
175 Args:
176 alpha: scalar or list of spline parameters to calculate the second
177 derivative of the heading at.
178 control_points: n x 4 matrix of control points. n[:, 0] is the
179 starting point, and n[:, 3] is the ending point.
180
181 Returns:
182 m array of spline point heading second derivatives. m is the number of
183 points in 'alpha'.
184 """
185 if dspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100186 dspline_points = dspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100187
188 if ddspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100189 ddspline_points = ddspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100190
191 if dddspline_points is None:
Austin Schuh387a6872018-12-01 19:14:33 +1100192 dddspline_points = dddspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100193
Austin Schuh387a6872018-12-01 19:14:33 +1100194 dddspline_points = dddspline(alpha, control_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100195
196 dx = numpy.array(dspline_points)[0, :]
197 dy = numpy.array(dspline_points)[1, :]
198
199 ddx = numpy.array(ddspline_points)[0, :]
200 ddy = numpy.array(ddspline_points)[1, :]
201
202 dddx = numpy.array(dddspline_points)[0, :]
203 dddy = numpy.array(dddspline_points)[1, :]
204
205 return -1.0 / ((dx**2.0 + dy**2.0)**2.0) * (dx * ddy - dy * ddx) * 2.0 * (
206 dy * ddy + dx * ddx) + 1.0 / (dx**2.0 + dy**2.0) * (dx * dddy - dy *
207 dddx)
208
209
Austin Schuh387a6872018-12-01 19:14:33 +1100210class Path(object):
211 """Represents a path to follow."""
212 def __init__(self, control_points):
213 """Constructs a path given the control points."""
214 self._control_points = control_points
215
216 def spline_velocity(alpha):
217 return numpy.linalg.norm(dspline(alpha, self._control_points), axis=0)
218
219 self._point_distances = [0.0]
220 num_alpha = 100
221 # Integrate the xy velocity as a function of alpha for each step in the
222 # table to get an alpha -> distance calculation. Gaussian Quadrature
223 # is quite accurate, so we can get away with fewer points here than we
224 # might think.
225 for alpha in numpy.linspace(0.0, 1.0, num_alpha)[:-1]:
226 self._point_distances.append(
227 scipy.integrate.fixed_quad(spline_velocity, alpha, alpha + 1.0
228 / (num_alpha - 1.0))[0] +
229 self._point_distances[-1])
230
231 def distance_to_alpha(self, distance):
232 """Converts distances along the spline to alphas.
233
234 Args:
235 distance: A scalar or array of distances to convert
236
237 Returns:
238 An array of distances, (1 big if the input was a scalar)
239 """
240 if numpy.isscalar(distance):
241 return numpy.array([self._distance_to_alpha_scalar(distance)])
242 else:
243 return numpy.array([self._distance_to_alpha_scalar(d) for d in distance])
244
245 def _distance_to_alpha_scalar(self, distance):
246 """Helper to compute alpha for a distance for a single scalar."""
247 if distance <= 0.0:
248 return 0.0
249 elif distance >= self.length():
250 return 1.0
251 after_index = numpy.searchsorted(
252 self._point_distances, distance, side='right')
253 before_index = after_index - 1
254
255 # Linearly interpolate alpha from our (sorted) distance table.
256 return (distance - self._point_distances[before_index]) / (
257 self._point_distances[after_index] -
258 self._point_distances[before_index]) * (1.0 / (
259 len(self._point_distances) - 1.0)) + float(before_index) / (
260 len(self._point_distances) - 1.0)
261
262 def length(self):
263 """Returns the length of the spline (in meters)"""
264 return self._point_distances[-1]
265
266 # TODO(austin): need a better name...
267 def xy(self, distance):
268 """Returns the xy position as a function of distance."""
269 return spline(self.distance_to_alpha(distance), self._control_points)
270
271 # TODO(austin): need a better name...
272 def dxy(self, distance):
273 """Returns the xy velocity as a function of distance."""
274 dspline_point = dspline(
275 self.distance_to_alpha(distance), self._control_points)
276 return dspline_point / numpy.linalg.norm(dspline_point, axis=0)
277
278 # TODO(austin): need a better name...
279 def ddxy(self, distance):
280 """Returns the xy acceleration as a function of distance."""
281 alpha = self.distance_to_alpha(distance)
282 dspline_points = dspline(alpha, self._control_points)
283 ddspline_points = ddspline(alpha, self._control_points)
284
285 norm = numpy.linalg.norm(
286 dspline_points, axis=0)**2.0
287
288 return ddspline_points / norm - numpy.multiply(
289 dspline_points, (numpy.array(dspline_points)[0, :] *
290 numpy.array(ddspline_points)[0, :] +
291 numpy.array(dspline_points)[1, :] *
292 numpy.array(ddspline_points)[1, :]) / (norm**2.0))
293
294 def theta(self, distance, dspline_points=None):
295 """Returns the heading as a function of distance."""
296 return spline_theta(
297 self.distance_to_alpha(distance),
298 self._control_points,
299 dspline_points=dspline_points)
300
301 def dtheta(self, distance, dspline_points=None, ddspline_points=None):
302 """Returns the angular velocity as a function of distance."""
303 alpha = self.distance_to_alpha(distance)
304 if dspline_points is None:
305 dspline_points = dspline(alpha, self._control_points)
306 if ddspline_points is None:
307 ddspline_points = ddspline(alpha, self._control_points)
308
309 dtheta_points = dspline_theta(alpha, self._control_points,
310 dspline_points, ddspline_points)
311
312 return dtheta_points / numpy.linalg.norm(dspline_points, axis=0)
313
314 def ddtheta(self,
315 distance,
316 dspline_points=None,
317 ddspline_points=None,
318 dddspline_points=None):
319 """Returns the angular acceleration as a function of distance."""
320 alpha = self.distance_to_alpha(distance)
321 if dspline_points is None:
322 dspline_points = dspline(alpha, self._control_points)
323 if ddspline_points is None:
324 ddspline_points = ddspline(alpha, self._control_points)
325 if dddspline_points is None:
326 dddspline_points = dddspline(alpha, self._control_points)
327
328 dtheta_points = dspline_theta(alpha, self._control_points,
329 dspline_points, ddspline_points)
330 ddtheta_points = ddspline_theta(alpha, self._control_points,
331 dspline_points, ddspline_points,
332 dddspline_points)
333
334 # TODO(austin): Factor out the d^alpha/dd^2.
335 return ddtheta_points / numpy.linalg.norm(
336 dspline_points, axis=0)**2.0 - numpy.multiply(
337 dtheta_points, (numpy.array(dspline_points)[0, :] *
338 numpy.array(ddspline_points)[0, :] +
339 numpy.array(dspline_points)[1, :] *
340 numpy.array(ddspline_points)[1, :]) /
341 ((numpy.array(dspline_points)[0, :]**2.0 +
342 numpy.array(dspline_points)[1, :]**2.0)**2.0))
343
344
345
Austin Schuh35d19872018-11-30 15:50:47 +1100346def main(argv):
347 # Build up the control point matrix
348 start = numpy.matrix([[0.0, 0.0]]).T
349 c1 = numpy.matrix([[0.5, 0.0]]).T
350 c2 = numpy.matrix([[0.5, 1.0]]).T
351 end = numpy.matrix([[1.0, 1.0]]).T
352 control_points = numpy.hstack((start, c1, c2, end))
353
354 # The alphas to plot
355 alphas = numpy.linspace(0.0, 1.0, 1000)
356
357 # Compute x, y and the 3 derivatives
358 spline_points = spline(alphas, control_points)
359 dspline_points = dspline(alphas, control_points)
360 ddspline_points = ddspline(alphas, control_points)
361 dddspline_points = dddspline(alphas, control_points)
362
363 # Compute theta and the two derivatives
364 theta = spline_theta(alphas, control_points, dspline_points=dspline_points)
Austin Schuh387a6872018-12-01 19:14:33 +1100365 dtheta = dspline_theta(
366 alphas, control_points, dspline_points=dspline_points)
Austin Schuh35d19872018-11-30 15:50:47 +1100367 ddtheta = ddspline_theta(
368 alphas,
369 control_points,
370 dspline_points=dspline_points,
371 dddspline_points=dddspline_points)
372
373 # Plot the control points and the spline.
374 pylab.figure()
375 pylab.plot(
376 numpy.array(control_points)[0, :],
377 numpy.array(control_points)[1, :],
378 '-o',
379 label='control')
380 pylab.plot(
381 numpy.array(spline_points)[0, :],
382 numpy.array(spline_points)[1, :],
383 label='spline')
384 pylab.legend()
385
386 # For grins, confirm that the double integral of the acceleration (with
387 # respect to the spline parameter) matches the position. This lets us
388 # confirm that the derivatives are consistent.
389 xint_plot = numpy.matrix(numpy.zeros((2, len(alphas))))
390 dxint_plot = xint_plot.copy()
391 xint = spline_points[:, 0].copy()
392 dxint = dspline_points[:, 0].copy()
393 xint_plot[:, 0] = xint
394 dxint_plot[:, 0] = dxint
395 for i in range(len(alphas) - 1):
396 xint += (alphas[i + 1] - alphas[i]) * dxint
397 dxint += (alphas[i + 1] - alphas[i]) * ddspline_points[:, i]
398 xint_plot[:, i + 1] = xint
399 dxint_plot[:, i + 1] = dxint
400
401 # Integrate up the spline velocity and heading to confirm that given a
402 # velocity (as a function of the spline parameter) and angle, we will move
403 # from the starting point to the ending point.
404 thetaint_plot = numpy.zeros((len(alphas),))
405 thetaint = theta[0]
406 dthetaint_plot = numpy.zeros((len(alphas),))
407 dthetaint = dtheta[0]
408 thetaint_plot[0] = thetaint
409 dthetaint_plot[0] = dthetaint
410
411 txint_plot = numpy.matrix(numpy.zeros((2, len(alphas))))
412 txint = spline_points[:, 0].copy()
413 txint_plot[:, 0] = txint
414 for i in range(len(alphas) - 1):
415 dalpha = alphas[i + 1] - alphas[i]
416 txint += dalpha * numpy.linalg.norm(
417 dspline_points[:, i]) * numpy.matrix(
418 [[numpy.cos(theta[i])], [numpy.sin(theta[i])]])
419 txint_plot[:, i + 1] = txint
420 thetaint += dalpha * dtheta[i]
421 dthetaint += dalpha * ddtheta[i]
422 thetaint_plot[i + 1] = thetaint
423 dthetaint_plot[i + 1] = dthetaint
424
425
426 # Now plot x, dx/dalpha, ddx/ddalpha, dddx/dddalpha, and integrals thereof
427 # to perform consistency checks.
428 pylab.figure()
429 pylab.plot(alphas, numpy.array(spline_points)[0, :], label='x')
430 pylab.plot(alphas, numpy.array(xint_plot)[0, :], label='ix')
431 pylab.plot(alphas, numpy.array(dspline_points)[0, :], label='dx')
432 pylab.plot(alphas, numpy.array(dxint_plot)[0, :], label='idx')
433 pylab.plot(alphas, numpy.array(txint_plot)[0, :], label='tix')
434 pylab.plot(alphas, numpy.array(ddspline_points)[0, :], label='ddx')
435 pylab.plot(alphas, numpy.array(dddspline_points)[0, :], label='dddx')
436 pylab.legend()
437
438 # Now do the same for y.
439 pylab.figure()
440 pylab.plot(alphas, numpy.array(spline_points)[1, :], label='y')
441 pylab.plot(alphas, numpy.array(xint_plot)[1, :], label='iy')
442 pylab.plot(alphas, numpy.array(dspline_points)[1, :], label='dy')
443 pylab.plot(alphas, numpy.array(dxint_plot)[1, :], label='idy')
444 pylab.plot(alphas, numpy.array(txint_plot)[1, :], label='tiy')
445 pylab.plot(alphas, numpy.array(ddspline_points)[1, :], label='ddy')
446 pylab.plot(alphas, numpy.array(dddspline_points)[1, :], label='dddy')
447 pylab.legend()
448
449 # And for theta.
450 pylab.figure()
451 pylab.plot(alphas, theta, label='theta')
452 pylab.plot(alphas, dtheta, label='dtheta')
453 pylab.plot(alphas, ddtheta, label='ddtheta')
454 pylab.plot(alphas, thetaint_plot, label='thetai')
455 pylab.plot(alphas, dthetaint_plot, label='dthetai')
Austin Schuh387a6872018-12-01 19:14:33 +1100456 pylab.plot(
457 alphas,
458 numpy.linalg.norm(
459 numpy.array(dspline_points), axis=0),
460 label='velocity')
461
462 # Now, repeat as a function of path length as opposed to alpha
463 path = Path(control_points)
464 distance_count = 1000
465 position = path.xy(0.0)
466 velocity = path.dxy(0.0)
467 theta = path.theta(0.0)
468 omega = path.dtheta(0.0)
469
470 iposition_plot = numpy.matrix(numpy.zeros((2, distance_count)))
471 ivelocity_plot = numpy.matrix(numpy.zeros((2, distance_count)))
472 iposition_plot[:, 0] = position.copy()
473 ivelocity_plot[:, 0] = velocity.copy()
474 itheta_plot = numpy.zeros((distance_count,))
475 iomega_plot = numpy.zeros((distance_count,))
476 itheta_plot[0] = theta
477 iomega_plot[0] = omega
478
479 distances = numpy.linspace(0.0, path.length(), distance_count)
480
481 for i in xrange(len(distances) - 1):
482 position += velocity * (distances[i + 1] - distances[i])
483 velocity += path.ddxy(distances[i]) * (distances[i + 1] - distances[i])
484 iposition_plot[:, i + 1] = position
485 ivelocity_plot[:, i + 1] = velocity
486
487 theta += omega * (distances[i + 1] - distances[i])
488 omega += path.ddtheta(distances[i]) * (distances[i + 1] - distances[i])
489 itheta_plot[i + 1] = theta
490 iomega_plot[i + 1] = omega
491
492 pylab.figure()
493 pylab.plot(distances, numpy.array(path.xy(distances))[0, :], label='x')
494 pylab.plot(distances, numpy.array(iposition_plot)[0, :], label='ix')
495 pylab.plot(distances, numpy.array(path.dxy(distances))[0, :], label='dx')
496 pylab.plot(distances, numpy.array(ivelocity_plot)[0, :], label='idx')
497 pylab.plot(distances, numpy.array(path.ddxy(distances))[0, :], label='ddx')
498 pylab.legend()
499
500 pylab.figure()
501 pylab.plot(distances, numpy.array(path.xy(distances))[1, :], label='y')
502 pylab.plot(distances, numpy.array(iposition_plot)[1, :], label='iy')
503 pylab.plot(distances, numpy.array(path.dxy(distances))[1, :], label='dy')
504 pylab.plot(distances, numpy.array(ivelocity_plot)[1, :], label='idy')
505 pylab.plot(distances, numpy.array(path.ddxy(distances))[1, :], label='ddy')
506 pylab.legend()
507
508 pylab.figure()
509 pylab.plot(distances, path.theta(distances), label='theta')
510 pylab.plot(distances, itheta_plot, label='itheta')
511 pylab.plot(distances, path.dtheta(distances), label='omega')
512 pylab.plot(distances, iomega_plot, label='iomega')
513 pylab.plot(distances, path.ddtheta(distances), label='alpha')
514 pylab.legend()
Austin Schuh35d19872018-11-30 15:50:47 +1100515
516 # TODO(austin): Start creating a velocity plan now that we have all the
517 # derivitives of our spline.
518
Austin Schuh44aa9142018-12-03 21:07:23 +1100519 velocity_drivetrain = polydrivetrain.VelocityDrivetrainModel(
520 y2018.control_loops.python.drivetrain.kDrivetrain)
521
522 vmax = numpy.inf
523 vmax = 10.0
524 lateral_accel_plan = numpy.array(numpy.zeros((distance_count, )))
525 lateral_accel_plan.fill(vmax)
526 curvature_plan = lateral_accel_plan.copy()
527
528 longitudal_accel = 15.0
529 lateral_accel = 20.0
530
531 for i, distance in enumerate(distances):
532 lateral_accel_plan[i] = min(
533 lateral_accel_plan[i],
534 numpy.sqrt(lateral_accel / numpy.linalg.norm(path.ddxy(distance))))
535
536 # We've now got the equation: K1 (dx/dt)^2 = A * K2 * dx/dt + B * U
537 # We need to find the feasible
538 current_ddtheta = path.ddtheta(distance)[0]
539 current_dtheta = path.dtheta(distance)[0]
540 K1 = numpy.matrix(
541 [[-velocity_drivetrain.robot_radius_l * current_ddtheta],
542 [velocity_drivetrain.robot_radius_r * current_ddtheta]])
543 K2 = numpy.matrix(
544 [[1.0 - velocity_drivetrain.robot_radius_l * current_dtheta],
545 [1.0 + velocity_drivetrain.robot_radius_r * current_dtheta]])
546 A = velocity_drivetrain.A_continuous
547 B = velocity_drivetrain.B_continuous
548
549 # Now, rephrase it as K5 a + K3 v^2 + K4 v = U
550 # Now, rephrase it as K5 a + K3 v^2 + K4 v = U
551 K3 = numpy.linalg.inv(B) * K1
552 K5 = numpy.linalg.inv(B) * K2
553 K4 = -K5
554
555 x = []
556 for a, b in [(K3[0, 0], K4[0, 0]), (K3[1, 0], K4[1, 0])]:
557 for c in [12.0, -12.0]:
558 middle = b * b - 4.0 * a * c
559 if middle >= 0.0:
560 x.append((-b + numpy.sqrt(middle)) / (2.0 * a))
561 x.append((-b - numpy.sqrt(middle)) / (2.0 * a))
562
563 maxx = 0.0
564 for newx in x:
565 if newx < 0.0:
566 continue
567 U = (K3 * newx * newx + K4 * newx).T
568 # TODO(austin): We know that one of these *will* be +-12.0. Only
569 # check the other one.
570 if not (numpy.abs(U) > 12.0 + 1e-6).any():
571 maxx = max(newx, maxx)
572
573 if maxx == 0.0:
574 print('Could not solve')
575 curvature_plan[i] = min(lateral_accel_plan[i], maxx)
576
577 pylab.figure()
578 pylab.plot(distances, lateral_accel_plan, label='accel pass')
579 pylab.plot(distances, curvature_plan, label='voltage limit pass')
580 pylab.xlabel("distance along spline (m)")
581 pylab.ylabel("velocity (m/s)")
582 pylab.legend()
583
Austin Schuh35d19872018-11-30 15:50:47 +1100584 pylab.show()
585
586
587if __name__ == '__main__':
588 argv = FLAGS(sys.argv)
589 sys.exit(main(argv))