blob: 24f1f51096041e8faf05584c93e455b1c55cd7c8 [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
37class Spline:
Alex Perry0603b542019-01-25 20:29:51 -080038 """
39 A wrapper around spline.h/cc through libspline.cc.
40 The functions return values parameterized by alpha, a number that varies
41 between 0 and 1 along the length of the spline.
42 """
Alex Perry20762632019-01-21 17:48:02 -050043
Alex Perrya60da442019-01-21 19:00:27 -050044 def __init__(self, points):
45 assert points.shape == (2, 6)
46 self.__points = points
James Kuszmaul77253872019-12-28 11:59:57 -080047 self.__spline = ct.c_void_p(libSpline.NewSpline(
Alex Perrya60da442019-01-21 19:00:27 -050048 np.ctypeslib.as_ctypes(self.__points[0]),
James Kuszmaul77253872019-12-28 11:59:57 -080049 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050050
51 def __del__(self):
52 libSpline.deleteSpline(self.__spline)
53
54 def setPoint(self, index, x, y):
55 self.__points[0, index] = x
56 self.__points[1, index] = y
57 libSpline.deleteSpline(self.__spline)
James Kuszmaul77253872019-12-28 11:59:57 -080058 self.__spline = ct.c_void_p(libSpline.newSpline(
Alex Perrya60da442019-01-21 19:00:27 -050059 np.ctypeslib.as_ctypes(self.__points[0]),
James Kuszmaul77253872019-12-28 11:59:57 -080060 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050061
62 def Point(self, alpha):
63 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050064 libSpline.SplinePoint(self.__spline, ct.c_double(alpha),
65 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050066 return result
67
68 def DPoint(self, alpha):
69 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050070 libSpline.SplineDPoint(self.__spline, ct.c_double(alpha),
71 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050072 return result
73
74 def DDPoint(self, alpha):
75 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050076 libSpline.SplineDDPoint(self.__spline, ct.c_double(alpha),
77 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050078 return result
79
80 def DDDPoint(self, alpha):
81 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050082 libSpline.SplineDDDPoint(self.__spline, ct.c_double(alpha),
83 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050084 return result
85
86 def Theta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050087 return libSpline.SplineTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050088
89 def DTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050090 return libSpline.SplineDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050091
92 def DDTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050093 return libSpline.SplineDDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050094
95 def ControlPoints(self):
Alex Perrya60da442019-01-21 19:00:27 -050096 return self.__points
97
Alex Perry0603b542019-01-25 20:29:51 -080098 def GetSplinePtr(self):
Alex Perrya60da442019-01-21 19:00:27 -050099 return self.__spline
100
101
102class DistanceSpline:
Alex Perry0603b542019-01-25 20:29:51 -0800103 """
104 A wrapper around distance_spline.h/cc through libspline.cc.
105 The functions return values parameterized by the distance along the spline,
106 starting at 0 and and ending at the value returned by Length().
107 """
Alex Perrya60da442019-01-21 19:00:27 -0500108
109 def __init__(self, splines):
110 self.__spline = None
111 spline_ptrs = []
112 for spline in splines:
James Kuszmaul77253872019-12-28 11:59:57 -0800113 spline_ptrs.append(spline.GetSplinePtr().value)
Alex Perrya60da442019-01-21 19:00:27 -0500114 spline_ptrs = np.array(spline_ptrs)
115
116 spline_array = np.ctypeslib.as_ctypes(spline_ptrs)
James Kuszmaul77253872019-12-28 11:59:57 -0800117 self.__spline = ct.c_void_p(libSpline.NewDistanceSpline(
118 ct.byref(spline_array), len(splines)))
Alex Perrya60da442019-01-21 19:00:27 -0500119
120 def __del__(self):
121 libSpline.deleteDistanceSpline(self.__spline)
122
123 def XY(self, distance):
124 result = np.zeros(2)
125 libSpline.DistanceSplineXY(self.__spline, ct.c_double(distance),
126 np.ctypeslib.as_ctypes(result))
127 return result
128
129 def DXY(self, distance):
130 result = np.zeros(2)
131 libSpline.DistanceSplineDXY(self.__spline, ct.c_double(distance),
132 np.ctypeslib.as_ctypes(result))
133 return result
134
135 def DDXY(self, distance):
136 result = np.zeros(2)
137 libSpline.DistanceSplineDDXY(self.__spline, ct.c_double(distance),
138 np.ctypeslib.as_ctypes(result))
139 return result
140
141 def Theta(self, distance):
142 return libSpline.DistanceSplineTheta(self.__spline,
143 ct.c_double(distance))
144
145 def DTheta(self, distance):
146 return libSpline.DistanceSplineDTheta(self.__spline,
147 ct.c_double(distance))
148
149 def DThetaDt(self, distance, velocity):
150 return libSpline.DistanceSplineDThetaDt(self.__spline,
151 ct.c_double(distance),
152 ct.c_double(velocity))
153
154 def DDTheta(self, distance):
155 return libSpline.DistanceSplineDDTheta(self.__spline,
156 ct.c_double(distance))
157
158 def Length(self):
159 return libSpline.DistanceSplineLength(self.__spline)
Alex Perry0603b542019-01-25 20:29:51 -0800160
161 def GetSplinePtr(self):
162 return self.__spline
163
164
165class Trajectory:
166 """A wrapper around trajectory.h/cc through libspline.cc."""
167
168 def __init__(self, distance_spline, vmax=10, num_distance=0):
James Kuszmaul77253872019-12-28 11:59:57 -0800169 self.__trajectory = ct.c_void_p(libSpline.NewTrajectory(
170 distance_spline.GetSplinePtr(), ct.c_double(vmax), num_distance))
Alex Perry0603b542019-01-25 20:29:51 -0800171
172 def __del__(self):
173 libSpline.deleteTrajectory(self.__trajectory)
174
175 def SetLongitudalAcceleration(self, accel):
176 libSpline.TrajectorySetLongitualAcceleration(self.__trajectory,
177 ct.c_double(accel))
178
179 def SetLateralAcceleration(self, accel):
180 libSpline.TrajectorySetLateralAcceleration(self.__trajectory,
181 ct.c_double(accel))
182
183 def SetVoltageLimit(self, limit):
184 libSpline.TrajectorySetVoltageLimit(self.__trajectory,
185 ct.c_double(limit))
186
187 def LimitVelocity(self, start_distance, end_distance, max_vel):
188 libSpline.TrajectoryLimitVelocity(self.__trajectory,
189 ct.c_double(start_distance),
190 ct.c_double(end_distance),
191 ct.c_double(max_vel))
192
193 def Plan(self):
194 """
195 Call this to compute the plan, if any of the limits change, a new plan
196 must be generated.
197 """
198 libSpline.TrajectoryPlan(self.__trajectory)
199
Alex Perry50baefc2019-01-27 13:26:29 -0800200 def Voltage(self, distance):
201 """
202 Returns a pair of voltages for a given distance.
203 Order is left-right.
204 """
205 result = np.zeros(2)
206 libSpline.TrajectoryVoltage(self.__trajectory, ct.c_double(distance),
207 np.ctypeslib.as_ctypes(result))
208 return result
209
Alex Perry0603b542019-01-25 20:29:51 -0800210 def Length(self):
211 return libSpline.TrajectoryLength(self.__trajectory)
212
213 def Distance(self, index):
214 return libSpline.TrajectoryDistance(self.__trajectory, index)
215
216 def Distances(self):
217 """
218 Returns an array of distances used to compute the plan. The linear
219 distance between each distance is equal.
220 """
221 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
222 distances = numpy.zeros(path_length)
223 libSpline.TrajectoryDistances(self.__trajectory,
224 np.ctypeslib.as_ctypes(distances))
225 return distances
226
227 def GetPlan(self):
228 """
229 Returns the plan as an array of velocities matched to each distance
230 from Distances.
231 """
232 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
233 velocities = numpy.zeros(path_length)
234 libSpline.TrajectoryGetPlan(self.__trajectory,
235 np.ctypeslib.as_ctypes(velocities))
236 return velocities
237
238 def GetPlanXVA(self, dt):
239 """
240 dt is in seconds
241 Returns the position, velocity, and acceleration as a function of time.
242 This is returned as a 3xN numpy array where N is proportional to how
243 long it takes to run the path.
244 This is slow so don't call more than once with the same data.
245 """
James Kuszmaul77253872019-12-28 11:59:57 -0800246 XVAPtr = ct.c_void_p(libSpline.TrajectoryGetPlanXVAPtr(self.__trajectory, int(dt*1e9)))
Alex Perry0603b542019-01-25 20:29:51 -0800247 XVALength = libSpline.TrajectoryGetVectorLength(XVAPtr)
248 X = np.zeros(XVALength)
249 V = np.zeros(XVALength)
250 A = np.zeros(XVALength)
251 libSpline.TrajectoryGetPlanXVA(XVAPtr, np.ctypeslib.as_ctypes(X),
252 np.ctypeslib.as_ctypes(V),
253 np.ctypeslib.as_ctypes(A))
254 libSpline.TrajectoryDeleteVector(XVAPtr)
255 return np.vstack([X, V, A])