4
4
from __future__ import annotations
5
5
6
6
from typing import Callable , Union , Optional , Tuple , overload
7
+ from overtake import overtake
7
8
from wpimath .controller import (
8
9
PIDController ,
9
10
RamseteController ,
@@ -47,44 +48,7 @@ def __init__(
47
48
controller : RamseteController ,
48
49
kinematics : DifferentialDriveKinematics ,
49
50
requirements : Tuple [Subsystem ],
50
- * ,
51
- outputMPS : Callable [[units .meters_per_second , units .meters_per_second ], None ],
52
- ):
53
- ...
54
-
55
- @overload
56
- def __init__ (
57
- self ,
58
- trajectory : Trajectory ,
59
- pose : Callable [[], Pose2d ],
60
- controller : RamseteController ,
61
- kinematics : DifferentialDriveKinematics ,
62
- requirements : Tuple [Subsystem ],
63
- * ,
64
- outputVolts : Callable [[units .volts , units .volts ], None ],
65
- feedforward : SimpleMotorFeedforwardMeters ,
66
- leftController : PIDController ,
67
- rightController : PIDController ,
68
- wheelSpeeds : Callable [[], DifferentialDriveWheelSpeeds ],
69
- ):
70
- ...
71
-
72
- def __init__ (
73
- self ,
74
- trajectory : Trajectory ,
75
- pose : Callable [[], Pose2d ],
76
- controller : RamseteController ,
77
- kinematics : DifferentialDriveKinematics ,
78
- requirements : Tuple [Subsystem ],
79
- * ,
80
- outputMPS : Optional [
81
- Callable [[units .meters_per_second , units .meters_per_second ], None ]
82
- ] = None ,
83
- outputVolts : Optional [Callable [[units .volts , units .volts ], None ]] = None ,
84
- feedforward : Optional [SimpleMotorFeedforwardMeters ] = None ,
85
- leftController : Optional [PIDController ] = None ,
86
- rightController : Optional [PIDController ] = None ,
87
- wheelSpeeds : Optional [Callable [[], DifferentialDriveWheelSpeeds ]] = None ,
51
+ output : Callable [[float , float ], None ],
88
52
):
89
53
"""Constructs a new RamseteCommand that, when executed, will follow the provided trajectory. PID
90
54
control and feedforward are handled internally, and outputs are scaled -12 to 12 representing
@@ -99,17 +63,37 @@ def __init__(
99
63
:param controller: The RAMSETE controller used to follow the trajectory.
100
64
:param kinematics: The kinematics for the robot drivetrain.
101
65
:param requirements: The subsystems to require.
66
+ :param output A function that consumes the computed left and right outputs in `units.meters_per_second`
67
+ """
68
+ super ().__init__ ()
102
69
103
- REQUIRED KEYWORD PARAMETERS
104
- Note: The output mode must be specified by the users of RamseteCommands. Users can specify ONE of
105
- an output function that will supply the consumer with left and right speeds in `units.meters_per_second`
106
- or in `units.volts`. If neither, or both, are supplied to the constructor a `RuntimeError` will be
107
- raised.
108
- :param outputVolts A function that consumes the computed left and right outputs in `units.volts`
109
- :param outputMPS A function that consumes the computed left and right outputs in `units.meters_per_second`
110
-
70
+ self ._timer = Timer ()
71
+ self .trajectory = trajectory
72
+ self .pose = pose
73
+ self .follower = controller
74
+ self .kinematics = kinematics
75
+ self .output = output
76
+ self .usePID = False
77
+ # All the parameter checks pass, inform scheduler. Type ignoring is set explictitly for the linter because this
78
+ # implementation declares the tuple explicitly, whereas the general implementations use the unpack operator (*)
79
+ # to pass the requirements to the scheduler.
80
+ self .addRequirements (requirements ) # type: ignore
111
81
112
- Constructs a new RamseteCommand that, when executed, will follow the provided trajectory. PID
82
+ @overload
83
+ def __init__ (
84
+ self ,
85
+ trajectory : Trajectory ,
86
+ pose : Callable [[], Pose2d ],
87
+ controller : RamseteController ,
88
+ kinematics : DifferentialDriveKinematics ,
89
+ requirements : Tuple [Subsystem ],
90
+ output : Callable [[float , float ], None ],
91
+ feedforward : SimpleMotorFeedforwardMeters ,
92
+ leftController : PIDController ,
93
+ rightController : PIDController ,
94
+ wheelSpeeds : Callable [[], DifferentialDriveWheelSpeeds ],
95
+ ):
96
+ """Constructs a new RamseteCommand that, when executed, will follow the provided trajectory. PID
113
97
control and feedforward are handled internally, and outputs are scaled -12 to 12 representing
114
98
units of volts.
115
99
@@ -122,20 +106,7 @@ def __init__(
122
106
:param controller: The RAMSETE controller used to follow the trajectory.
123
107
:param kinematics: The kinematics for the robot drivetrain.
124
108
:param requirements: The subsystems to require.
125
-
126
- REQUIRED KEYWORD PARAMETERS
127
- Note: The output mode must be specified by the users of RamseteCommands. Users can specify ONE of
128
- an output function that will supply the consumer with left and right speeds in `units.meters_per_second`
129
- or in `units.volts`. If neither, or both, are supplied to the constructor a `RuntimeError` will be
130
- raised.
131
- :param outputVolts A function that consumes the computed left and right outputs in `units.volts`
132
- :param outputMPS A function that consumes the computed left and right outputs in `units.meters_per_second`
133
-
134
- OPTIONAL PARAMETERS
135
- When the following optional parameters are provided, when executed, the RamseteCommand will follow
136
- provided trajectory. PID control and feedforward are handled internally, and the outputs are scaled
137
- from -12 to 12 representing units of volts. If any one of the optional parameters are provided, each
138
- other optional parameter becomes required.
109
+ :param output A function that consumes the computed left and right outputs in `units.volts`
139
110
:param feedforward The feedforward to use for the drive
140
111
:param leftController: The PIDController for the left side of the robot drive.
141
112
:param rightController: The PIDController for the right side of the robot drive.
@@ -151,53 +122,36 @@ def __init__(
151
122
self .pose = pose
152
123
self .follower = controller
153
124
self .kinematics = kinematics
154
- self .outputMPS = outputMPS
155
- self .outputVolts = outputVolts
125
+ self .output = output
156
126
self .leftController = leftController
157
127
self .rightController = rightController
158
128
self .wheelspeeds = wheelSpeeds
159
129
self .feedforward = feedforward
160
130
self ._prevSpeeds = DifferentialDriveWheelSpeeds ()
161
131
self ._prevTime = - 1.0
162
-
163
- # Required requirements check for output
164
- if outputMPS is None and outputVolts is None :
165
- raise RuntimeError (
166
- f"Failed to instantiate RamseteCommand, no output consumer provided. Must provide either output in meters per second or volts."
167
- )
168
-
169
- if outputMPS is not None and outputVolts is not None :
170
- raise RuntimeError (
171
- f"Failed to instantiate RamseteCommand, too many consumers provided. Must provide either output in meters per second or volts but not both."
172
- )
173
-
174
- # Optional requirements checks. If any one of the optional parameters are not None, then all the optional
175
- # requirements become required.
176
- if (
177
- feedforward is not None
178
- or leftController is not None
179
- or rightController is not None
180
- or wheelSpeeds is not None
181
- ):
182
- if (
183
- feedforward is None
184
- or leftController is None
185
- or rightController is None
186
- or wheelSpeeds is None
187
- ):
188
- raise RuntimeError (
189
- f"Failed to instantiate RamseteCommand, not all optional arguments were provided.\n \
190
- Feedforward - { feedforward } , LeftController - { leftController } , RightController - { rightController } , WheelSpeeds - { wheelSpeeds } "
191
- )
192
- self .usePID = True
193
- else :
194
- self .usePID = False
195
-
132
+ self .usePID = True
196
133
# All the parameter checks pass, inform scheduler. Type ignoring is set explictitly for the linter because this
197
134
# implementation declares the tuple explicitly, whereas the general implementations use the unpack operator (*)
198
135
# to pass the requirements to the scheduler.
199
136
self .addRequirements (requirements ) # type: ignore
200
137
138
+ @overtake (runtime_type_checker = "beartype" )
139
+ def __init__ (
140
+ self ,
141
+ * ,
142
+ trajectory : Trajectory ,
143
+ pose : Callable [[], Pose2d ],
144
+ controller : RamseteController ,
145
+ kinematics : DifferentialDriveKinematics ,
146
+ requirements : Tuple [Subsystem ],
147
+ output : Callable [[float , float ], None ],
148
+ feedforward : Optional [SimpleMotorFeedforwardMeters ] = None ,
149
+ leftController : Optional [PIDController ] = None ,
150
+ rightController : Optional [PIDController ] = None ,
151
+ wheelSpeeds : Optional [Callable [[], DifferentialDriveWheelSpeeds ]] = None ,
152
+ ):
153
+ ...
154
+
201
155
def initialize (self ):
202
156
self ._prevTime = - 1
203
157
initial_state = self .trajectory .sample (0 )
@@ -218,10 +172,7 @@ def execute(self):
218
172
dt = curTime - self ._prevTime
219
173
220
174
if self ._prevTime < 0 :
221
- if self .outputVolts is not None :
222
- self .outputVolts (0.0 , 0.0 )
223
- if self .outputMPS is not None :
224
- self .outputMPS (0.0 , 0.0 )
175
+ self .output (0.0 , 0.0 )
225
176
self ._prevTime = curTime
226
177
return
227
178
@@ -249,11 +200,11 @@ def execute(self):
249
200
rightOutput = rightFeedforward + self .rightController .calculate (
250
201
self .wheelspeeds ().right , rightSpeedSetpoint
251
202
)
252
- self .outputVolts (leftOutput , rightOutput )
203
+ self .output (leftOutput , rightOutput )
253
204
else :
254
205
leftOutput = leftSpeedSetpoint
255
206
rightOutput = rightSpeedSetpoint
256
- self .outputMPS (leftOutput , rightOutput )
207
+ self .output (leftOutput , rightOutput )
257
208
258
209
self ._prevSpeeds = targetWheelSpeeds
259
210
self ._prevTime = curTime
@@ -262,10 +213,7 @@ def end(self, interrupted: bool):
262
213
self ._timer .stop ()
263
214
264
215
if interrupted :
265
- if self .outputVolts is not None :
266
- self .outputVolts (0.0 , 0.0 )
267
- if self .outputMPS is not None :
268
- self .outputMPS (0.0 , 0.0 )
216
+ self .output (0.0 , 0.0 )
269
217
270
218
def isFinished (self ):
271
219
return self ._timer .hasElapsed (self .trajectory .totalTime ())
0 commit comments