blob: 7a7763797cbd11afd5fd9e04a644ff9df5a2e98d [file] [log] [blame]
Alex Perry20762632019-01-21 17:48:02 -05001#!/usr/bin/python
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'))
Alex Perry20762632019-01-21 17:48:02 -050015 except OSError, e:
16 pass
17
18# Define required output types.
Alex Perrya60da442019-01-21 19:00:27 -050019libSpline.SplineTheta.restype = ct.c_double
20libSpline.SplineDTheta.restype = ct.c_double
21libSpline.SplineDDTheta.restype = ct.c_double
22libSpline.DistanceSplineTheta.restype = ct.c_double
23libSpline.DistanceSplineDTheta.restype = ct.c_double
24libSpline.DistanceSplineDThetaDt.restype = ct.c_double
25libSpline.DistanceSplineDDTheta.restype = ct.c_double
26libSpline.DistanceSplineLength.restype = ct.c_double
Alex Perry0603b542019-01-25 20:29:51 -080027libSpline.TrajectoryLength.restype = ct.c_double
28libSpline.TrajectoryDistance.resType = ct.c_double
Alex Perrya60da442019-01-21 19:00:27 -050029
Alex Perry0603b542019-01-25 20:29:51 -080030# Required for trajectory
31libSpline.SetUpLogging()
Alex Perry20762632019-01-21 17:48:02 -050032
33class Spline:
Alex Perry0603b542019-01-25 20:29:51 -080034 """
35 A wrapper around spline.h/cc through libspline.cc.
36 The functions return values parameterized by alpha, a number that varies
37 between 0 and 1 along the length of the spline.
38 """
Alex Perry20762632019-01-21 17:48:02 -050039
Alex Perrya60da442019-01-21 19:00:27 -050040 def __init__(self, points):
41 assert points.shape == (2, 6)
42 self.__points = points
43 self.__spline = libSpline.NewSpline(
44 np.ctypeslib.as_ctypes(self.__points[0]),
45 np.ctypeslib.as_ctypes(self.__points[1]))
Alex Perry20762632019-01-21 17:48:02 -050046
47 def __del__(self):
48 libSpline.deleteSpline(self.__spline)
49
50 def setPoint(self, index, x, y):
51 self.__points[0, index] = x
52 self.__points[1, index] = y
53 libSpline.deleteSpline(self.__spline)
Alex Perrya60da442019-01-21 19:00:27 -050054 self.__spline = libSpline.newSpline(
55 np.ctypeslib.as_ctypes(self.__points[0]),
56 np.ctypeslib.as_ctypes(self.__points[1]))
Alex Perry20762632019-01-21 17:48:02 -050057
58 def Point(self, alpha):
59 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050060 libSpline.SplinePoint(self.__spline, ct.c_double(alpha),
61 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050062 return result
63
64 def DPoint(self, alpha):
65 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050066 libSpline.SplineDPoint(self.__spline, ct.c_double(alpha),
67 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050068 return result
69
70 def DDPoint(self, alpha):
71 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050072 libSpline.SplineDDPoint(self.__spline, ct.c_double(alpha),
73 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050074 return result
75
76 def DDDPoint(self, alpha):
77 result = np.zeros(2)
Alex Perrya60da442019-01-21 19:00:27 -050078 libSpline.SplineDDDPoint(self.__spline, ct.c_double(alpha),
79 np.ctypeslib.as_ctypes(result))
Alex Perry20762632019-01-21 17:48:02 -050080 return result
81
82 def Theta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050083 return libSpline.SplineTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050084
85 def DTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050086 return libSpline.SplineDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050087
88 def DDTheta(self, alpha):
Alex Perrya60da442019-01-21 19:00:27 -050089 return libSpline.SplineDDTheta(self.__spline, ct.c_double(alpha))
Alex Perry20762632019-01-21 17:48:02 -050090
91 def ControlPoints(self):
Alex Perrya60da442019-01-21 19:00:27 -050092 return self.__points
93
Alex Perry0603b542019-01-25 20:29:51 -080094 def GetSplinePtr(self):
Alex Perrya60da442019-01-21 19:00:27 -050095 return self.__spline
96
97
98class DistanceSpline:
Alex Perry0603b542019-01-25 20:29:51 -080099 """
100 A wrapper around distance_spline.h/cc through libspline.cc.
101 The functions return values parameterized by the distance along the spline,
102 starting at 0 and and ending at the value returned by Length().
103 """
Alex Perrya60da442019-01-21 19:00:27 -0500104
105 def __init__(self, splines):
106 self.__spline = None
107 spline_ptrs = []
108 for spline in splines:
Alex Perry0603b542019-01-25 20:29:51 -0800109 spline_ptrs.append(spline.GetSplinePtr())
Alex Perrya60da442019-01-21 19:00:27 -0500110 spline_ptrs = np.array(spline_ptrs)
111
112 spline_array = np.ctypeslib.as_ctypes(spline_ptrs)
113 self.__spline = libSpline.NewDistanceSpline(
114 ct.byref(spline_array), len(splines))
115
116 def __del__(self):
117 libSpline.deleteDistanceSpline(self.__spline)
118
119 def XY(self, distance):
120 result = np.zeros(2)
121 libSpline.DistanceSplineXY(self.__spline, ct.c_double(distance),
122 np.ctypeslib.as_ctypes(result))
123 return result
124
125 def DXY(self, distance):
126 result = np.zeros(2)
127 libSpline.DistanceSplineDXY(self.__spline, ct.c_double(distance),
128 np.ctypeslib.as_ctypes(result))
129 return result
130
131 def DDXY(self, distance):
132 result = np.zeros(2)
133 libSpline.DistanceSplineDDXY(self.__spline, ct.c_double(distance),
134 np.ctypeslib.as_ctypes(result))
135 return result
136
137 def Theta(self, distance):
138 return libSpline.DistanceSplineTheta(self.__spline,
139 ct.c_double(distance))
140
141 def DTheta(self, distance):
142 return libSpline.DistanceSplineDTheta(self.__spline,
143 ct.c_double(distance))
144
145 def DThetaDt(self, distance, velocity):
146 return libSpline.DistanceSplineDThetaDt(self.__spline,
147 ct.c_double(distance),
148 ct.c_double(velocity))
149
150 def DDTheta(self, distance):
151 return libSpline.DistanceSplineDDTheta(self.__spline,
152 ct.c_double(distance))
153
154 def Length(self):
155 return libSpline.DistanceSplineLength(self.__spline)
Alex Perry0603b542019-01-25 20:29:51 -0800156
157 def GetSplinePtr(self):
158 return self.__spline
159
160
161class Trajectory:
162 """A wrapper around trajectory.h/cc through libspline.cc."""
163
164 def __init__(self, distance_spline, vmax=10, num_distance=0):
165 self.__trajectory = libSpline.NewTrajectory(
166 distance_spline.GetSplinePtr(), ct.c_double(vmax), num_distance)
167
168 def __del__(self):
169 libSpline.deleteTrajectory(self.__trajectory)
170
171 def SetLongitudalAcceleration(self, accel):
172 libSpline.TrajectorySetLongitualAcceleration(self.__trajectory,
173 ct.c_double(accel))
174
175 def SetLateralAcceleration(self, accel):
176 libSpline.TrajectorySetLateralAcceleration(self.__trajectory,
177 ct.c_double(accel))
178
179 def SetVoltageLimit(self, limit):
180 libSpline.TrajectorySetVoltageLimit(self.__trajectory,
181 ct.c_double(limit))
182
183 def LimitVelocity(self, start_distance, end_distance, max_vel):
184 libSpline.TrajectoryLimitVelocity(self.__trajectory,
185 ct.c_double(start_distance),
186 ct.c_double(end_distance),
187 ct.c_double(max_vel))
188
189 def Plan(self):
190 """
191 Call this to compute the plan, if any of the limits change, a new plan
192 must be generated.
193 """
194 libSpline.TrajectoryPlan(self.__trajectory)
195
Alex Perry50baefc2019-01-27 13:26:29 -0800196 def Voltage(self, distance):
197 """
198 Returns a pair of voltages for a given distance.
199 Order is left-right.
200 """
201 result = np.zeros(2)
202 libSpline.TrajectoryVoltage(self.__trajectory, ct.c_double(distance),
203 np.ctypeslib.as_ctypes(result))
204 return result
205
Alex Perry0603b542019-01-25 20:29:51 -0800206 def Length(self):
207 return libSpline.TrajectoryLength(self.__trajectory)
208
209 def Distance(self, index):
210 return libSpline.TrajectoryDistance(self.__trajectory, index)
211
212 def Distances(self):
213 """
214 Returns an array of distances used to compute the plan. The linear
215 distance between each distance is equal.
216 """
217 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
218 distances = numpy.zeros(path_length)
219 libSpline.TrajectoryDistances(self.__trajectory,
220 np.ctypeslib.as_ctypes(distances))
221 return distances
222
223 def GetPlan(self):
224 """
225 Returns the plan as an array of velocities matched to each distance
226 from Distances.
227 """
228 path_length = libSpline.TrajectoryGetPathLength(self.__trajectory)
229 velocities = numpy.zeros(path_length)
230 libSpline.TrajectoryGetPlan(self.__trajectory,
231 np.ctypeslib.as_ctypes(velocities))
232 return velocities
233
234 def GetPlanXVA(self, dt):
235 """
236 dt is in seconds
237 Returns the position, velocity, and acceleration as a function of time.
238 This is returned as a 3xN numpy array where N is proportional to how
239 long it takes to run the path.
240 This is slow so don't call more than once with the same data.
241 """
242 XVAPtr = libSpline.TrajectoryGetPlanXVAPtr(self.__trajectory, int(dt*1e9))
243 XVALength = libSpline.TrajectoryGetVectorLength(XVAPtr)
244 X = np.zeros(XVALength)
245 V = np.zeros(XVALength)
246 A = np.zeros(XVALength)
247 libSpline.TrajectoryGetPlanXVA(XVAPtr, np.ctypeslib.as_ctypes(X),
248 np.ctypeslib.as_ctypes(V),
249 np.ctypeslib.as_ctypes(A))
250 libSpline.TrajectoryDeleteVector(XVAPtr)
251 return np.vstack([X, V, A])