Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/main/java/frc/robot/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -705,12 +705,12 @@ public static final class Shooter {
public static final class Hood {
public static final int HOOD_ID = 12;

public static final double KP = 0.0;
public static final double KP = 2000;
public static final double KI = 0.0;
public static final double KD = 0.0;
public static final double KV = 0.0;
public static final double KD = 80.0;
public static final double KV = 0.124;
public static final double KS = 0.0;
public static final double KG = 0.0;
public static final double KG = 0.4;

public static final double STATOR_CURRENT_LIMIT = 40.0;
public static final double SUPPLY_CURRENT_LIMIT = 40.0;
Expand Down Expand Up @@ -748,14 +748,15 @@ public static final class Rollers {
public static final int WARMUP_2_ID = 9;
public static final int WARMUP_3_ID = 11;

public static final double KP = 0.0;
public static final double KP = 0.85;
public static final double KI = 0.0;
public static final double KD = 0.0;
public static final double KV = 0.0;
public static final double KV = 0.124;
public static final double KS = 0.0;

public static final double STATOR_CURRENT_LIMIT = 120.0;
public static final double SUPPLY_CURRENT_LIMIT = 40.0;
public static final double MOTOR_ROTS_PER_WHEEL_ROTS = 15.0 / 12.0;
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.DriverStation.Alliance;
import edu.wpi.first.wpilibj2.command.Commands;
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
// * KEEP FOR WIN COMMAND TESTING
import frc.robot.commands.SwerveCommands.SwerveJoystickCommand;
Expand All @@ -19,6 +20,7 @@
import frc.robot.subsystems.HopperSubsystem;
import frc.robot.subsystems.IntakeSubsystem;
import frc.robot.subsystems.IntakeVisionDetection;
import frc.robot.subsystems.ShooterSubsystem;
import frc.robot.subsystems.VisionSubsystem;
import frc.robot.util.CustomController;
import frc.robot.util.VisionUtils;
Expand All @@ -41,6 +43,7 @@ public class RobotContainer {
Constants.hopperOnRobot ? new HopperSubsystem() : null;
public final IntakeSubsystem intakeSubsystem =
Constants.intakeOnRobot ? new IntakeSubsystem() : null;
public final ShooterSubsystem shooterSubsystem = new ShooterSubsystem();

// private final AutoRoutines autoRoutines;
// private final AutoChooser autoChooser;
Expand Down Expand Up @@ -178,6 +181,44 @@ private void configureBindings() {
// joystick.y().onTrue(new InstantCommand(() -> hoodAngle-=0.2));
// joystick.a().onTrue(new InstantCommand(() -> shooterSpeed+=0.5));
// joystick.b().onTrue(new InstantCommand(() -> shooterSpeed-=0.5));

// Shooter
shooterSubsystem.setDefaultCommand(shooterSubsystem.runOnce(shooterSubsystem::stopShooter));

// joystick
// .rightBumper()
// .whileTrue(
// new ShootBasicHood(
// () -> 44.2,
// () -> Constants.Shooter.Hood.MIN_HOOD_POSITION,
// shooterSubsystem,
// hopperSubsystem));

joystick
.rightBumper()
.whileTrue(
shooterSubsystem
.shootWithHood(44.2, Constants.Shooter.Hood.MIN_HOOD_POSITION)
.alongWith(
Commands.waitUntil(shooterSubsystem::isShooterAtSpeed)
.andThen(hopperSubsystem.runHopperUntilInterruptedCommand())));
// joystick
// .rightTrigger()
// .whileTrue(
// new ShootBasicHood(
// () -> 58.2,
// () -> Constants.Shooter.Hood.MAX_HOOD_POSITION,
// shooterSubsystem,
// hopperSubsystem));

joystick
.rightTrigger()
.whileTrue(
shooterSubsystem
.shootWithHood(58.2, Constants.Shooter.Hood.MAX_HOOD_POSITION)
.alongWith(
Commands.waitUntil(shooterSubsystem::isShooterAtSpeed)
.andThen(hopperSubsystem.runHopperUntilInterruptedCommand())));
}

public static boolean isRedAlliance() {
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/frc/robot/commandGroups/ShootBasicHood.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package frc.robot.commandGroups;

import edu.wpi.first.wpilibj2.command.Commands;
import edu.wpi.first.wpilibj2.command.ParallelCommandGroup;
import frc.robot.subsystems.HopperSubsystem;
import frc.robot.subsystems.ShooterSubsystem;
import java.util.function.DoubleSupplier;

public class ShootBasicHood extends ParallelCommandGroup {
public ShootBasicHood(
DoubleSupplier speed,
DoubleSupplier angle,
ShooterSubsystem shooterSubsystem,
HopperSubsystem hopperSubsystem) {
addCommands(
shooterSubsystem.shootWithHood(speed.getAsDouble(), angle.getAsDouble()),
Commands.waitUntil(shooterSubsystem::isShooterAtSpeed)
.andThen(hopperSubsystem.runHopperUntilInterruptedCommand()));
}
}
230 changes: 173 additions & 57 deletions src/main/java/frc/robot/subsystems/ShooterSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,88 +1,204 @@
package frc.robot.subsystems;

import static edu.wpi.first.units.Units.Rotations;

import com.ctre.phoenix6.CANBus;
import com.ctre.phoenix6.configs.CANcoderConfiguration;
import com.ctre.phoenix6.configs.CurrentLimitsConfigs;
import com.ctre.phoenix6.configs.FeedbackConfigs;
import com.ctre.phoenix6.configs.MagnetSensorConfigs;
import com.ctre.phoenix6.configs.MotorOutputConfigs;
import com.ctre.phoenix6.configs.Slot0Configs;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.controls.Follower;
import com.ctre.phoenix6.controls.PositionVoltage;
import com.ctre.phoenix6.controls.VelocityVoltage;
import com.ctre.phoenix6.hardware.CANcoder;
import com.ctre.phoenix6.signals.FeedbackSensorSourceValue;
import com.ctre.phoenix6.signals.InvertedValue;
import com.ctre.phoenix6.signals.MotorAlignmentValue;
import com.ctre.phoenix6.signals.NeutralModeValue;
import com.ctre.phoenix6.signals.SensorDirectionValue;

import edu.wpi.first.math.MathUtil;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.Constants;
import frc.robot.util.LoggedTalonFX;


public class ShooterSubsystem extends SubsystemBase {

private final LoggedTalonFX warmup1, warmup2, warmup3, shooter, hood;
private final CANcoder hoodEncoder;


/*
* make instance variables for necessary closed loop control requests: VelocityVoltage, PositionVoltage. Initialize them with value 0.0.
* make instance variables of type double for the target roller speed and target hood angle
*/

public ShooterSubsystem() {
// The canbus is a communication system that can connect devices like the roboRIO, pdh, and motors.
CANBus canbus = Constants.Swerve.CAN_BUS;

// LoggedTalonFX is our version of the existing TalonFX class, which automatically logs some motor information
warmup1 = new LoggedTalonFX("ShooterWarmup1", Constants.Shooter.Rollers.WARMUP_1_ID, canbus);
warmup2 = new LoggedTalonFX("ShooterWarmup2", Constants.Shooter.Rollers.WARMUP_2_ID, canbus);
warmup3 = new LoggedTalonFX("ShooterWarmup3", Constants.Shooter.Rollers.WARMUP_3_ID, canbus);

shooter = warmup3; // warmup1 and warmup2 will be set as "followers" of the "lead" warmup3, so later we can just reference the `shooter` variable

// Initialize the hood motor just like the warmup motors. You can find the necessary ID in Constants.

// Create a variable of type Slot0Configs called rollersSlot0Configs, and initialize it with the pid and feedforward gains found in Constants

// Create a variable of type CurrentLimitsConfigs called rollersClConfigs, and initialize it with the stator and supply limits found in Constants

// Create a variable of type MotorOutputConfigs called rollersOutputConfigs, and initialize it to treat clockwise as positive, and neutral mode as coast

TalonFXConfiguration rollersConfig = new TalonFXConfiguration();
// Set the Slot0, CurrentLimits, and MotorOutput parameters of `rollersConfig` to the configs you just created.

warmup1.getConfigurator().apply(rollersConfig);
// I just applied the configuration that you just created to warmup1. Apply it to warmup2 and warmup3 as well.

Follower follower = new Follower(Constants.Shooter.Rollers.WARMUP_3_ID, MotorAlignmentValue.Aligned);
// use the `setControl` method of warmup1 and 2 to configure them to use this follower configuration.

hoodEncoder = new CANcoder(Constants.Shooter.Hood.ENCODER_PORT, Constants.Swerve.CAN_BUS);

// Create a variable of type Slot0Configs called hoodSlot0Configs, and initialize it with the pid and feedforward gains found in Constants

// Create a variable of type CurrentLimitsConfigs called hoodClConfigs, and initialize it with the stator and supply limits found in Constants

// Create a variable of type MotorOutputConfigs called hoodOutputConfigs, and initialize it to treat counterclockwise as positive, and neutral mode as coast

FeedbackConfigs hoodFeedbackConfigs =
private final LoggedTalonFX warmup1, warmup2, warmup3, shooter, hood;
private final CANcoder hoodEncoder;

/*
* make instance variables for necessary closed loop control requests: VelocityVoltage, PositionVoltage. Initialize them with value 0.0.
* make instance variables of type double for the target roller speed and target hood angle
*/

private VelocityVoltage m_velocityReq = new VelocityVoltage(0.0);
private PositionVoltage m_positionReq = new PositionVoltage(0.0);

private double targetShooterSpeed, targetHoodAngle;

public ShooterSubsystem() {
// The canbus is a communication system that can connect devices like the roboRIO, pdh, and
// motors.
CANBus canbus = Constants.Swerve.CAN_BUS;

targetShooterSpeed = 0;
targetHoodAngle = 0;

// LoggedTalonFX is our version of the existing TalonFX class, which automatically logs some
// motor information
warmup1 = new LoggedTalonFX("ShooterWarmup1", Constants.Shooter.Rollers.WARMUP_1_ID, canbus);
warmup2 = new LoggedTalonFX("ShooterWarmup2", Constants.Shooter.Rollers.WARMUP_2_ID, canbus);
warmup3 = new LoggedTalonFX("ShooterWarmup3", Constants.Shooter.Rollers.WARMUP_3_ID, canbus);

shooter =
warmup3; // warmup1 and warmup2 will be set as "followers" of the "lead" warmup3, so later
// we can just reference the `shooter` variable

// Initialize the hood motor just like the warmup motors. You can find the necessary ID in
// Constants.
hood = new LoggedTalonFX("ShooterHood", Constants.Shooter.Hood.HOOD_ID, canbus);

// Create a variable of type Slot0Configs called rollersSlot0Configs, and initialize it with the
// pid and feedforward gains found in Constants
Slot0Configs rollersSlot0Configs =
new Slot0Configs()
.withKP(Constants.Shooter.Rollers.KP)
.withKI(Constants.Shooter.Rollers.KI)
.withKD(Constants.Shooter.Rollers.KD)
.withKS(Constants.Shooter.Rollers.KS)
.withKV(Constants.Shooter.Rollers.KV);

// Create a variable of type CurrentLimitsConfigs called rollersClConfigs, and initialize it
// with the stator and supply limits found in Constants
CurrentLimitsConfigs rollersClConfigs =
new CurrentLimitsConfigs()
.withStatorCurrentLimit(Constants.Shooter.Rollers.STATOR_CURRENT_LIMIT)
.withSupplyCurrentLimit(Constants.Shooter.Rollers.SUPPLY_CURRENT_LIMIT);

// Create a variable of type MotorOutputConifigs called rollersOutputConfigs, and initialize it
// to treat clockwise as positive, and neutral mode as coast
MotorOutputConfigs rollersOutputConfigs =
new MotorOutputConfigs()
.withInverted(InvertedValue.Clockwise_Positive)
.withNeutralMode(NeutralModeValue.Coast);

TalonFXConfiguration rollersConfig =
new TalonFXConfiguration()
.withSlot0(rollersSlot0Configs)
.withCurrentLimits(rollersClConfigs)
.withMotorOutput(rollersOutputConfigs);
// Set the Slot0, CurrentLimits, and MotorOutput parameters of `rollersConfig` to the configs
// you just created.

warmup1.getConfigurator().apply(rollersConfig);
warmup2.getConfigurator().apply(rollersConfig);
warmup3.getConfigurator().apply(rollersConfig);
// I just applied the configuration that you just created to warmup1. Apply it to warmup2 and
// warmup3 as well.

Follower follower =
new Follower(Constants.Shooter.Rollers.WARMUP_3_ID, MotorAlignmentValue.Aligned);
// use the `setControl` method of warmup1 and 2 to configure them to use this follower
// configuration.
warmup1.setControl(follower);
warmup2.setControl(follower);

hoodEncoder = new CANcoder(Constants.Shooter.Hood.ENCODER_PORT, Constants.Swerve.CAN_BUS);

// Create a variable of type Slot0Configs called hoodSlot0Configs, and initialize it with the
// pid and feedforward gains found in Constants
Slot0Configs hoodSlot0Configs =
new Slot0Configs()
.withKP(Constants.Shooter.Hood.KP)
.withKI(Constants.Shooter.Hood.KI)
.withKD(Constants.Shooter.Hood.KD)
.withKS(Constants.Shooter.Hood.KS)
.withKG(Constants.Shooter.Hood.KG)
.withKV(Constants.Shooter.Hood.KV);

// Create a variable of type CurrentLimitsConfigs called hoodClConfigs, and initialize it with
// the stator and supply limits found in Constants
CurrentLimitsConfigs hoodClConfigs =
new CurrentLimitsConfigs()
.withStatorCurrentLimit(Constants.Shooter.Hood.STATOR_CURRENT_LIMIT)
.withSupplyCurrentLimit(Constants.Shooter.Hood.SUPPLY_CURRENT_LIMIT);

// Create a variable of type MotorOutputConifigs called hoodOutputConfigs, and initialize it to
// treat counterclockwise as positive, and neutral mode as coast
MotorOutputConfigs hoodOutputConfigs =
new MotorOutputConfigs()
.withInverted(InvertedValue.CounterClockwise_Positive)
.withNeutralMode(NeutralModeValue.Coast);

FeedbackConfigs hoodFeedbackConfigs =
new FeedbackConfigs()
.withFeedbackRemoteSensorID(hoodEncoder.getDeviceID())
.withFeedbackSensorSource(FeedbackSensorSourceValue.FusedCANcoder)
.withSensorToMechanismRatio(Constants.Shooter.Hood.ENCODER_ROTS_PER_HOOD_ROT)
.withRotorToSensorRatio(Constants.Shooter.Hood.MOTOR_ROTS_PER_ENCODER_ROT);

// Create a TalonFXConfiguration called hoodConfig
// Set the Slot0, CurrentLimits, MotorOutput, and Feedback parameters to the device configs above

// Apply the created configuration to the hood motor

MagnetSensorConfigs hoodCANcoderConfig =
// Create a TalonFXConfiguration called hoodConfig
// Set the Slot0, CurrentLimits, MotorOutput, and Feedback parameters to the device configs
// above
// Apply the created configuration to the hood motor
hood.getConfigurator()
.apply(
new TalonFXConfiguration()
.withSlot0(hoodSlot0Configs)
.withCurrentLimits(hoodClConfigs)
.withMotorOutput(hoodOutputConfigs)
.withFeedback(hoodFeedbackConfigs));

MagnetSensorConfigs hoodCANcoderConfig =
new CANcoderConfiguration()
.MagnetSensor.withAbsoluteSensorDiscontinuityPoint(Rotations.of(1))
.withSensorDirection(SensorDirectionValue.CounterClockwise_Positive)
.withMagnetOffset(Rotations.of(Constants.Shooter.Hood.ENCODER_OFFSET));

// Apply this config to the `hoodEncoder`. Notice how applying a device configuration is similar between motors and other devices

}
// Apply this config to the `hoodEncoder`. Notice how applying a device configuration is similar
// between motors and other devices
hoodEncoder.getConfigurator().apply(hoodCANcoderConfig);
}

public void setHoodAngle(double degrees) {
targetHoodAngle = degrees;
hood.setControl(
m_positionReq.withPosition(
MathUtil.clamp(
targetHoodAngle,
Constants.Shooter.Hood.MIN_HOOD_POSITION,
Constants.Shooter.Hood.MAX_HOOD_POSITION)
/ 360.0));
}

public void setShooterSpeed(double velocityRps) {
targetShooterSpeed = velocityRps;
shooter.setControl(
m_velocityReq.withVelocity(
targetShooterSpeed * Constants.Shooter.Rollers.MOTOR_ROTS_PER_WHEEL_ROTS));
}

public void stopShooter() {
targetShooterSpeed = 0.0;
shooter.stopMotor();
}

public boolean isShooterAtSpeed() {
double currentVelocity =
shooter.getCachedVelocityRps() / Constants.Shooter.Rollers.MOTOR_ROTS_PER_WHEEL_ROTS;
return Math.abs(currentVelocity - targetShooterSpeed) <= 1.0;
}

public Command shootWithHood(double hoodAngleDegrees, double shooterVelocityRps) {
return runEnd(
() -> {
setShooterSpeed(shooterVelocityRps);
setHoodAngle(hoodAngleDegrees);
},
this::stopShooter);
}
}
Loading