blob: 9ba6f4f122fb87c23e71aa246452e22b9450f297 [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(
49 libSpline.NewSpline(
50 np.ctypeslib.as_ctypes(self.__points[0]),
51 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050052
53 def __del__(self):
54 libSpline.deleteSpline(self.__spline)
55
56 def setPoint(self, index, x, y):
57 self.__points[0, index] = x
58 self.__points[1, index] = y
59 libSpline.deleteSpline(self.__spline)
Ravago Jones26f7ad02021-02-05 15:45:59 -080060 self.__spline = ct.c_void_p(
61 libSpline.newSpline(
62 np.ctypeslib.as_ctypes(self.__points[0]),
63 np.ctypeslib.as_ctypes(self.__points[1])))
Alex Perry20762632019-01-21 17:48:02 -050064
65 def Point(self, alpha):
66 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050067 libSpline.SplinePoint(self.__spline, ct.c_double(alpha),
68 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050069 return result
70
71 def DPoint(self, alpha):
72 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050073 libSpline.SplineDPoint(self.__spline, ct.c_double(alpha),
74 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050075 return result
76
77 def DDPoint(self, alpha):
78 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050079 libSpline.SplineDDPoint(self.__spline, ct.c_double(alpha),
80 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050081 return result
82
83 def DDDPoint(self, alpha):
84 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050085 libSpline.SplineDDDPoint(self.__spline, ct.c_double(alpha),
86 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050087 return result
88
89 def Theta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050090 return libSpline.SplineTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050091
92 def DTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050093 return libSpline.SplineDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050094
95 def DDTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050096 return libSpline.SplineDDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050097
98 def ControlPoints(self):
Alex Perrya60da442019-01-21 19:00:27 -050099 return self.__points
100
Alex Perry0603b542019-01-25 20:29:51 -0800101 def GetSplinePtr(self):
Alex Perrya60da442019-01-21 19:00:27 -0500102 return self.__spline
103
104
105class DistanceSpline:
Alex Perry0603b542019-01-25 20:29:51 -0800106 """
107 A wrapper around distance_spline.h/cc through libspline.cc.
108 The functions return values parameterized by the distance along the spline,
109 starting at 0 and and ending at the value returned by Length().
110 """
Alex Perrya60da442019-01-21 19:00:27 -0500111
112 def __init__(self, splines):
113 self.__spline = None
114 spline_ptrs = []
115 for spline in splines:
James Kuszmaul77253872019-12-28 11:59:57 -0800116 spline_ptrs.append(spline.GetSplinePtr().value)
Alex Perrya60da442019-01-21 19:00:27 -0500117 spline_ptrs = np.array(spline_ptrs)
118
119 spline_array = np.ctypeslib.as_ctypes(spline_ptrs)
Ravago Jones26f7ad02021-02-05 15:45:59 -0800120 self.__spline = ct.c_void_p(
121 libSpline.NewDistanceSpline(ct.byref(spline_array), len(splines)))
Alex Perrya60da442019-01-21 19:00:27 -0500122
123 def __del__(self):
124 libSpline.deleteDistanceSpline(self.__spline)
125
126 def XY(self, distance):
127 result = np.zeros(2)
128 libSpline.DistanceSplineXY(self.__spline, ct.c_double(distance),
129 np.ctypeslib.as_ctypes(result))
130 return result
131
132 def DXY(self, distance):
133 result = np.zeros(2)
134 libSpline.DistanceSplineDXY(self.__spline, ct.c_double(distance),
135 np.ctypeslib.as_ctypes(result))
136 return result
137
138 def DDXY(self, distance):
139 result = np.zeros(2)
140 libSpline.DistanceSplineDDXY(self.__spline, ct.c_double(distance),
141 np.ctypeslib.as_ctypes(result))
142 return result
143
144 def Theta(self, distance):
145 return libSpline.DistanceSplineTheta(self.__spline,
146 ct.c_double(distance))
147
148 def DTheta(self, distance):
149 return libSpline.DistanceSplineDTheta(self.__spline,
150 ct.c_double(distance))
151
152 def DThetaDt(self, distance, velocity):
153 return libSpline.DistanceSplineDThetaDt(self.__spline,
154 ct.c_double(distance),
155 ct.c_double(velocity))
156
157 def DDTheta(self, distance):
158 return libSpline.DistanceSplineDDTheta(self.__spline,
159 ct.c_double(distance))
160
161 def Length(self):
162 return libSpline.DistanceSplineLength(self.__spline)
Alex Perry0603b542019-01-25 20:29:51 -0800163
164 def GetSplinePtr(self):
165 return self.__spline
166
167
168class Trajectory:
169 """A wrapper around trajectory.h/cc through libspline.cc."""
170
171 def __init__(self, distance_spline, vmax=10, num_distance=0):
Ravago Jones26f7ad02021-02-05 15:45:59 -0800172 self.__trajectory = ct.c_void_p(
173 libSpline.NewTrajectory(distance_spline.GetSplinePtr(),
174 ct.c_double(vmax), num_distance))
Alex Perry0603b542019-01-25 20:29:51 -0800175
176 def __del__(self):
177 libSpline.deleteTrajectory(self.__trajectory)
178
Ravago Jones3b92afa2021-02-05 14:27:32 -0800179 def SetLongitudinalAcceleration(self, accel):
180 libSpline.TrajectorySetLongitudinalAcceleration(
181 self.__trajectory, ct.c_double(accel))
Alex Perry0603b542019-01-25 20:29:51 -0800182
183 def SetLateralAcceleration(self, accel):
184 libSpline.TrajectorySetLateralAcceleration(self.__trajectory,
185 ct.c_double(accel))
186
187 def SetVoltageLimit(self, limit):
188 libSpline.TrajectorySetVoltageLimit(self.__trajectory,
189 ct.c_double(limit))
190
191 def LimitVelocity(self, start_distance, end_distance, max_vel):
192 libSpline.TrajectoryLimitVelocity(self.__trajectory,
193 ct.c_double(start_distance),
194 ct.c_double(end_distance),
195 ct.c_double(max_vel))
196
197 def Plan(self):
198 """
199 Call this to compute the plan, if any of the limits change, a new plan
200 must be generated.
201 """
202 libSpline.TrajectoryPlan(self.__trajectory)
203
Alex Perry50baefc2019-01-27 13:26:29 -0800204 def Voltage(self, distance):
205 """
206 Returns a pair of voltages for a given distance.
207 Order is left-right.
208 """
209 result = np.zeros(2)
210 libSpline.TrajectoryVoltage(self.__trajectory, ct.c_double(distance),
211 np.ctypeslib.as_ctypes(result))
212 return result
213
Alex Perry0603b542019-01-25 20:29:51 -0800214 def Length(self):
215 return libSpline.TrajectoryLength(self.__trajectory)
216
217 def Distance(self, index):
218 return libSpline.TrajectoryDistance(self.__trajectory, index)
219
220 def Distances(self):
221 """
222 Returns an array of distances used to compute the plan. The linear
223 distance between each distance is equal.
224 """
225 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
226 distances = numpy.zeros(path_length)
227 libSpline.TrajectoryDistances(self.__trajectory,
228 np.ctypeslib.as_ctypes(distances))
229 return distances
230
231 def GetPlan(self):
232 """
233 Returns the plan as an array of velocities matched to each distance
234 from Distances.
235 """
236 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
237 velocities = numpy.zeros(path_length)
238 libSpline.TrajectoryGetPlan(self.__trajectory,
239 np.ctypeslib.as_ctypes(velocities))
240 return velocities
241
242 def GetPlanXVA(self, dt):
243 """
244 dt is in seconds
245 Returns the position, velocity, and acceleration as a function of time.
246 This is returned as a 3xN numpy array where N is proportional to how
247 long it takes to run the path.
248 This is slow so don't call more than once with the same data.
249 """
Ravago Jones26f7ad02021-02-05 15:45:59 -0800250 XVAPtr = ct.c_void_p(
251 libSpline.TrajectoryGetPlanXVAPtr(self.__trajectory,
252 int(dt * 1e9)))
Alex Perry0603b542019-01-25 20:29:51 -0800253 XVALength = libSpline.TrajectoryGetVectorLength(XVAPtr)
James Kuszmaulc3eaa472021-03-03 19:43:45 -0800254 if XVALength == 0:
255 libSpline.TrajectoryDeleteVector(XVAPtr)
256 return None
Alex Perry0603b542019-01-25 20:29:51 -0800257 X = np.zeros(XVALength)
258 V = np.zeros(XVALength)
259 A = np.zeros(XVALength)
260 libSpline.TrajectoryGetPlanXVA(XVAPtr, np.ctypeslib.as_ctypes(X),
261 np.ctypeslib.as_ctypes(V),
262 np.ctypeslib.as_ctypes(A))
263 libSpline.TrajectoryDeleteVector(XVAPtr)
264 return np.vstack([X, V, A])