3
3
# the WPILib BSD license file in the root directory of this project.
4
4
from __future__ import annotations
5
5
6
- from typing import Callable , Union , Optional
6
+ from typing import Callable , Union , Optional , Tuple , overload
7
7
from wpimath .controller import (
8
8
PIDController ,
9
9
RamseteController ,
16
16
DifferentialDriveWheelSpeeds ,
17
17
)
18
18
from wpimath .trajectory import Trajectory
19
+ from wpimath import units as units
19
20
from wpiutil import SendableBuilder
20
21
from wpilib import Timer
21
22
@@ -36,18 +37,35 @@ class RamseteCommand(Command):
36
37
Advanced teams seeking more flexibility (for example, those who wish to use the onboard PID
37
38
functionality of a "smart" motor controller) may use the secondary constructor that omits the PID
38
39
and feedforward functionality, returning only the raw wheel speeds from the RAMSETE controller.
39
-
40
- This class is provided by the NewCommands VendorDep
41
40
"""
42
41
42
+ @overload
43
+ def __init__ (
44
+ self ,
45
+ trajectory : Trajectory ,
46
+ pose : Callable [[], Pose2d ],
47
+ controller : RamseteController ,
48
+ kinematics : DifferentialDriveKinematics ,
49
+ requirements : Tuple [Subsystem ],
50
+ * ,
51
+ outputMPS : Optional [
52
+ Callable [[units .meters_per_second , units .meters_per_second ], None ]
53
+ ],
54
+ ):
55
+ ...
56
+
43
57
def __init__ (
44
58
self ,
45
59
trajectory : Trajectory ,
46
60
pose : Callable [[], Pose2d ],
47
61
controller : RamseteController ,
48
62
kinematics : DifferentialDriveKinematics ,
49
- outputVolts : Callable [[float , float ], None ],
50
- * requirements : Subsystem ,
63
+ requirements : Tuple [Subsystem ],
64
+ * ,
65
+ outputVolts : Optional [Callable [[units .volts , units .volts ], None ]] = None ,
66
+ outputMPS : Optional [
67
+ Callable [[units .meters_per_second , units .meters_per_second ], None ]
68
+ ] = None ,
51
69
feedforward : Optional [SimpleMotorFeedforwardMeters ] = None ,
52
70
leftController : Optional [PIDController ] = None ,
53
71
rightController : Optional [PIDController ] = None ,
@@ -65,10 +83,39 @@ def __init__(
65
83
provide this.
66
84
:param controller: The RAMSETE controller used to follow the trajectory.
67
85
:param kinematics: The kinematics for the robot drivetrain.
68
- :param outputVolts: A function that consumes the computed left and right outputs (in volts) for
69
- the robot drive.
70
86
:param requirements: The subsystems to require.
71
87
88
+ REQUIRED KEYWORD PARAMETERS
89
+ Note: The output mode must be specified by the users of RamseteCommands. Users can specify ONE of
90
+ an output function that will supply the consumer with left and right speeds in `units.meters_per_second`
91
+ or in `units.volts`. If neither, or both, are supplied to the constructor a `RuntimeError` will be
92
+ raised.
93
+ :param outputVolts A function that consumes the computed left and right outputs in `units.volts`
94
+ :param outputMPS A function that consumes the computed left and right outputs in `units.meters_per_second`
95
+
96
+
97
+ Constructs a new RamseteCommand that, when executed, will follow the provided trajectory. PID
98
+ control and feedforward are handled internally, and outputs are scaled -12 to 12 representing
99
+ units of volts.
100
+
101
+ Note: The controller will *not* set the outputVolts to zero upon completion of the path -
102
+ this is left to the user, since it is not appropriate for paths with nonstationary endstates.
103
+
104
+ :param trajectory: The trajectory to follow.
105
+ :param pose: A function that supplies the robot pose - use one of the odometry classes to
106
+ provide this.
107
+ :param controller: The RAMSETE controller used to follow the trajectory.
108
+ :param kinematics: The kinematics for the robot drivetrain.
109
+ :param requirements: The subsystems to require.
110
+
111
+ REQUIRED KEYWORD PARAMETERS
112
+ Note: The output mode must be specified by the users of RamseteCommands. Users can specify ONE of
113
+ an output function that will supply the consumer with left and right speeds in `units.meters_per_second`
114
+ or in `units.volts`. If neither, or both, are supplied to the constructor a `RuntimeError` will be
115
+ raised.
116
+ :param outputVolts A function that consumes the computed left and right outputs in `units.volts`
117
+ :param outputMPS A function that consumes the computed left and right outputs in `units.meters_per_second`
118
+
72
119
OPTIONAL PARAMETERS
73
120
When the following optional parameters are provided, when executed, the RamseteCommand will follow
74
121
provided trajectory. PID control and feedforward are handled internally, and the outputs are scaled
@@ -89,12 +136,38 @@ def __init__(
89
136
self .pose = pose
90
137
self .follower = controller
91
138
self .kinematics = kinematics
92
- self .output = outputVolts
93
- self .usePID = False
139
+
140
+ # Required requirements check for output
141
+ if outputMPS is None and outputVolts is None :
142
+ raise RuntimeError (
143
+ f"Failed to instantiate RamseteCommand, no output consumer provided. Must provide either output in meters per second or volts."
144
+ )
145
+
146
+ if outputMPS is not None and outputVolts is not None :
147
+ raise RuntimeError (
148
+ f"Failed to instantiate RamseteCommand, too many consumers provided. Must provide either output in meters per second or volts but not both."
149
+ )
150
+
151
+ # If the above check fails, then one of them is not None. Take the one supplied and assign it for output.
152
+ if outputMPS is not None :
153
+ self .output = outputMPS
154
+ else :
155
+ self .output = outputVolts
156
+
94
157
# Optional requirements checks. If any one of the optional parameters are not None, then all the optional
95
158
# requirements become required.
96
- if feedforward or leftController or rightController or wheelSpeeds is not None :
97
- if feedforward or leftController or rightController or wheelSpeeds is None :
159
+ if (
160
+ feedforward is not None
161
+ or leftController is not None
162
+ or rightController is not None
163
+ or wheelSpeeds is not None
164
+ ):
165
+ if (
166
+ feedforward is None
167
+ or leftController is None
168
+ or rightController is None
169
+ or wheelSpeeds is None
170
+ ):
98
171
raise RuntimeError (
99
172
f"Failed to instantiate RamseteCommand, not all optional arguments were provided.\n \
100
173
Feedforward - { feedforward } , LeftController - { leftController } , RightController - { rightController } , WheelSpeeds - { wheelSpeeds } "
@@ -105,10 +178,12 @@ def __init__(
105
178
self .wheelspeeds = wheelSpeeds
106
179
self .feedforward = feedforward
107
180
self .usePID = True
181
+ else :
182
+ self .usePID = False
108
183
self ._prevSpeeds = DifferentialDriveWheelSpeeds ()
109
184
self ._prevTime = - 1.0
110
185
111
- self .addRequirements (* requirements )
186
+ self .addRequirements (requirements )
112
187
113
188
def initialize (self ):
114
189
self ._prevTime = - 1
@@ -158,11 +233,12 @@ def execute(self):
158
233
rightOutput = rightFeedforward + self .rightController .calculate (
159
234
self .wheelspeeds ().right , rightSpeedSetpoint
160
235
)
236
+ self .output (leftOutput , rightOutput )
161
237
else :
162
238
leftOutput = leftSpeedSetpoint
163
239
rightOutput = rightSpeedSetpoint
240
+ self .output (leftOutput , rightOutput )
164
241
165
- self .output (leftOutput , rightOutput )
166
242
self ._prevSpeeds = targetWheelSpeeds
167
243
self ._prevTime = curTime
168
244
0 commit comments