1 | package org.usfirst.frc.team3695.robot.subsystems; |
||
2 | |||
3 | import com.ctre.phoenix.motorcontrol.ControlMode; |
||
4 | import com.ctre.phoenix.motorcontrol.FeedbackDevice; |
||
5 | import com.ctre.phoenix.motorcontrol.StatusFrameEnhanced; |
||
6 | import com.ctre.phoenix.motorcontrol.can.TalonSRX; |
||
7 | import edu.wpi.first.wpilibj.BuiltInAccelerometer; |
||
8 | import edu.wpi.first.wpilibj.Joystick; |
||
9 | import edu.wpi.first.wpilibj.command.Subsystem; |
||
10 | import edu.wpi.first.wpilibj.interfaces.Accelerometer; |
||
11 | import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; |
||
12 | |||
13 | import org.usfirst.frc.team3695.robot.Constants; |
||
14 | import org.usfirst.frc.team3695.robot.Robot; |
||
15 | import org.usfirst.frc.team3695.robot.commands.ManualCommandDrive; |
||
16 | import org.usfirst.frc.team3695.robot.enumeration.Bot; |
||
17 | import org.usfirst.frc.team3695.robot.enumeration.Drivetrain; |
||
18 | import org.usfirst.frc.team3695.robot.util.Xbox; |
||
19 | |||
20 | /** VROOM VROOM */ |
||
21 | public class SubsystemDrive extends Subsystem { |
||
22 | |||
23 | |||
24 | private static TalonSRX leftMaster; |
||
25 | private static TalonSRX leftSlave; |
||
26 | private static TalonSRX rightMaster; |
||
27 | private static TalonSRX rightSlave; |
||
28 | |||
29 | public Drivetrain drivetrain; |
||
30 | |||
31 | public static boolean reversing; |
||
0 ignored issues
–
show
|
|||
32 | public static boolean docking; |
||
0 ignored issues
–
show
public static fields should always be marked final to prevent them being overwritten in unexpected ways. Consider making
docking final.
![]() |
|||
33 | private static double dockInhibitor; |
||
34 | |||
35 | private Accelerometer accel; |
||
36 | |||
37 | public PID pid; // instantiate innerclass |
||
38 | |||
39 | /* Allowable tolerance to be considered in range when driving a distance, in rotations */ |
||
40 | public static final double DISTANCE_ALLOWABLE_ERROR = SubsystemDrive.in2rot(2.0); |
||
41 | |||
42 | /* runs at robot boot */ |
||
43 | public void initDefaultCommand() { |
||
44 | setDefaultCommand(new ManualCommandDrive()); |
||
45 | } |
||
46 | |||
47 | /* converts left magnetic encoder's magic units to inches */ |
||
48 | public static double leftMag2In(double leftMag) { |
||
49 | return leftMag / 212; |
||
0 ignored issues
–
show
|
|||
50 | } |
||
51 | |||
52 | /* converts right magnetic encoder's magic units to inches */ |
||
53 | public static double rightMag2In(double rightMag) { |
||
54 | return rightMag / 212; |
||
0 ignored issues
–
show
|
|||
55 | } |
||
56 | |||
57 | /* converts left magnetic encoder's magic units to inches */ |
||
58 | public static double leftIn2Mag(double leftMag) { |
||
59 | return leftMag * 212; |
||
0 ignored issues
–
show
|
|||
60 | } |
||
61 | |||
62 | /* converts right magnetic encoder's magic units to inches */ |
||
63 | public static double rightIn2Mag(double rightMag) { |
||
64 | // return rightMag * Constants.RIGHT_MAGIC_PER_INCHES; |
||
65 | return rightMag * 212; |
||
0 ignored issues
–
show
|
|||
66 | } |
||
67 | |||
68 | /* converts RPM to inches per second */ |
||
69 | public static double rpm2ips(double rpm) { |
||
70 | return rpm / 60.0 * Constants.WHEEL_DIAMETER * Math.PI; |
||
0 ignored issues
–
show
|
|||
71 | } |
||
72 | |||
73 | /* converts an inches per second number to RPM */ |
||
74 | public static double ips2rpm(double ips) { |
||
75 | return ips * 60.0 / Constants.WHEEL_DIAMETER / Math.PI; |
||
0 ignored issues
–
show
|
|||
76 | } |
||
77 | |||
78 | /* converts rotations to distance traveled in inches */ |
||
79 | public static double rot2in(double rot) { |
||
80 | return rot * Constants.WHEEL_DIAMETER * Math.PI; |
||
81 | } |
||
82 | |||
83 | /* converts distance traveled in inches to rotations */ |
||
84 | public static double in2rot(double in) { |
||
85 | return in / Constants.WHEEL_DIAMETER / Math.PI; |
||
86 | } |
||
87 | |||
88 | |||
89 | |||
90 | |||
91 | /* apply left motor invert */ |
||
92 | public static final double leftify(double left) { |
||
93 | Boolean invert = Robot.bot == Bot.OOF ? Constants.OOF.LEFT_MOTOR_INVERT : Constants.TEUFELSKIND.LEFT_MOTOR_INVERT; |
||
94 | return left * (invert ? -1.0 : 1.0) * (docking ? dockInhibitor : 1); |
||
95 | } |
||
96 | |||
97 | /* apply right motor invert */ |
||
98 | public static final double rightify(double right) { |
||
99 | Boolean invert = Robot.bot == Bot.OOF ? Constants.OOF.RIGHT_MOTOR_INVERT : Constants.TEUFELSKIND.RIGHT_MOTOR_INVERT; |
||
100 | return right * (invert ? -1.0 : 1.0) * (docking ? dockInhibitor : 1); |
||
101 | } |
||
102 | |||
103 | |||
104 | |||
105 | /** |
||
106 | * gives birth to the talons and instantiates variables (including the Bot enum) |
||
107 | */ |
||
108 | public SubsystemDrive() { |
||
109 | |||
110 | accel = new BuiltInAccelerometer(); |
||
111 | |||
112 | drivetrain = Drivetrain.ROCKET_LEAGUE; |
||
113 | |||
114 | reversing = false; |
||
115 | docking = false; |
||
116 | dockInhibitor = 0.5d; |
||
0 ignored issues
–
show
|
|||
117 | |||
118 | pid = new PID(); |
||
119 | |||
120 | // masters |
||
121 | leftMaster = new TalonSRX(Constants.LEFT_MASTER); |
||
0 ignored issues
–
show
|
|||
122 | leftMaster.configSelectedFeedbackSensor(FeedbackDevice.CTRE_MagEncoder_Relative, Constants.LEFT_PID, Constants.TIMEOUT_PID); |
||
123 | rightMaster = new TalonSRX(Constants.RIGHT_MASTER); |
||
0 ignored issues
–
show
|
|||
124 | rightMaster.configSelectedFeedbackSensor(FeedbackDevice.CTRE_MagEncoder_Relative, Constants.RIGHT_PID, Constants.TIMEOUT_PID); |
||
125 | |||
126 | // slaves |
||
127 | leftSlave = new TalonSRX(Constants.LEFT_SLAVE); |
||
0 ignored issues
–
show
|
|||
128 | leftSlave.follow(leftMaster); |
||
129 | rightSlave = new TalonSRX(Constants.RIGHT_SLAVE); |
||
0 ignored issues
–
show
|
|||
130 | rightSlave.follow(rightMaster); |
||
131 | |||
132 | switch (Robot.bot){ |
||
133 | case TEUFELSKIND: |
||
134 | PID.setPIDF(Constants.TEUFELSKIND.P, Constants.TEUFELSKIND.I, Constants.TEUFELSKIND.D, Constants.TEUFELSKIND.F); |
||
135 | break; |
||
136 | case OOF: |
||
137 | PID.setPIDF(Constants.OOF.P, Constants.OOF.I, Constants.OOF.D, Constants.OOF.F); |
||
138 | break; |
||
139 | } |
||
140 | } |
||
141 | |||
142 | public void setDrivetrain(Drivetrain drivetrain) { |
||
143 | this.drivetrain = drivetrain; |
||
144 | } |
||
145 | |||
146 | public void toggleDocking(double dockInhibitor){ |
||
147 | docking = !docking; |
||
0 ignored issues
–
show
|
|||
148 | this.dockInhibitor = dockInhibitor; |
||
0 ignored issues
–
show
|
|||
149 | } |
||
150 | |||
151 | public void toggleReversing(){ |
||
152 | reversing = !reversing; |
||
0 ignored issues
–
show
|
|||
153 | } |
||
154 | |||
155 | public double getYAngle() { |
||
156 | //http://www.hobbytronics.co.uk/accelerometer-info |
||
157 | //Formula for getting the angle through the accelerometer |
||
158 | //arctan returns in radians so we convert to degrees. |
||
159 | return Math.atan(accel.getY() / Math.sqrt(Math.pow(accel.getX(), 2) + Math.pow(accel.getZ(), 2))) * 180 / Math.PI; |
||
0 ignored issues
–
show
|
|||
160 | } |
||
161 | |||
162 | |||
163 | |||
164 | /** |
||
165 | * simple rocket league drive code (not actually rocket league) |
||
166 | * independent rotation and acceleration |
||
167 | */ |
||
168 | public void driveRLTank(Joystick joy, double ramp, double inhibitor) { |
||
169 | double adder = Xbox.RT(joy) - Xbox.LT(joy); |
||
170 | double left = adder + (Xbox.LEFT_X(joy) / 1.333333); |
||
0 ignored issues
–
show
|
|||
171 | double right = adder - (Xbox.LEFT_X(joy) / 1.333333); |
||
0 ignored issues
–
show
|
|||
172 | left = (left > 1.0 ? 1.0 : (left < -1.0 ? -1.0 : left)); |
||
173 | right = (right > 1.0 ? 1.0 : (right < -1.0 ? -1.0 : right)); |
||
174 | setRamps(ramp); |
||
175 | |||
176 | // if (getYAngle() > Constants.TILT_ANGLE ) { |
||
177 | // leftMaster.set(ControlMode.PercentOutput, -1*Constants.RECOVERY_SPEED); |
||
178 | // rightMaster.set(ControlMode.PercentOutput, -1*Constants.RECOVERY_SPEED); |
||
179 | // } else if (getYAngle() < -1*Constants.TILT_ANGLE){ |
||
180 | // leftMaster.set(ControlMode.PercentOutput, Constants.RECOVERY_SPEED); |
||
181 | // rightMaster.set(ControlMode.PercentOutput, Constants.RECOVERY_SPEED); |
||
182 | // } else { |
||
183 | leftMaster.set(ControlMode.PercentOutput, leftify(left)); |
||
184 | rightMaster.set(ControlMode.PercentOutput, rightify(right)); |
||
185 | // } |
||
186 | } |
||
187 | |||
188 | /** |
||
189 | * drive code where rotation is dependent on acceleration |
||
190 | * @param radius 0.00-1.00, 1 being zero radius and 0 being driving in a line |
||
191 | */ |
||
192 | public void driveForza(Joystick joy, double ramp, double radius, double inhibitor) { |
||
193 | double left = 0, |
||
194 | right = 0; |
||
0 ignored issues
–
show
|
|||
195 | double acceleration = Xbox.RT(joy) - Xbox.LT(joy); |
||
196 | |||
197 | setRamps(ramp); |
||
198 | // if (getYAngle() > Constants.TILT_ANGLE ) { |
||
199 | // leftMaster.set(ControlMode.PercentOutput, -1 * Constants.RECOVERY_SPEED); |
||
200 | // rightMaster.set(ControlMode.PercentOutput, -1 * Constants.RECOVERY_SPEED); |
||
201 | // } else if (getYAngle() < -1 * Constants.TILT_ANGLE){ |
||
202 | // leftMaster.set(ControlMode.PercentOutput, Constants.RECOVERY_SPEED); |
||
203 | // rightMaster.set(ControlMode.PercentOutput, Constants.RECOVERY_SPEED); |
||
204 | // } else { |
||
205 | |||
206 | if (!reversing ? Xbox.LEFT_X(joy) < 0 : Xbox.LEFT_X(joy) > 0) { |
||
0 ignored issues
–
show
|
|||
207 | right = acceleration; |
||
208 | left = (acceleration * ((2 * (1 - Math.abs(Xbox.LEFT_X(joy)))) - 1)) / radius; |
||
0 ignored issues
–
show
|
|||
209 | } else if (!reversing ? Xbox.LEFT_X(joy) > 0 : Xbox.LEFT_X(joy) < 0) { |
||
0 ignored issues
–
show
|
|||
210 | left = acceleration; |
||
211 | right = (acceleration * ((2 * (1 - Math.abs(Xbox.LEFT_X(joy)))) - 1)) / radius; |
||
0 ignored issues
–
show
|
|||
212 | } else { |
||
213 | left = acceleration; |
||
214 | right = acceleration; |
||
215 | } |
||
216 | // }][\ |
||
217 | left = (left > 1.0 ? 1.0 : (left < -1.0 ? -1.0 : left)); |
||
218 | right = (right > 1.0 ? 1.0 : (right < -1.0 ? -1.0 : right)); |
||
219 | leftMaster.set(ControlMode.PercentOutput, leftify(left) * inhibitor * (reversing ? -1.0 : 1.0)); |
||
220 | rightMaster.set(ControlMode.PercentOutput, rightify(right) * inhibitor * (reversing ? -1.0 : 1.0)); |
||
221 | |||
222 | SmartDashboard.putString("Left Master", "Left Master Voltage: " + leftMaster.getBusVoltage()); |
||
223 | SmartDashboard.putString("Right Master", "Right Master Voltage: " + rightMaster.getBusVoltage()); |
||
224 | } |
||
225 | |||
226 | |||
227 | |||
228 | public void setRamps(double ramp) { |
||
229 | if (leftMaster != null) |
||
230 | leftMaster.configOpenloopRamp(ramp, 10); |
||
0 ignored issues
–
show
|
|||
231 | if (leftSlave != null) |
||
232 | leftSlave.configOpenloopRamp(ramp, 10); |
||
0 ignored issues
–
show
|
|||
233 | if (rightMaster != null) |
||
234 | rightMaster.configOpenloopRamp(ramp, 10); |
||
0 ignored issues
–
show
|
|||
235 | if (rightSlave != null) |
||
236 | rightSlave.configOpenloopRamp(ramp, 10); |
||
0 ignored issues
–
show
|
|||
237 | } |
||
238 | |||
239 | |||
240 | |||
241 | public boolean driveDistance(double leftIn, double rightIn) { |
||
242 | double leftGoal = (leftIn2Mag(leftIn)); |
||
243 | double rightGoal = (rightIn2Mag(rightIn)); |
||
244 | leftMaster.set(ControlMode.Position, leftify(leftGoal)); |
||
245 | leftSlave.follow(leftMaster); |
||
246 | rightMaster.set(ControlMode.Position, rightify(rightGoal)); |
||
247 | rightSlave.follow(rightMaster); |
||
248 | |||
249 | boolean leftInRange = |
||
250 | pid.getLeftInches() > leftify(leftGoal) - DISTANCE_ALLOWABLE_ERROR && |
||
251 | pid.getLeftInches() < leftify(leftGoal) + DISTANCE_ALLOWABLE_ERROR; |
||
252 | boolean rightInRange = |
||
253 | pid.getRightInches() > rightify(rightGoal) - DISTANCE_ALLOWABLE_ERROR && |
||
254 | pid.getRightInches() < rightify(rightGoal) + DISTANCE_ALLOWABLE_ERROR; |
||
255 | return leftInRange && rightInRange; |
||
256 | } |
||
257 | |||
258 | public void driveDirect(double left, double right) { |
||
259 | left = (left > 1.0 ? 1.0 : (left < -1.0 ? -1.0 : left)); |
||
260 | right = (right > 1.0 ? 1.0 : (right < -1.0 ? -1.0 : right)); |
||
261 | leftMaster.set(ControlMode.PercentOutput, leftify(left)); |
||
262 | rightMaster.set(ControlMode.PercentOutput, rightify(right)); |
||
263 | } |
||
264 | |||
265 | public void setInverts() { |
||
266 | rightMaster.setInverted(Robot.bot == Bot.OOF ? Constants.OOF.RIGHT_MASTER_INVERT : Constants.TEUFELSKIND.RIGHT_MASTER_INVERT); |
||
267 | rightSlave.setInverted(Robot.bot == Bot.OOF ? Constants.OOF.RIGHT_SLAVE_INVERT : Constants.TEUFELSKIND.RIGHT_SLAVE_INVERT); |
||
268 | leftMaster.setInverted(Robot.bot == Bot.OOF ? Constants.OOF.LEFT_MASTER_INVERT : Constants.TEUFELSKIND.LEFT_MASTER_INVERT); |
||
269 | leftSlave.setInverted(Robot.bot == Bot.OOF ? Constants.OOF.LEFT_SLAVE_INVERT : Constants.TEUFELSKIND.LEFT_SLAVE_INVERT); |
||
270 | } |
||
271 | |||
272 | |||
273 | public static class PID { |
||
274 | Boolean enabled; |
||
275 | |||
276 | public PID() { |
||
277 | enabled = true; |
||
278 | } |
||
279 | public static void setPIDF(double p, double i, double d, double f) { |
||
280 | //For future reference: Inverts must be applied individually |
||
281 | setPIDF(Robot.SUB_DRIVE.leftMaster, false, p, i, d, f); |
||
282 | setPIDF(Robot.SUB_DRIVE.leftSlave, false, p, i, d, f); |
||
283 | setPIDF(Robot.SUB_DRIVE.rightMaster, true, p, i, d, f); |
||
284 | setPIDF(Robot.SUB_DRIVE.rightSlave, true, p, i, d, f); |
||
285 | } |
||
286 | |||
287 | public static void setPIDF(TalonSRX _talon, Boolean invert, double p, double i, double d, double f) { |
||
288 | /* first choose the sensor */ |
||
289 | _talon.configSelectedFeedbackSensor(FeedbackDevice.CTRE_MagEncoder_Relative, |
||
290 | 0, Constants.TIMEOUT_PID); |
||
291 | _talon.setSensorPhase(true); |
||
292 | _talon.setInverted(invert); |
||
293 | /* Set relevant frame periods to be at least as fast as periodic rate*/ |
||
294 | _talon.setStatusFramePeriod(StatusFrameEnhanced.Status_13_Base_PIDF0, 10, |
||
0 ignored issues
–
show
|
|||
295 | Constants.TIMEOUT_PID); |
||
296 | _talon.setStatusFramePeriod(StatusFrameEnhanced.Status_10_MotionMagic, 10, |
||
0 ignored issues
–
show
|
|||
297 | Constants.TIMEOUT_PID); |
||
298 | /* set the peak and nominal outputs */ |
||
299 | _talon.configNominalOutputForward(0, Constants.TIMEOUT_PID); |
||
300 | _talon.configNominalOutputReverse(0, Constants.TIMEOUT_PID); |
||
301 | _talon.configPeakOutputForward(1, Constants.TIMEOUT_PID); |
||
302 | _talon.configPeakOutputReverse(-1, Constants.TIMEOUT_PID); |
||
303 | /* set closed loop gains in slot0 - see documentation */ |
||
304 | _talon.selectProfileSlot(0, Constants.RIGHT_PID); |
||
305 | _talon.config_kP(0, p, Constants.TIMEOUT_PID); |
||
306 | _talon.config_kI(0, i, Constants.TIMEOUT_PID); |
||
307 | _talon.config_kD(0, d, Constants.TIMEOUT_PID); |
||
308 | _talon.config_kF(0, f, Constants.TIMEOUT_PID); |
||
309 | /* set acceleration and vcruise velocity - see documentation */ |
||
310 | _talon.configMotionCruiseVelocity(15000, Constants.TIMEOUT_PID); |
||
0 ignored issues
–
show
|
|||
311 | _talon.configMotionAcceleration(6000, Constants.TIMEOUT_PID); |
||
0 ignored issues
–
show
|
|||
312 | } |
||
313 | |||
314 | public void zeroEncoders() { |
||
315 | Robot.SUB_DRIVE.leftMaster.setSelectedSensorPosition(0, 0, Constants.TIMEOUT_PID); |
||
316 | Robot.SUB_DRIVE.rightMaster.setSelectedSensorPosition(0, 0, Constants.TIMEOUT_PID); |
||
317 | Robot.SUB_DRIVE.leftMaster.setIntegralAccumulator(0,0, Constants.TIMEOUT_PID); |
||
318 | Robot.SUB_DRIVE.rightMaster.setIntegralAccumulator(0,0, Constants.TIMEOUT_PID); |
||
319 | } |
||
320 | |||
321 | public double getError() { |
||
322 | return (leftify(Robot.SUB_DRIVE.leftMaster.getErrorDerivative(Constants.LEFT_PID)) + rightify(Robot.SUB_DRIVE.rightMaster.getErrorDerivative(Constants.RIGHT_PID))) / 2.0; |
||
0 ignored issues
–
show
|
|||
323 | } |
||
324 | |||
325 | public double getRightInches() { |
||
326 | return rightMag2In(Robot.SUB_DRIVE.rightMaster.getSelectedSensorPosition(Constants.RIGHT_PID)); |
||
327 | } |
||
328 | |||
329 | public double getLeftInches() { |
||
330 | return leftMag2In(Robot.SUB_DRIVE.leftMaster.getSelectedSensorPosition(Constants.LEFT_PID)); |
||
331 | } |
||
332 | |||
333 | public void reset() { |
||
334 | Robot.SUB_DRIVE.leftMaster.setSelectedSensorPosition(0, Constants.LEFT_PID, Constants.TIMEOUT_PID); |
||
335 | Robot.SUB_DRIVE.rightMaster.setSelectedSensorPosition(0, Constants.RIGHT_PID, Constants.TIMEOUT_PID); |
||
336 | } |
||
337 | } |
||
338 | } |
||
339 |
See this CWE advisory on why this is a security issue.