blob: 5aded23481b7e78253ed067d7966d60e26abebf4 [file] [log] [blame]
Austin Schuh085eab92020-11-26 13:54:51 -08001#!/usr/bin/python3
Alex Perry20762632019-01-21 17:48:02 -05002"""Wrapper around spline.h/cc through spline_array.cc."""
3
4__author__ = 'Alex Perry (alex.perry96@gmail.com)'
5
6import ctypes as ct
7import numpy as np
8import os
9
10libSpline = None
11for path in os.environ.get('PYTHONPATH').split(':'):
12 try:
Alex Perrya60da442019-01-21 19:00:27 -050013 libSpline = ct.cdll.LoadLibrary(
14 os.path.join(path, 'frc971/control_loops/drivetrain/spline.so'))
Andrew Runke6842bf92019-01-26 15:38:25 -080015 except (OSError):
Alex Perry20762632019-01-21 17:48:02 -050016 pass
17
18# Define required output types.
James Kuszmaul77253872019-12-28 11:59:57 -080019libSpline.NewSpline.restype = ct.c_void_p
Alex Perrya60da442019-01-21 19:00:27 -050020libSpline.SplineTheta.restype = ct.c_double
21libSpline.SplineDTheta.restype = ct.c_double
22libSpline.SplineDDTheta.restype = ct.c_double
James Kuszmaul77253872019-12-28 11:59:57 -080023libSpline.NewDistanceSpline.restype = ct.c_void_p
Alex Perrya60da442019-01-21 19:00:27 -050024libSpline.DistanceSplineTheta.restype = ct.c_double
25libSpline.DistanceSplineDTheta.restype = ct.c_double
26libSpline.DistanceSplineDThetaDt.restype = ct.c_double
27libSpline.DistanceSplineDDTheta.restype = ct.c_double
28libSpline.DistanceSplineLength.restype = ct.c_double
James Kuszmaul77253872019-12-28 11:59:57 -080029libSpline.NewTrajectory.restype = ct.c_void_p
Alex Perry0603b542019-01-25 20:29:51 -080030libSpline.TrajectoryLength.restype = ct.c_double
James Kuszmaul77253872019-12-28 11:59:57 -080031libSpline.TrajectoryDistance.restype = ct.c_double
32libSpline.TrajectoryGetPlanXVAPtr.restype = ct.c_void_p
Alex Perrya60da442019-01-21 19:00:27 -050033
Alex Perry0603b542019-01-25 20:29:51 -080034# Required for trajectory
35libSpline.SetUpLogging()
Alex Perry20762632019-01-21 17:48:02 -050036
Ravago Jones26f7ad02021-02-05 15:45:59 -080037
Alex Perry20762632019-01-21 17:48:02 -050038class Spline:
Alex Perry0603b542019-01-25 20:29:51 -080039 """
40 A wrapper around spline.h/cc through libspline.cc.
41 The functions return values parameterized by alpha, a number that varies
42 between 0 and 1 along the length of the spline.
43 """
Alex Perry20762632019-01-21 17:48:02 -050044
Alex Perrya60da442019-01-21 19:00:27 -050045 def __init__(self, points):
46 assert points.shape == (2, 6)
47 self.__points = points
Ravago Jones26f7ad02021-02-05 15:45:59 -080048 self.__spline = ct.c_void_p(
Ravago Jones5127ccc2022-07-31 16:32:45 -070049 libSpline.NewSpline(np.ctypeslib.as_ctypes(self.__points[0]),
50 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050051
52 def __del__(self):
53 libSpline.deleteSpline(self.__spline)
54
55 def setPoint(self, index, x, y):
56 self.__points[0, index] = x
57 self.__points[1, index] = y
58 libSpline.deleteSpline(self.__spline)
Ravago Jones26f7ad02021-02-05 15:45:59 -080059 self.__spline = ct.c_void_p(
Ravago Jones5127ccc2022-07-31 16:32:45 -070060 libSpline.newSpline(np.ctypeslib.as_ctypes(self.__points[0]),
61 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050062
63 def Point(self, alpha):
64 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050065 libSpline.SplinePoint(self.__spline, ct.c_double(alpha),
66 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050067 return result
68
69 def DPoint(self, alpha):
70 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050071 libSpline.SplineDPoint(self.__spline, ct.c_double(alpha),
72 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050073 return result
74
75 def DDPoint(self, alpha):
76 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050077 libSpline.SplineDDPoint(self.__spline, ct.c_double(alpha),
78 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050079 return result
80
81 def DDDPoint(self, alpha):
82 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050083 libSpline.SplineDDDPoint(self.__spline, ct.c_double(alpha),
84 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050085 return result
86
87 def Theta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050088 return libSpline.SplineTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050089
90 def DTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050091 return libSpline.SplineDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050092
93 def DDTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050094 return libSpline.SplineDDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050095
96 def ControlPoints(self):
Alex Perrya60da442019-01-21 19:00:27 -050097 return self.__points
98
Alex Perry0603b542019-01-25 20:29:51 -080099 def GetSplinePtr(self):
Alex Perrya60da442019-01-21 19:00:27 -0500100 return self.__spline
101
102
103class DistanceSpline:
Alex Perry0603b542019-01-25 20:29:51 -0800104 """
105 A wrapper around distance_spline.h/cc through libspline.cc.
106 The functions return values parameterized by the distance along the spline,
107 starting at 0 and and ending at the value returned by Length().
108 """
Alex Perrya60da442019-01-21 19:00:27 -0500109
110 def __init__(self, splines):
111 self.__spline = None
112 spline_ptrs = []
113 for spline in splines:
James Kuszmaul77253872019-12-28 11:59:57 -0800114 spline_ptrs.append(spline.GetSplinePtr().value)
Alex Perrya60da442019-01-21 19:00:27 -0500115 spline_ptrs = np.array(spline_ptrs)
116
117 spline_array = np.ctypeslib.as_ctypes(spline_ptrs)
Ravago Jones26f7ad02021-02-05 15:45:59 -0800118 self.__spline = ct.c_void_p(
119 libSpline.NewDistanceSpline(ct.byref(spline_array), len(splines)))
Alex Perrya60da442019-01-21 19:00:27 -0500120
121 def __del__(self):
122 libSpline.deleteDistanceSpline(self.__spline)
123
124 def XY(self, distance):
125 result = np.zeros(2)
126 libSpline.DistanceSplineXY(self.__spline, ct.c_double(distance),
127 np.ctypeslib.as_ctypes(result))
128 return result
129
130 def DXY(self, distance):
131 result = np.zeros(2)
132 libSpline.DistanceSplineDXY(self.__spline, ct.c_double(distance),
133 np.ctypeslib.as_ctypes(result))
134 return result
135
136 def DDXY(self, distance):
137 result = np.zeros(2)
138 libSpline.DistanceSplineDDXY(self.__spline, ct.c_double(distance),
139 np.ctypeslib.as_ctypes(result))
140 return result
141
142 def Theta(self, distance):
143 return libSpline.DistanceSplineTheta(self.__spline,
144 ct.c_double(distance))
145
146 def DTheta(self, distance):
147 return libSpline.DistanceSplineDTheta(self.__spline,
148 ct.c_double(distance))
149
150 def DThetaDt(self, distance, velocity):
151 return libSpline.DistanceSplineDThetaDt(self.__spline,
152 ct.c_double(distance),
153 ct.c_double(velocity))
154
155 def DDTheta(self, distance):
156 return libSpline.DistanceSplineDDTheta(self.__spline,
157 ct.c_double(distance))
158
159 def Length(self):
160 return libSpline.DistanceSplineLength(self.__spline)
Alex Perry0603b542019-01-25 20:29:51 -0800161
162 def GetSplinePtr(self):
163 return self.__spline
164
165
166class Trajectory:
167 """A wrapper around trajectory.h/cc through libspline.cc."""
168
169 def __init__(self, distance_spline, vmax=10, num_distance=0):
Ravago Jones26f7ad02021-02-05 15:45:59 -0800170 self.__trajectory = ct.c_void_p(
171 libSpline.NewTrajectory(distance_spline.GetSplinePtr(),
172 ct.c_double(vmax), num_distance))
Alex Perry0603b542019-01-25 20:29:51 -0800173
174 def __del__(self):
175 libSpline.deleteTrajectory(self.__trajectory)
176
Ravago Jones3b92afa2021-02-05 14:27:32 -0800177 def SetLongitudinalAcceleration(self, accel):
178 libSpline.TrajectorySetLongitudinalAcceleration(
179 self.__trajectory, ct.c_double(accel))
Alex Perry0603b542019-01-25 20:29:51 -0800180
181 def SetLateralAcceleration(self, accel):
182 libSpline.TrajectorySetLateralAcceleration(self.__trajectory,
183 ct.c_double(accel))
184
185 def SetVoltageLimit(self, limit):
186 libSpline.TrajectorySetVoltageLimit(self.__trajectory,
187 ct.c_double(limit))
188
189 def LimitVelocity(self, start_distance, end_distance, max_vel):
190 libSpline.TrajectoryLimitVelocity(self.__trajectory,
191 ct.c_double(start_distance),
192 ct.c_double(end_distance),
193 ct.c_double(max_vel))
194
195 def Plan(self):
196 """
197 Call this to compute the plan, if any of the limits change, a new plan
198 must be generated.
199 """
200 libSpline.TrajectoryPlan(self.__trajectory)
201
Alex Perry50baefc2019-01-27 13:26:29 -0800202 def Voltage(self, distance):
203 """
204 Returns a pair of voltages for a given distance.
205 Order is left-right.
206 """
207 result = np.zeros(2)
208 libSpline.TrajectoryVoltage(self.__trajectory, ct.c_double(distance),
209 np.ctypeslib.as_ctypes(result))
210 return result
211
Alex Perry0603b542019-01-25 20:29:51 -0800212 def Length(self):
213 return libSpline.TrajectoryLength(self.__trajectory)
214
215 def Distance(self, index):
216 return libSpline.TrajectoryDistance(self.__trajectory, index)
217
218 def Distances(self):
219 """
220 Returns an array of distances used to compute the plan. The linear
221 distance between each distance is equal.
222 """
223 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
224 distances = numpy.zeros(path_length)
225 libSpline.TrajectoryDistances(self.__trajectory,
226 np.ctypeslib.as_ctypes(distances))
227 return distances
228
229 def GetPlan(self):
230 """
231 Returns the plan as an array of velocities matched to each distance
232 from Distances.
233 """
234 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
235 velocities = numpy.zeros(path_length)
236 libSpline.TrajectoryGetPlan(self.__trajectory,
237 np.ctypeslib.as_ctypes(velocities))
238 return velocities
239
240 def GetPlanXVA(self, dt):
241 """
242 dt is in seconds
243 Returns the position, velocity, and acceleration as a function of time.
244 This is returned as a 3xN numpy array where N is proportional to how
245 long it takes to run the path.
246 This is slow so don't call more than once with the same data.
247 """
Ravago Jones26f7ad02021-02-05 15:45:59 -0800248 XVAPtr = ct.c_void_p(
249 libSpline.TrajectoryGetPlanXVAPtr(self.__trajectory,
250 int(dt * 1e9)))
Alex Perry0603b542019-01-25 20:29:51 -0800251 XVALength = libSpline.TrajectoryGetVectorLength(XVAPtr)
James Kuszmaulc3eaa472021-03-03 19:43:45 -0800252 if XVALength == 0:
253 libSpline.TrajectoryDeleteVector(XVAPtr)
254 return None
Alex Perry0603b542019-01-25 20:29:51 -0800255 X = np.zeros(XVALength)
256 V = np.zeros(XVALength)
257 A = np.zeros(XVALength)
258 libSpline.TrajectoryGetPlanXVA(XVAPtr, np.ctypeslib.as_ctypes(X),
259 np.ctypeslib.as_ctypes(V),
260 np.ctypeslib.as_ctypes(A))
261 libSpline.TrajectoryDeleteVector(XVAPtr)
262 return np.vstack([X, V, A])