|
| 1 | +package frc.robot.subsystems; |
| 2 | + |
| 3 | +import com.thethriftybot.ThriftyNova; |
| 4 | + |
| 5 | +import edu.wpi.first.math.controller.ArmFeedforward; |
| 6 | +import edu.wpi.first.math.system.plant.DCMotor; |
| 7 | +import edu.wpi.first.units.measure.Angle; |
| 8 | + |
| 9 | +import static edu.wpi.first.units.Units.Amps; |
| 10 | +import static edu.wpi.first.units.Units.Degrees; |
| 11 | +import static edu.wpi.first.units.Units.DegreesPerSecond; |
| 12 | +import static edu.wpi.first.units.Units.DegreesPerSecondPerSecond; |
| 13 | +import static edu.wpi.first.units.Units.Feet; |
| 14 | +import static edu.wpi.first.units.Units.Inches; |
| 15 | +import static edu.wpi.first.units.Units.Pounds; |
| 16 | +import static edu.wpi.first.units.Units.RPM; |
| 17 | +import static edu.wpi.first.units.Units.Seconds; |
| 18 | + |
| 19 | +import edu.wpi.first.wpilibj2.command.Command; |
| 20 | +import edu.wpi.first.wpilibj2.command.Commands; |
| 21 | +import edu.wpi.first.wpilibj2.command.SubsystemBase; |
| 22 | +import frc.robot.Constants; |
| 23 | +import yams.gearing.GearBox; |
| 24 | +import yams.gearing.MechanismGearing; |
| 25 | +import yams.mechanisms.config.ArmConfig; |
| 26 | +import yams.mechanisms.config.FlyWheelConfig; |
| 27 | +import yams.mechanisms.positional.Arm; |
| 28 | +import yams.mechanisms.velocity.FlyWheel; |
| 29 | +import yams.motorcontrollers.SmartMotorController; |
| 30 | +import yams.motorcontrollers.SmartMotorControllerConfig; |
| 31 | +import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode; |
| 32 | +import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode; |
| 33 | +import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity; |
| 34 | +import yams.motorcontrollers.local.NovaWrapper; |
| 35 | + |
| 36 | +public class IntakeSubsystem extends SubsystemBase { |
| 37 | + |
| 38 | + private static final double INTAKE_SPEED = 0.1; |
| 39 | + |
| 40 | + // ThriftyNova controlling the intake roller |
| 41 | + private ThriftyNova rollerNova = new ThriftyNova(Constants.IntakeConstants.kRollerMotorId); |
| 42 | + |
| 43 | + private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this) |
| 44 | + .withControlMode(ControlMode.OPEN_LOOP) |
| 45 | + .withTelemetry("IntakeMotor", TelemetryVerbosity.HIGH) |
| 46 | + .withGearing(new MechanismGearing(GearBox.fromReductionStages(1))) // Direct drive, adjust if geared |
| 47 | + .withMotorInverted(false) |
| 48 | + .withIdleMode(MotorMode.COAST) |
| 49 | + .withStatorCurrentLimit(Amps.of(40)); |
| 50 | + |
| 51 | + private SmartMotorController smc = new NovaWrapper(rollerNova, DCMotor.getNeoVortex(1), smcConfig); |
| 52 | + |
| 53 | + private final FlyWheelConfig intakeConfig = new FlyWheelConfig(smc) |
| 54 | + .withDiameter(Inches.of(4)) |
| 55 | + .withMass(Pounds.of(0.5)) |
| 56 | + .withUpperSoftLimit(RPM.of(6000)) |
| 57 | + .withLowerSoftLimit(RPM.of(-6000)) |
| 58 | + .withTelemetry("Intake", TelemetryVerbosity.HIGH); |
| 59 | + |
| 60 | + private FlyWheel intake = new FlyWheel(intakeConfig); |
| 61 | + |
| 62 | + // 5:1, 5:1, 60/18 reduction |
| 63 | + private SmartMotorControllerConfig intakePivotSmartMotorConfig = new SmartMotorControllerConfig(this) |
| 64 | + .withControlMode(ControlMode.CLOSED_LOOP) |
| 65 | + .withClosedLoopController(200, 0, 0, DegreesPerSecond.of(360), DegreesPerSecondPerSecond.of(360)) |
| 66 | + .withFeedforward(new ArmFeedforward(0, 0, 0.1)) |
| 67 | + .withTelemetry("IntakePivotMotor", TelemetryVerbosity.HIGH) |
| 68 | + .withGearing(new MechanismGearing(GearBox.fromReductionStages(5, 5, 60.0 / 18))) |
| 69 | + .withMotorInverted(true) |
| 70 | + .withIdleMode(MotorMode.BRAKE) |
| 71 | + .withStatorCurrentLimit(Amps.of(10)) |
| 72 | + .withClosedLoopRampRate(Seconds.of(0.1)); |
| 73 | + |
| 74 | + private ThriftyNova pivotMotor = new ThriftyNova(Constants.IntakeConstants.kPivotMotorId); |
| 75 | + |
| 76 | + private SmartMotorController intakePivotController = new NovaWrapper(pivotMotor, DCMotor.getNeoVortex(1), |
| 77 | + intakePivotSmartMotorConfig); |
| 78 | + |
| 79 | + private final ArmConfig intakePivotConfig = new ArmConfig(intakePivotController) |
| 80 | + .withSoftLimits(Degrees.of(-95), Degrees.of(45)) // TODO: Find and set proper limits once setpoints and range is |
| 81 | + // known |
| 82 | + .withHardLimit(Degrees.of(-100), Degrees.of(50)) |
| 83 | + .withStartingPosition(Degrees.of(-90)) |
| 84 | + .withLength(Feet.of(1)) |
| 85 | + .withMass(Pounds.of(2)) // Reis says: 2 pounds, not a lot |
| 86 | + .withTelemetry("IntakePivot", TelemetryVerbosity.HIGH); |
| 87 | + |
| 88 | + private Arm intakePivot = new Arm(intakePivotConfig); |
| 89 | + |
| 90 | + public IntakeSubsystem() { |
| 91 | + } |
| 92 | + |
| 93 | + /** |
| 94 | + * Command to run the intake while held. |
| 95 | + */ |
| 96 | + public Command intakeCommand() { |
| 97 | + return intake.set(INTAKE_SPEED).finallyDo(() -> smc.setDutyCycle(0)).withName("Intake.Run"); |
| 98 | + } |
| 99 | + |
| 100 | + /** |
| 101 | + * Command to eject while held. |
| 102 | + */ |
| 103 | + public Command ejectCommand() { |
| 104 | + return intake.set(-INTAKE_SPEED).finallyDo(() -> smc.setDutyCycle(0)).withName("Intake.Eject"); |
| 105 | + } |
| 106 | + |
| 107 | + public Command setPivotAngle(Angle angle) { |
| 108 | + return intakePivot.setAngle(angle).withName("IntakePivot.SetAngle"); |
| 109 | + } |
| 110 | + |
| 111 | + public Command rezero() { |
| 112 | + return Commands.runOnce(() -> pivotMotor.setEncoderPosition(0), this).withName("IntakePivot.Rezero"); |
| 113 | + } |
| 114 | + |
| 115 | + @Override |
| 116 | + public void periodic() { |
| 117 | + intake.updateTelemetry(); |
| 118 | + intakePivot.updateTelemetry(); |
| 119 | + } |
| 120 | + |
| 121 | + @Override |
| 122 | + public void simulationPeriodic() { |
| 123 | + intake.simIterate(); |
| 124 | + intakePivot.simIterate(); |
| 125 | + } |
| 126 | +} |
0 commit comments