-
Notifications
You must be signed in to change notification settings - Fork 0
Initial Climb Subsystem #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
09cd8f4
cb0cb50
f931e74
66e4da0
83a6794
a78dcc7
e8132ea
1d4f932
1376efc
cdc2512
97a6220
494b88b
82e4acd
0f3cc2a
4af74e2
f3e3c6f
eb0c5fc
810c3c4
daec791
c6192e1
88599f9
3a962d5
f562771
98a9de0
732740f
5af022c
0778ab5
6c1f3b0
7025585
773923a
a35af84
8f516bc
912f283
867578b
e5d4307
9412d2e
c00bcde
2d38ce9
78886b0
ce9a58b
95716d3
a3da027
5a1e20b
91eaac2
15d3efe
da4965c
a0beac7
27fd2f4
9b0c237
104c5c5
c2c3774
8f901c2
958bf02
580deb6
3f5bd10
a5a42f7
c8965d7
d87287f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,151 @@ | ||
| package frc.robot.constants; | ||
|
|
||
| public class ClimbConstants {} | ||
| import static edu.wpi.first.units.Units.Degrees; | ||
| import static edu.wpi.first.units.Units.DegreesPerSecond; | ||
|
|
||
| import com.ctre.phoenix6.configs.CurrentLimitsConfigs; | ||
| import com.ctre.phoenix6.configs.HardwareLimitSwitchConfigs; | ||
| import com.ctre.phoenix6.configs.MotionMagicConfigs; | ||
| import com.ctre.phoenix6.configs.MotorOutputConfigs; | ||
| import com.ctre.phoenix6.configs.Slot0Configs; | ||
| import com.ctre.phoenix6.configs.SoftwareLimitSwitchConfigs; | ||
| import com.ctre.phoenix6.configs.TalonFXConfiguration; | ||
| import com.ctre.phoenix6.signals.ForwardLimitSourceValue; | ||
| import com.ctre.phoenix6.signals.ForwardLimitTypeValue; | ||
| import com.ctre.phoenix6.signals.GravityTypeValue; | ||
| import com.ctre.phoenix6.signals.NeutralModeValue; | ||
| import com.ctre.phoenix6.signals.ReverseLimitSourceValue; | ||
| import com.ctre.phoenix6.signals.ReverseLimitTypeValue; | ||
| import edu.wpi.first.units.measure.Angle; | ||
| import edu.wpi.first.units.measure.AngularVelocity; | ||
|
|
||
| public class ClimbConstants { | ||
| public static int kWheelFxId = 0; | ||
| public static int kArmFxId = 0; | ||
|
|
||
| public static final AngularVelocity kWheelCloseEnough = DegreesPerSecond.of(5.0); | ||
| public static final Angle kArmCloseEnough = Degrees.of(5.0); | ||
| public static final Angle kArmMaxFwd = Degrees.of(100); | ||
| public static final Angle kArmMaxRev = Degrees.of(-100); | ||
| public static final Angle kArmZeroTicks = Degrees.of(1530); | ||
|
|
||
| public static TalonFXConfiguration getWheelFXConfig() { | ||
| TalonFXConfiguration wheelFxConfig = new TalonFXConfiguration(); | ||
|
|
||
| CurrentLimitsConfigs current = | ||
| new CurrentLimitsConfigs() | ||
| .withStatorCurrentLimit(10) | ||
| .withStatorCurrentLimitEnable(false) | ||
| .withStatorCurrentLimit(20) | ||
| .withSupplyCurrentLimit(10) | ||
| .withSupplyCurrentLowerLimit(8) | ||
| .withSupplyCurrentLowerTime(0.02) | ||
| .withSupplyCurrentLimitEnable(true); | ||
| wheelFxConfig.CurrentLimits = current; | ||
|
|
||
| HardwareLimitSwitchConfigs hwLimit = | ||
| new HardwareLimitSwitchConfigs() | ||
| .withForwardLimitAutosetPositionEnable(false) | ||
| .withForwardLimitEnable(false) | ||
| .withForwardLimitType(ForwardLimitTypeValue.NormallyOpen) | ||
| .withForwardLimitSource(ForwardLimitSourceValue.LimitSwitchPin) | ||
| .withReverseLimitAutosetPositionEnable(false) | ||
| .withReverseLimitEnable(false) | ||
| .withReverseLimitType(ReverseLimitTypeValue.NormallyOpen) | ||
| .withReverseLimitSource(ReverseLimitSourceValue.LimitSwitchPin); | ||
| wheelFxConfig.HardwareLimitSwitch = hwLimit; | ||
|
|
||
| Slot0Configs slot0 = | ||
| new Slot0Configs() | ||
| .withKP(0) | ||
| .withKI(0) | ||
| .withKD(0) | ||
| .withGravityType(GravityTypeValue.Elevator_Static) | ||
| .withKG(0) | ||
| .withKS(0) | ||
| .withKV(0) | ||
| .withKA(0); | ||
| wheelFxConfig.Slot0 = slot0; | ||
|
|
||
| MotionMagicConfigs motionMagic = | ||
| new MotionMagicConfigs() | ||
| .withMotionMagicAcceleration(0) | ||
| .withMotionMagicCruiseVelocity(0) | ||
| .withMotionMagicExpo_kA(0) | ||
| .withMotionMagicExpo_kV(0) | ||
| .withMotionMagicJerk(0); | ||
| wheelFxConfig.MotionMagic = motionMagic; | ||
|
|
||
| MotorOutputConfigs motorOut = | ||
| new MotorOutputConfigs() | ||
| .withDutyCycleNeutralDeadband(0.01) | ||
| .withNeutralMode(NeutralModeValue.Coast); | ||
| wheelFxConfig.MotorOutput = motorOut; | ||
|
|
||
| return wheelFxConfig; | ||
| } | ||
|
|
||
| public static TalonFXConfiguration getArmFxConfig() { | ||
| TalonFXConfiguration armFxConfig = new TalonFXConfiguration(); | ||
|
|
||
| CurrentLimitsConfigs current = | ||
| new CurrentLimitsConfigs() | ||
| .withStatorCurrentLimit(10) | ||
| .withStatorCurrentLimitEnable(false) | ||
| .withStatorCurrentLimit(20) | ||
| .withSupplyCurrentLimit(10) | ||
| .withSupplyCurrentLowerLimit(8) | ||
| .withSupplyCurrentLowerTime(0.02) | ||
| .withSupplyCurrentLimitEnable(true); | ||
| armFxConfig.CurrentLimits = current; | ||
|
|
||
| HardwareLimitSwitchConfigs hwLimit = | ||
| new HardwareLimitSwitchConfigs() | ||
| .withForwardLimitAutosetPositionEnable(false) | ||
| .withForwardLimitEnable(false) | ||
| .withForwardLimitType(ForwardLimitTypeValue.NormallyOpen) | ||
| .withForwardLimitSource(ForwardLimitSourceValue.LimitSwitchPin) | ||
| .withReverseLimitAutosetPositionEnable(false) | ||
| .withReverseLimitEnable(false) | ||
| .withReverseLimitType(ReverseLimitTypeValue.NormallyOpen) | ||
| .withReverseLimitSource(ReverseLimitSourceValue.LimitSwitchPin); | ||
| armFxConfig.HardwareLimitSwitch = hwLimit; | ||
|
|
||
| SoftwareLimitSwitchConfigs swLimit = | ||
| new SoftwareLimitSwitchConfigs() | ||
| .withForwardSoftLimitEnable(true) | ||
| .withForwardSoftLimitThreshold(kArmMaxFwd) | ||
| .withReverseSoftLimitEnable(true) | ||
| .withReverseSoftLimitThreshold(kArmMaxRev); | ||
| armFxConfig.SoftwareLimitSwitch = swLimit; | ||
|
|
||
| Slot0Configs slot0 = | ||
| new Slot0Configs() | ||
| .withKP(0) | ||
| .withKI(0) | ||
| .withKD(0) | ||
| .withGravityType(GravityTypeValue.Elevator_Static) | ||
| .withKG(0) | ||
| .withKS(0) | ||
| .withKV(0) | ||
| .withKA(0); | ||
| armFxConfig.Slot0 = slot0; | ||
|
|
||
| MotionMagicConfigs motionMagic = | ||
| new MotionMagicConfigs() | ||
| .withMotionMagicAcceleration(0) | ||
| .withMotionMagicCruiseVelocity(0) | ||
| .withMotionMagicExpo_kA(0) | ||
| .withMotionMagicExpo_kV(0) | ||
| .withMotionMagicJerk(0); | ||
| armFxConfig.MotionMagic = motionMagic; | ||
|
|
||
| MotorOutputConfigs motorOut = | ||
| new MotorOutputConfigs() | ||
| .withDutyCycleNeutralDeadband(0.01) | ||
| .withNeutralMode(NeutralModeValue.Coast); | ||
| armFxConfig.MotorOutput = motorOut; | ||
|
|
||
| return armFxConfig; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package frc.robot.subsystems.climb; | ||
|
|
||
| import static edu.wpi.first.units.Units.Rotations; | ||
|
|
||
| import edu.wpi.first.units.measure.Angle; | ||
| import org.littletonrobotics.junction.AutoLog; | ||
| import org.strykeforce.telemetry.TelemetryService; | ||
|
|
||
| public interface ClimbArmIO { | ||
|
|
||
| @AutoLog | ||
| static class ClimbArmIOInputs { | ||
| public Angle position = Rotations.of(0.0); | ||
| } | ||
|
|
||
| public default void setPosition(Angle position) {} | ||
|
|
||
| public default void updateInputs(ClimbArmIOInputs inputs) {} | ||
|
|
||
| public default void zero() {} | ||
|
|
||
| public default void registerWith(TelemetryService telemetryService) {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package frc.robot.subsystems.climb; | ||
|
|
||
| import static edu.wpi.first.units.Units.Rotations; | ||
|
|
||
| import com.ctre.phoenix6.StatusSignal; | ||
| import com.ctre.phoenix6.configs.TalonFXConfiguration; | ||
| import com.ctre.phoenix6.configs.TalonFXConfigurator; | ||
| import com.ctre.phoenix6.controls.MotionMagicDutyCycle; | ||
| import com.ctre.phoenix6.hardware.TalonFX; | ||
| import edu.wpi.first.units.measure.Angle; | ||
| import frc.robot.constants.ClimbConstants; | ||
| import frc.robot.constants.ExampleConstants; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class ClimbArmIOFX implements ClimbArmIO { | ||
| private Logger logger; | ||
| private TalonFX talonFx; | ||
|
|
||
| private final Angle absSensorInitial; | ||
| private Angle relSetpointOffset; | ||
| private Angle setpoint; | ||
|
|
||
| TalonFXConfigurator configurator; | ||
| private MotionMagicDutyCycle positionRequest = | ||
| new MotionMagicDutyCycle(0).withEnableFOC(false).withFeedForward(0).withSlot(0); | ||
| StatusSignal<Angle> curPosition; | ||
|
|
||
| public ClimbArmIOFX() { | ||
| logger = LoggerFactory.getLogger(this.getClass()); | ||
| talonFx = new TalonFX(ClimbConstants.kArmFxId); | ||
| absSensorInitial = | ||
| talonFx.getPosition().getValue(); // relative encoder starts up as absolute position offset | ||
|
|
||
| configurator = talonFx.getConfigurator(); | ||
| configurator.apply(new TalonFXConfiguration()); // Factory default motor controller | ||
| configurator.apply(ClimbConstants.getArmFxConfig()); | ||
|
|
||
| curPosition = talonFx.getPosition(); | ||
| } | ||
|
|
||
| @Override | ||
| public void setPosition(Angle position) { | ||
| setpoint = position.plus(relSetpointOffset); | ||
|
|
||
| logger.info("Setting position to {} rotations", setpoint.in(Rotations)); | ||
|
|
||
| talonFx.setControl(positionRequest.withPosition(setpoint)); | ||
| } | ||
|
|
||
| @Override | ||
| public void updateInputs(ClimbArmIOInputs inputs) { | ||
| inputs.position = curPosition.refresh().getValue(); | ||
| } | ||
|
|
||
| @Override | ||
| public void zero() { | ||
| relSetpointOffset = ExampleConstants.kZeroTicks; | ||
| logger.info( | ||
| "Abs: {}, Zero Pos: {}, Offset: {}", | ||
| absSensorInitial, | ||
| ExampleConstants.kZeroTicks, | ||
| absSensorInitial.minus(ExampleConstants.kZeroTicks)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,89 @@ | ||
| package frc.robot.subsystems.climb; | ||
|
|
||
| public class ClimbSubsystem {} | ||
| import static edu.wpi.first.units.Units.Rotations; | ||
|
|
||
| import edu.wpi.first.units.measure.Angle; | ||
| import frc.robot.constants.ClimbConstants; | ||
| import frc.robot.standards.ClosedLoopPosSubsystem; | ||
| import java.util.Set; | ||
| import org.littletonrobotics.junction.Logger; | ||
| import org.strykeforce.telemetry.TelemetryService; | ||
| import org.strykeforce.telemetry.measurable.MeasurableSubsystem; | ||
| import org.strykeforce.telemetry.measurable.Measure; | ||
|
|
||
| public class ClimbSubsystem extends MeasurableSubsystem implements ClosedLoopPosSubsystem { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming most of these are because you aren't done yet but you'll need methods like the following:
|
||
| private final ClimbArmIO io; | ||
| private final ClimbWheelIO wheelIo; | ||
|
|
||
| private final ClimbArmIOInputsAutoLogged inputs = new ClimbArmIOInputsAutoLogged(); | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to add wheelIOInputsAutoLogged as well
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. may want to rename so it is clear which is armInputs and which is wheelInputs |
||
| private Angle setpoint = Rotations.of(0.0); | ||
| private ClimbState curState = ClimbState.INIT; | ||
|
|
||
| public ClimbSubsystem(ClimbArmIO io, ClimbWheelIO wheelIo) { | ||
| this.io = io; | ||
| this.wheelIo = wheelIo; | ||
|
|
||
| zero(); | ||
| } | ||
|
|
||
| @Override | ||
| public Angle getPosition() { | ||
| return inputs.position; | ||
| } | ||
|
|
||
| @Override | ||
| public void setPosition(Angle position) { | ||
| io.setPosition(position); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isFinished() { | ||
| return setpoint.minus(inputs.position).abs(Rotations) | ||
| <= ClimbConstants.kArmCloseEnough.in(Rotations); | ||
| } | ||
|
|
||
| @Override | ||
| public void zero() { | ||
| io.zero(); | ||
|
|
||
| curState = ClimbState.ZEROED; | ||
| } | ||
|
|
||
| @Override | ||
| public void periodic() { | ||
| // Read Inputs | ||
| io.updateInputs(inputs); | ||
|
||
|
|
||
| // State Machine | ||
| switch (curState) { | ||
| case INIT: | ||
| break; | ||
| case ZEROED: | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| // Log Outputs | ||
| Logger.recordOutput("Coral/curState", curState.ordinal()); | ||
| Logger.recordOutput("Coral/setpoint", setpoint.in(Rotations)); | ||
| } | ||
|
|
||
| @Override | ||
| public void registerWith(TelemetryService telemetryService) { | ||
| super.registerWith(telemetryService); | ||
| wheelIo.registerWith(telemetryService); | ||
| io.registerWith(telemetryService); | ||
| } | ||
|
|
||
| @Override | ||
| public Set<Measure> getMeasures() { | ||
| return Set.of(); | ||
| } | ||
|
|
||
| public enum ClimbState { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likely will end up having more states, but we probably don't know enough yet to write them |
||
| INIT, | ||
| ZEROED | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package frc.robot.subsystems.climb; | ||
|
|
||
| import org.strykeforce.telemetry.TelemetryService; | ||
|
|
||
| public interface ClimbWheelIO { | ||
|
|
||
| public default void setPercent(double pct) {} | ||
|
|
||
| public default void registerWith(TelemetryService telemetryService) {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package frc.robot.subsystems.climb; | ||
|
|
||
| import com.ctre.phoenix6.configs.TalonFXConfiguration; | ||
| import com.ctre.phoenix6.configs.TalonFXConfigurator; | ||
| import com.ctre.phoenix6.hardware.TalonFX; | ||
| import frc.robot.constants.ClimbConstants; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.strykeforce.telemetry.TelemetryService; | ||
|
|
||
| public class ClimbWheelIOFX implements ClimbWheelIO { | ||
| private Logger logger; | ||
| private TalonFX talonFx; | ||
|
|
||
| TalonFXConfigurator configurator; | ||
|
|
||
| public ClimbWheelIOFX() { | ||
| logger = LoggerFactory.getLogger(this.getClass()); | ||
| talonFx = new TalonFX(ClimbConstants.kWheelFxId); | ||
|
|
||
| configurator = talonFx.getConfigurator(); | ||
| configurator.apply(new TalonFXConfiguration()); // Factory default motor controller | ||
| configurator.apply(ClimbConstants.getWheelFXConfig()); | ||
| } | ||
|
|
||
| @Override | ||
| public void setPercent(double pct) { | ||
| logger.info("Setting percent to {}", pct); | ||
|
|
||
| talonFx.set(pct); | ||
|
||
| } | ||
|
|
||
| @Override | ||
| public void registerWith(TelemetryService telemetryService) { | ||
| telemetryService.register(talonFx, true); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to actually write to the encoder as we will have an encoder on the shaft that tilts the cage in (using a winch) instead of saving off a zero