Skip to content

Commit

Permalink
feat: shooter IO interfaces + all hardware implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
mimizh2418 committed Jan 25, 2024
1 parent e11715f commit afe2d26
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/main/java/org/team1540/robot2024/Constants.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.team1540.robot2024;

import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.util.Units;

/**
Expand Down Expand Up @@ -55,4 +56,49 @@ public static class Drivetrain {
public static final double DRIVE_BASE_RADIUS = Math.hypot(TRACK_WIDTH_X / 2.0, TRACK_WIDTH_Y / 2.0);
public static final double MAX_ANGULAR_SPEED = MAX_LINEAR_SPEED / DRIVE_BASE_RADIUS;
}

public static class Shooter {
public static class Flywheels {
// TODO: determine ids
public static final int LEFT_ID = 0;
public static final int RIGHT_ID = 0;

public static final double WHEEL_RADIUS_METERS = Units.inchesToMeters(2.0);
public static final double GEAR_RATIO = 24.0 / 36.0;

// TODO: tune pid
public static final double KP = 0.1;
public static final double KI = 0.0;
public static final double KD = 0.0;
public static final double KS = 0.0;
public static final double KV = 0.038; // TODO: this is what recalc says, may have to tune
}

public static class Pivot {
// TODO: determine ids
public static final int MOTOR_ID = 0;
public static final int CANCODER_ID = 0;

// TODO: figure this out
public static final double CANCODER_OFFSET_ROTS = 0;
// TODO: determine ratios
public static final double CANCODER_TO_PIVOT = 60.0 / 20.0;
public static final double MOTOR_TO_CANCODER = 33.0;

public static final Rotation2d MAX_ANGLE = Rotation2d.fromDegrees(60.0);
public static final Rotation2d MIN_ANGLE = Rotation2d.fromDegrees(8.0);

// TODO: tune pid
public static final double KP = 0.1;
public static final double KI = 0.0;
public static final double KD = 0.0;
public static final double KS = 0.0;
public static final double KG = 0.1;
public static final double KV = 0.1;

public static final double CRUISE_VELOCITY_RPS = 4.0;
public static final double MAX_ACCEL_RPS2 = 40.0;
public static final double JERK_RPS3 = 2000;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.team1540.robot2024.subsystems.shooter;

import org.littletonrobotics.junction.AutoLog;

public interface FlywheelsIO {
@AutoLog
class FlywheelsIOInputs {
public double leftAppliedVolts = 0.0;
public double leftCurrentAmps = 0.0;
public double leftVelocityRPM = 0.0;
public double leftSetpointRPM = 0.0;

public double rightAppliedVolts = 0.0;
public double rightCurrentAmps = 0.0;
public double rightVelocityRPM = 0.0;
public double rightSetpointRPM = 0.0;
}

/**
* Updates the set of loggable inputs
*/
default void updateInputs(FlywheelsIOInputs inputs) {}

/**
* Runs open loop at the specified voltages
*/
default void setVoltage(double leftVolts, double rightVolts) {}


/**
* Runs closed loop at the specified RPMs
*/
default void setVelocity(double leftRPM, double rightRPM) {}

/**
* Configures the PID controller
*/
default void configPID(double kP, double kI, double kD) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package org.team1540.robot2024.subsystems.shooter;

import com.ctre.phoenix6.BaseStatusSignal;
import com.ctre.phoenix6.StatusSignal;
import com.ctre.phoenix6.configs.Slot0Configs;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.controls.VelocityVoltage;
import com.ctre.phoenix6.controls.VoltageOut;
import com.ctre.phoenix6.hardware.TalonFX;
import com.ctre.phoenix6.signals.FeedbackSensorSourceValue;
import com.ctre.phoenix6.signals.NeutralModeValue;

import static org.team1540.robot2024.Constants.Shooter.Flywheels.*;

