Austin Schuh | 085eab9 | 2020-11-26 13:54:51 -0800 | [diff] [blame] | 1 | #!/usr/bin/python3
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 2 | import numpy as np
|
| 3 | import matplotlib.pyplot as plt
|
| 4 | from frc971.control_loops.python import drivetrain
|
| 5 |
|
| 6 | # used to define properties of the drivetrain, changes depending on robot
|
| 7 | # see yXXXX/control_loops/python/drivetrain.py for the current values
|
| 8 |
|
| 9 | kDrivetrain = drivetrain.DrivetrainParams(
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 10 | J=6.0,
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 11 | mass=68.0,
|
| 12 | robot_radius=0.616 / 2.0,
|
| 13 | wheel_radius=0.127 / 2.0 * 120.0 / 118.0,
|
| 14 | G_low=46.0 / 60.0 * 20.0 / 48.0 * 14.0 / 62.0,
|
| 15 | G_high=62.0 / 44.0 * 20.0 / 48.0 * 14.0 / 62.0,
|
| 16 | q_pos_low=0.12,
|
| 17 | q_pos_high=0.14,
|
| 18 | q_vel_low=1.0,
|
| 19 | q_vel_high=0.95,
|
| 20 | efficiency=0.70,
|
| 21 | has_imu=True,
|
| 22 | force=True,
|
| 23 | kf_q_voltage=13.0,
|
| 24 | controller_poles=[0.82, 0.82],
|
| 25 | )
|
| 26 |
|
| 27 | drivetrain = drivetrain.Drivetrain(kDrivetrain)
|
| 28 | # set up coefficients for Hemrite basis function evaluation
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 29 | coeffs = np.array([[1, 0, 0, -10, 15, -6], [0, 1, 0, -6, 8, -3],
|
| 30 | [0, 0, 0.5, -1.5, 1.5, -0.5], [0, 0, 0, 0.5, -1, 0.5],
|
| 31 | [0, 0, 0, -4, 7, -3], [0, 0, 0, 10, -15, 6]])
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 32 | coeffs_prime = np.empty_like(coeffs)
|
| 33 | for ii in range(0, len(coeffs)):
|
| 34 | for jj in range(0, len(coeffs[ii]) - 1):
|
| 35 | coeffs_prime[ii][jj] = (jj + 1) * coeffs[ii][jj]
|
| 36 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 37 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 38 | def RungeKutta(f, x, dt):
|
| 39 | """4th order RungeKutta integration of F starting at X."""
|
| 40 | a = f(x)
|
| 41 | b = f(x + dt / 2.0 * a)
|
| 42 | c = f(x + dt / 2.0 * b)
|
| 43 | d = f(x + dt * c)
|
| 44 |
|
| 45 | return x + dt * (a + 2.0 * b + 2.0 * c + d) / 6.0
|
| 46 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 47 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 48 | def normalize(v):
|
| 49 | norm = np.linalg.norm(v)
|
| 50 | return v / norm
|
| 51 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 52 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 53 | def theta(v):
|
| 54 | return np.arctan2(v[1], v[0])
|
| 55 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 56 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 57 | # evaluate Nth hermite basis function at t
|
| 58 | def nth_H(N, t):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 59 | return coeffs[N][0] + coeffs[N][1] * t + coeffs[N][2] * t**2 + coeffs[N][
|
| 60 | 3] * t**3 + coeffs[N][4] * t**4 + coeffs[N][5] * t**5
|
| 61 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 62 |
|
| 63 | def nth_H_prime(N, t):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 64 | return coeffs[N][0] + coeffs[N][1] * t + coeffs[N][2] * t**2 + coeffs[N][
|
| 65 | 3] * t**3 + coeffs[N][4] * t**4
|
| 66 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 67 |
|
| 68 | # class defining a quintic Hermite spline, with utilities for modification and plotting
|
| 69 | class Hermite_Spline:
|
| 70 | # init method given known parameters, ie savefile loading(if necessary)
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 71 | def __init__(self, start, control1, control2, end, resolution=200):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 72 | self.start = start
|
| 73 | self.end = end
|
| 74 | self.control1 = control1
|
| 75 | self.control2 = control2
|
| 76 |
|
| 77 | self.points = np.array([])
|
| 78 | self.velocities = []
|
| 79 | self.accelerations = []
|
| 80 | self.arc_lengths = []
|
| 81 | self.thetas = []
|
| 82 | self.omegas = []
|
| 83 | self.curvatures = []
|
| 84 |
|
| 85 | self.shifted_points = []
|
| 86 |
|
| 87 | self.Ks = []
|
| 88 | self.dKs = []
|
| 89 |
|
| 90 | # coefficients are po, v0, a0, a1, v1, p1
|
| 91 | self.coeffs = np.array([])
|
| 92 | self.compute_coefficients()
|
| 93 | self.resolution = resolution
|
| 94 | self.setup()
|
| 95 |
|
| 96 | # take paramters and compute coeffcicents for Hermite basis functions, to be called every time he change control points
|
| 97 | def compute_coefficients(self):
|
| 98 | self.coeffs = np.append(self.coeffs, np.array(self.start))
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 99 | self.coeffs = np.append(self.coeffs,
|
| 100 | np.array(self.control1) - np.array(self.start))
|
| 101 | self.coeffs = np.append(self.coeffs, [0, 0])
|
| 102 | self.coeffs = np.append(self.coeffs, [0, 0])
|
| 103 | self.coeffs = np.append(self.coeffs,
|
| 104 | np.array(self.end) - np.array(self.control2))
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 105 | self.coeffs = np.append(self.coeffs, np.array(self.end))
|
| 106 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 107 | self.coeffs = np.reshape(self.coeffs, newshape=(6, 2))
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 108 |
|
| 109 | # setters for control points, set coefficients
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 110 | def set_positions(self, p1=None, p2=None):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 111 | if p1 != None:
|
| 112 | self.start = p1
|
| 113 | if p2 != None:
|
| 114 | self.end = p2
|
| 115 |
|
| 116 | self.compute_coefficients()
|
| 117 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 118 | def set_controls(self, c1=None, c2=None):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 119 | if c1 != None:
|
| 120 | self.control1 = c1
|
| 121 | if c2 != None:
|
| 122 | self.control2 = c2
|
| 123 |
|
| 124 | self.compute_coefficients()
|
| 125 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 126 | def set_velocities(self, v1=None, v2=None):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 127 | if v1 != None:
|
| 128 | self.control1 = self.start + v1
|
| 129 | if v2 != None:
|
| 130 | self.control2 = self.end + v2
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 131 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 132 | self.compute_coefficients()
|
| 133 |
|
| 134 | def get_smoothness(self):
|
| 135 | K = self.get_curvature()
|
| 136 | return np.sum(np.abs(np.gradient(K)))
|
| 137 |
|
| 138 | # given Basis functions and controls compute coordinate given t
|
| 139 | def spline_eval_hermite(self, t):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 140 | return np.array(self.coeffs[0] * nth_H(0, t) +
|
| 141 | self.coeffs[1] * nth_H(1, t) +
|
| 142 | self.coeffs[2] * nth_H(2, t) +
|
| 143 | self.coeffs[3] * nth_H(3, t) +
|
| 144 | self.coeffs[4] * nth_H(4, t) +
|
| 145 | self.coeffs[5] * nth_H(5, t))
|
| 146 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 147 | # given Basis functions and controls compute velocity given t
|
| 148 | def spline_eval_hermite_v(self, t):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 149 | return normalize(
|
| 150 | np.array(self.coeffs[0] * nth_H_prime(0, t) +
|
| 151 | self.coeffs[1] * nth_H_prime(1, t) +
|
| 152 | self.coeffs[2] * nth_H_prime(2, t) +
|
| 153 | self.coeffs[3] * nth_H_prime(3, t) +
|
| 154 | self.coeffs[4] * nth_H_prime(4, t) +
|
| 155 | self.coeffs[5] * nth_H_prime(5, t)))
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 156 |
|
| 157 | # take coefficients and compute spline points/properties
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 158 | def setup(self, resolution_multiplier=10, dt=.000001):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 159 | points = []
|
| 160 | velocities = []
|
| 161 | accelerations = []
|
| 162 | s = []
|
| 163 | thetas = []
|
| 164 | omegas = []
|
| 165 | curvatures = []
|
| 166 |
|
| 167 | last_point = self.spline_eval_hermite(0)
|
| 168 | distance = 0
|
| 169 |
|
| 170 | # iterate through interim points and compute pos_vectors, and at predefined points arc length,
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 171 | # velocity, and acceleration vectors and store them at their associated index
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 172 | for i in range(0, self.resolution * resolution_multiplier):
|
| 173 | t = i / (1.0 * self.resolution * resolution_multiplier)
|
| 174 |
|
| 175 | current_point = self.spline_eval_hermite(t)
|
| 176 | current_point_dt = self.spline_eval_hermite(t + dt)
|
| 177 | current_s = np.linalg.norm(current_point - last_point)
|
| 178 |
|
| 179 | ds = np.linalg.norm(current_point_dt - current_point)
|
| 180 |
|
| 181 | distance = current_s + distance
|
| 182 | # at important points compute important values and store
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 183 | if i % resolution_multiplier == 0:
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 184 | s.append(distance)
|
| 185 | points.append(current_point)
|
| 186 |
|
| 187 | v = self.spline_eval_hermite_v(t)
|
| 188 | v_dt = self.spline_eval_hermite_v(t + dt)
|
| 189 | theta_t = theta(v)
|
| 190 | theta_dt = theta(v_dt)
|
| 191 |
|
| 192 | a = (v_dt - v) / ds
|
| 193 | omega = (theta_dt - theta_t) / ds
|
| 194 | if np.linalg.norm(v) == 0:
|
| 195 | curvature = 0
|
| 196 | else:
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 197 | curvature = np.linalg.det(
|
| 198 | np.column_stack((v, a)) / (np.linalg.norm(v)**(3 / 2)))
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 199 |
|
| 200 | velocities.append(v)
|
| 201 | accelerations.append(a)
|
| 202 | thetas.append(theta_t)
|
| 203 | omegas.append(omega)
|
| 204 | if curvature == 0:
|
| 205 | curvatures.append(0.0001)
|
| 206 | else:
|
| 207 | curvatures.append(curvature)
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 208 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 209 | last_point = current_point
|
| 210 |
|
| 211 | self.arc_lengths = np.array(s)
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 212 | self.points = np.reshape(points, newshape=(-1, 2))
|
| 213 | self.velocities = np.reshape(velocities, newshape=(-1, 2))
|
| 214 | self.accelerations = np.reshape(accelerations, newshape=(-1, 2))
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 215 | self.thetas = np.array(thetas)
|
| 216 | self.omegas = np.array(omegas)
|
| 217 | self.curvatures = np.array(curvatures)
|
| 218 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 219 | def plot_diagnostics(self):
|
| 220 | plt.figure("Spline")
|
| 221 | plt.title('Spline')
|
| 222 | plt.plot(self.points[:, 0], self.points[:, 1])
|
| 223 | # plt.scatter(self.points[:, 0], self.points[:, 1])
|
| 224 |
|
| 225 | plt.figure("Diagnostics")
|
| 226 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 227 | plt.subplot(2, 2, 1)
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 228 | plt.title('theta')
|
| 229 | plt.xlabel('arc_length')
|
| 230 | plt.ylabel('theta')
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 231 | theta, = plt.plot(self.arc_lengths, self.thetas, label='theta')
|
| 232 | plt.legend(handles=[theta])
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 233 |
|
| 234 | plt.subplot(2, 2, 2)
|
| 235 | plt.title('omegas')
|
| 236 | plt.xlabel('arc_length')
|
| 237 | plt.ylabel('omega')
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 238 | omega, = plt.plot(self.arc_lengths, self.omegas, label='omega')
|
| 239 | plt.legend(handles=[omega])
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 240 |
|
| 241 | plt.subplot(2, 2, 3)
|
| 242 | plt.title('Velocities')
|
| 243 | plt.xlabel('arc_length')
|
| 244 | plt.ylabel('velocity')
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 245 | dxds, = plt.plot(self.arc_lengths,
|
| 246 | self.velocities[:, 0],
|
| 247 | label='dx/ds')
|
| 248 | dyds, = plt.plot(self.arc_lengths,
|
| 249 | self.velocities[:, 1],
|
| 250 | label='dy/ds')
|
| 251 | plt.legend(handles=[dxds, dyds])
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 252 |
|
| 253 | plt.subplot(2, 2, 4)
|
| 254 | plt.title('Accelerations')
|
| 255 | plt.xlabel('arc_length')
|
| 256 | plt.ylabel('acceleration')
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 257 | dx2ds2, = plt.plot(self.arc_lengths,
|
| 258 | self.accelerations[:, 0],
|
| 259 | label='d^2x/ds^2')
|
| 260 | dy2ds2, = plt.plot(self.arc_lengths,
|
| 261 | self.accelerations[:, 1],
|
| 262 | label='d^2x/ds^2')
|
| 263 | plt.legend(handles=[dx2ds2, dy2ds2])
|
| 264 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 265 |
|
| 266 | # class defining a number of splines with convinience methods
|
| 267 | class Path:
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 268 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 269 | def __init__(self):
|
| 270 | self.splines = []
|
| 271 | self.knot_accels = []
|
| 272 |
|
| 273 | def add_spline(self, spline):
|
| 274 | self.splines.append(spline)
|
| 275 |
|
| 276 | def get_K(self):
|
| 277 | curvatures = []
|
| 278 | for spline in self.splines:
|
| 279 | curvatures.append(spline.curvatures)
|
| 280 | return np.array(curvatures).flatten()
|
| 281 |
|
| 282 | def get_S(self):
|
| 283 | arc_lengths = []
|
| 284 | for spline in self.splines:
|
| 285 | arc_lengths.append(spline.arc_lengths)
|
| 286 | return np.array(arc_lengths).flatten()
|
| 287 |
|
| 288 | def get_points(self):
|
| 289 | points = []
|
| 290 | for spline in self.splines:
|
| 291 | points.append(spline.points)
|
| 292 | return points
|
| 293 |
|
| 294 | def get_velocities(self, i):
|
| 295 | velocities = []
|
| 296 | for spline in self.splines:
|
| 297 | velocities.append(spline.points)
|
| 298 | return velocities
|
| 299 |
|
| 300 | def remove_spine(self, i):
|
| 301 | if i < len(self.splines):
|
| 302 | self.splines.pop(i)
|
| 303 | else:
|
| 304 | print("index %f out of bounds, no spline of that index" % i)
|
| 305 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 306 | def join(self, first_priority=False):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 307 | for i in range(0, len(self.splines)):
|
| 308 | if first_priority & i != len(self.splines):
|
| 309 | print("unfinished")
|
| 310 |
|
| 311 |
|
| 312 | # class which takes a Path object along with constraints and reparamterizes it with respect to time
|
| 313 | class Trajectory:
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 314 |
|
| 315 | def __init__(self,
|
| 316 | path,
|
| 317 | max_angular_accel=3,
|
| 318 | max_voltage=11,
|
| 319 | max_normal_accel=.2):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 320 | self.path = path
|
| 321 | self.A = drivetrain.A_continuous
|
| 322 | self.B = drivetrain.B_continuous
|
| 323 | self.robot_radius = drivetrain.robot_radius
|
| 324 | self.Kv = 100
|
| 325 | self.robot_radius = 3
|
| 326 | self.max_angular_accel = max_angular_accel
|
| 327 | self.max_voltage = max_voltage
|
| 328 | self.max_normal_accel = max_normal_accel
|
| 329 |
|
| 330 | self.max_velocities_adhering_to_normal_accel = []
|
| 331 | self.max_velocities_adhering_to_voltage = []
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 332 | self.path.splines[0].setup(resolution_multiplier=100)
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 333 |
|
| 334 | self.set_max_v_adhering_to_normal_accel()
|
| 335 | self.max_voltageK_pass()
|
| 336 |
|
| 337 | def set_max_v_adhering_to_normal_accel(self):
|
| 338 | Ks = self.path.get_K()
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 339 | accels = np.full_like(Ks, fill_value=self.max_normal_accel)
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 340 | max_velocities = np.sqrt(np.abs(accels / Ks))
|
| 341 | self.max_velocities_adhering_to_normal_accel = max_velocities
|
| 342 |
|
| 343 | def max_voltageK_pass(self):
|
| 344 | max_ds_dt = []
|
| 345 | Ks = self.path.get_K()
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 346 | turning_radii = np.full_like(Ks, fill_value=1) / np.abs(Ks)
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 347 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 348 | # compute max steady-state velocity given voltage constraints
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 349 | for i in range(0, len(Ks)):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 350 | v_ratio = (turning_radii[i] + self.robot_radius) / (
|
| 351 | turning_radii[i] - self.robot_radius)
|
| 352 | matrix = np.array([[self.A[1, 1], self.A[1, 3], self.B[1, 1]],
|
| 353 | [self.A[3, 1] - 1, self.A[3, 3], self.B[3, 1]],
|
| 354 | [-1, v_ratio, 0]])
|
| 355 | sols = np.array([
|
| 356 | -1 * self.max_voltage * self.B[1, 0],
|
| 357 | -1 * self.max_voltage * self.B[3, 0], 0
|
| 358 | ])
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 359 | Vs = np.dot(np.linalg.inv(matrix), sols)
|
| 360 | max_ds_dt.append((Vs[0] + Vs[1]) / 2)
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 361 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 362 | self.max_velocities_adhering_to_voltage = max_ds_dt
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 363 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 364 | # compute the maximum acceleration we can ask for given voltage and, ya know, staying on the path.
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 365 | '''
|
| 366 | These methods use the continuous form of our drivetrain state equation
|
| 367 | in order to compute the maximum acceleration which adheres to the path
|
| 368 | and voltage constraints, as well as any arbitary set of constraints
|
| 369 | on velocity as a function of arc_length
|
| 370 | '''
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 371 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 372 | def forward_accel_pass(self):
|
| 373 | points = self.path.get_points()
|
| 374 | velocities = self.path.get_velocities()
|
| 375 | curvatures = self.path.get_K()
|
| 376 | arc_lenghts = self.path.get_S()
|
| 377 |
|
| 378 | for i in range(0, len(points)):
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 379 | #Xn1 =
|
| 380 | pass
|
| 381 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 382 | def backward_accelaration_pass(self):
|
| 383 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 384 | print("max backward accel pass")
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 385 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 386 | def plot_diagnostics(self, i=0):
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 387 |
|
| 388 | plt.figure('max velocity')
|
| 389 | plt.title('max_v_normal_accel')
|
| 390 | plt.xlabel('arc_length')
|
| 391 | plt.ylabel('max V')
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 392 | max_v_normal = plt.plot(self.path.get_S(),
|
| 393 | self.max_velocities_adhering_to_normal_accel,
|
| 394 | label='ds/dt (normal)') # , label = 'ds/dt')
|
| 395 | curvature = plt.plot(self.path.get_S(),
|
| 396 | 1000 * np.abs(self.path.get_K()),
|
| 397 | label='K')
|
| 398 | max_v_K_V = plt.plot(self.path.get_S(),
|
| 399 | self.max_velocities_adhering_to_voltage,
|
| 400 | label='ds/dt (voltage)')
|
| 401 | plt.legend(handles=[max_v_normal[0], curvature[0], max_v_K_V[0]])
|
| 402 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 403 |
|
| 404 | def main():
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 405 | A = Hermite_Spline(np.array([0, 0]),
|
| 406 | np.array([0, 400]),
|
| 407 | np.array([200, 300]),
|
| 408 | np.array([200, 200]),
|
| 409 | resolution=200)
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 410 | A.plot_diagnostics()
|
| 411 | path = Path()
|
| 412 | path.add_spline(A)
|
| 413 | trajectory = Trajectory(path, 0)
|
| 414 | trajectory.plot_diagnostics()
|
| 415 | plt.show()
|
| 416 |
|
Ravago Jones | 5127ccc | 2022-07-31 16:32:45 -0700 | [diff] [blame] | 417 |
|
John Park | 1aaadc7 | 2018-11-04 13:13:08 -0800 | [diff] [blame] | 418 | main()
|