public class FlywheelsIOTalonFX implements FlywheelsIO {
private final TalonFX leftMotor = new TalonFX(LEFT_ID);
private final TalonFX rightMotor = new TalonFX(RIGHT_ID);

private final StatusSignal<Double> leftVelocity = leftMotor.getVelocity();
private final StatusSignal<Double> leftAppliedVolts = leftMotor.getMotorVoltage();
private final StatusSignal<Double> leftCurrent = leftMotor.getSupplyCurrent();

private final StatusSignal<Double> rightVelocity = rightMotor.getVelocity();
private final StatusSignal<Double> rightAppliedVolts = rightMotor.getMotorVoltage();
private final StatusSignal<Double> rightCurrent = rightMotor.getSupplyCurrent();

private final VelocityVoltage leftVelocityCtrlReq =
new VelocityVoltage(0).withEnableFOC(false).withSlot(0);
private final VoltageOut leftVoltageCtrlReq =
new VoltageOut(0).withEnableFOC(false);

private final VelocityVoltage rightVelocityCtrlReq =
new VelocityVoltage(0).withEnableFOC(false).withSlot(0);
private final VoltageOut rightVoltageCtrlReq =
new VoltageOut(0).withEnableFOC(false);

public FlywheelsIOTalonFX() {
TalonFXConfiguration config = new TalonFXConfiguration();
config.MotorOutput.NeutralMode = NeutralModeValue.Coast;

// Shooter current limits are banned
config.CurrentLimits.SupplyCurrentLimitEnable = false;
config.CurrentLimits.StatorCurrentLimitEnable = false;

config.Feedback.FeedbackSensorSource = FeedbackSensorSourceValue.RotorSensor;
config.Feedback.SensorToMechanismRatio = GEAR_RATIO;
config.Feedback.RotorToSensorRatio = 1.0;

config.Slot0.kP = KP;
config.Slot0.kI = KI;
config.Slot0.kD = KD;
config.Slot0.kS = KS;
config.Slot0.kV = KV;

leftMotor.getConfigurator().apply(config);
rightMotor.getConfigurator().apply(config);
leftMotor.setInverted(false);
rightMotor.setInverted(true);

BaseStatusSignal.setUpdateFrequencyForAll(
50,
leftVelocity,
leftAppliedVolts,
leftCurrent,
rightVelocity,
rightAppliedVolts,
rightCurrent);

leftMotor.optimizeBusUtilization();
rightMotor.optimizeBusUtilization();
}

@Override
public void updateInputs(FlywheelsIOInputs inputs) {
BaseStatusSignal.refreshAll(
leftVelocity,
leftAppliedVolts,
leftCurrent,
rightVelocity,
rightAppliedVolts,
rightCurrent);

inputs.leftVelocityRPM = leftVelocity.getValueAsDouble() * 60;
inputs.leftSetpointRPM = leftVelocityCtrlReq.Velocity * 60;
inputs.leftAppliedVolts = leftAppliedVolts.getValueAsDouble();
inputs.leftCurrentAmps = leftCurrent.getValueAsDouble();

inputs.rightVelocityRPM = rightVelocity.getValueAsDouble() * 60;
inputs.rightSetpointRPM = rightVelocityCtrlReq.Velocity * 60;
inputs.rightAppliedVolts = rightAppliedVolts.getValueAsDouble();
inputs.rightCurrentAmps = rightCurrent.getValueAsDouble();
}

@Override
public void setVelocity(double leftRPM, double rightRPM) {
leftMotor.setControl(leftVelocityCtrlReq.withVelocity(leftRPM / 60));
rightMotor.setControl(rightVelocityCtrlReq.withVelocity(rightRPM / 60));
}

@Override
public void setVoltage(double leftVolts, double rightVolts) {
leftMotor.setControl(leftVoltageCtrlReq.withOutput(leftVolts));
rightMotor.setControl(rightVoltageCtrlReq.withOutput(rightVolts));
}

@Override
public void configPID(double kP, double kI, double kD) {
Slot0Configs pidConfigs = new Slot0Configs();
leftMotor.getConfigurator().refresh(pidConfigs);
pidConfigs.kP = kP;
pidConfigs.kI = kI;
pidConfigs.kD = kD;
leftMotor.getConfigurator().apply(pidConfigs);
rightMotor.getConfigurator().apply(pidConfigs);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.team1540.robot2024.subsystems.shooter;

import edu.wpi.first.math.geometry.Rotation2d;
import org.littletonrobotics.junction.AutoLog;

public interface ShooterPivotIO {
@AutoLog
class ShooterPivotIOInputs {
public Rotation2d position = new Rotation2d();
public Rotation2d absolutePosition = new Rotation2d();
public Rotation2d setpoint = new Rotation2d();
public double velocityRPS = 0.0;
public double appliedVolts = 0.0;
public double currentAmps = 0.0;
}

/**
* Updates the set of loggable inputs
*/
default void updateInputs(ShooterPivotIOInputs inputs) {}

/**
* Runs closed loop to the specified position
*/
default void setPosition(Rotation2d position) {}

/**
* Runs open loop at the specified voltage
*/
default void setVoltage(double volts) {}

default void configBrakeMode(boolean isBrakeMode) {}

/**
* Configures the PID controller
*/
default void configPID(double kP, double kI, double kD) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.team1540.robot2024.subsystems.shooter;

import com.ctre.phoenix6.BaseStatusSignal;
import com.ctre.phoenix6.StatusSignal;
import com.ctre.phoenix6.configs.CANcoderConfiguration;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.controls.MotionMagicVoltage;
import com.ctre.phoenix6.controls.VoltageOut;
import com.ctre.phoenix6.hardware.CANcoder;
import com.ctre.phoenix6.hardware.TalonFX;
import com.ctre.phoenix6.signals.*;
import edu.wpi.first.math.geometry.Rotation2d;

import static org.team1540.robot2024.Constants.Shooter.Pivot.*;

public class ShooterPivotIOTalonFX implements ShooterPivotIO {
private final TalonFX motor = new TalonFX(MOTOR_ID);
private final CANcoder cancoder = new CANcoder(CANCODER_ID);

private final StatusSignal<Double> position = motor.getPosition();
private final StatusSignal<Double> absolutePosition = cancoder.getAbsolutePosition();
private final StatusSignal<Double> velocity = motor.getVelocity();
private final StatusSignal<Double> appliedVoltage = motor.getMotorVoltage();
private final StatusSignal<Double> current = motor.getSupplyCurrent();

private final MotionMagicVoltage positionCtrlReq = new MotionMagicVoltage(0).withSlot(0);
private final VoltageOut voltageCtrlReq = new VoltageOut(0);

public ShooterPivotIOTalonFX() {
TalonFXConfiguration motorConfig = new TalonFXConfiguration();

// TODO: find invert
motorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake;
motorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive;

motorConfig.Feedback.FeedbackSensorSource = FeedbackSensorSourceValue.FusedCANcoder;
motorConfig.Feedback.FeedbackRemoteSensorID = CANCODER_ID;
motorConfig.Feedback.SensorToMechanismRatio = CANCODER_TO_PIVOT;
motorConfig.Feedback.RotorToSensorRatio = MOTOR_TO_CANCODER;

motorConfig.Slot0.kP = KP;
motorConfig.Slot0.kI = KI;
motorConfig.Slot0.kD = KD;
motorConfig.Slot0.kS = KS;
motorConfig.Slot0.kG = KG;
motorConfig.Slot0.kV = KV;

motorConfig.MotionMagic.MotionMagicCruiseVelocity = CRUISE_VELOCITY_RPS;
motorConfig.MotionMagic.MotionMagicAcceleration = MAX_ACCEL_RPS2;
motorConfig.MotionMagic.MotionMagicJerk = JERK_RPS3;

CANcoderConfiguration cancoderConfig = new CANcoderConfiguration();
cancoderConfig.MagnetSensor.MagnetOffset = CANCODER_OFFSET_ROTS;
// TODO: find invert
cancoderConfig.MagnetSensor.SensorDirection = SensorDirectionValue.CounterClockwise_Positive;
cancoderConfig.MagnetSensor.AbsoluteSensorRange = AbsoluteSensorRangeValue.Unsigned_0To1;

cancoder.getConfigurator().apply(cancoderConfig);
motor.getConfigurator().apply(motorConfig);

BaseStatusSignal.setUpdateFrequencyForAll(
50,
position,
absolutePosition,
velocity,
appliedVoltage,
current);

motor.optimizeBusUtilization();
cancoder.optimizeBusUtilization();
}

@Override
public void updateInputs(ShooterPivotIOInputs inputs) {
inputs.position = Rotation2d.fromRotations(position.getValueAsDouble());
inputs.absolutePosition = Rotation2d.fromRotations(absolutePosition.getValueAsDouble() / CANCODER_TO_PIVOT);
inputs.setpoint = Rotation2d.fromRotations(positionCtrlReq.Position);
inputs.velocityRPS = velocity.getValueAsDouble();
inputs.appliedVolts = appliedVoltage.getValueAsDouble();
inputs.currentAmps = current.getValueAsDouble();
}

@Override
public void setPosition(Rotation2d position) {
motor.setControl(positionCtrlReq.withPosition(position.getRotations()));
}

@Override
public void setVoltage(double volts) {
motor.setControl(voltageCtrlReq.withOutput(volts));
}
}

0 comments on commit afe2d26

Please sign in to comment.