Skip to content
Open
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
66a017d
add basic climb system
thartnett27-sudo Jan 23, 2026
f91b012
implement basic climb
thartnett27-sudo Jan 23, 2026
edd7ab4
cleaned code and fixed if statement
thartnett27-sudo Jan 23, 2026
99ef66b
added setPosition in hardware implementation file
leokalbteague-cloud Jan 25, 2026
ffd1ba7
added conversion from rads to motor rotations to setPosition (in hard…
leokalbteague-cloud Jan 25, 2026
79250ac
double supplier update
arcadeArchitect Jan 25, 2026
8c80c60
fix logging
arcadeArchitect Jan 25, 2026
4ff4ff4
fixed default setGoalState only set ClimbState to Stow
maiKuneho Jan 25, 2026
01e0b37
Merge branch '18-basic-climb' of https://github.com/Team5924/GoldenGa…
maiKuneho Jan 25, 2026
06091cf
fixed Climb State Label in RobotState to be consistent
maiKuneho Jan 25, 2026
a1e2701
Merge branch 'main' into 18-basic-climb
maiKuneho Jan 25, 2026
0be7464
Merge branch 'main' into 18-basic-climb
rice-cooker1 Jan 28, 2026
80aacef
fixed constants bug - code bui;ds now
michaelwillson415 Jan 31, 2026
61a3246
fixed IO inputs and Autolog
ricecooker0 Jan 31, 2026
2c65b9d
Merge remote-tracking branch 'origin/main' into 18-basic-climb
ricecooker0 Jan 31, 2026
54a48b8
Fixed duplicate climb constants and useless constants
ricecooker0 Feb 6, 2026
6f9623c
implement automatic voltage application in the periodic() method whe…
ricecooker0 Feb 6, 2026
d729b76
added .toString and io.setPosition(goalState.rads.getAsDouble());
ricecooker0 Feb 6, 2026
d0dae3c
Merge pull request #47 from Team5924/main
arcadeArchitect Feb 13, 2026
5318cc9
Integrate CANcoder for climb motor feedback
thartnett27-sudo Feb 13, 2026
94c3921
fixed ONE merging conflict in RobotState.java
astrobot-coder Feb 15, 2026
19a88be
fixed duplicate constructers, code will build now
michaelwillson415 Feb 18, 2026
ae56d9b
climb beam break implementation
michaelwillson415 Feb 18, 2026
e081e9b
nitpick fixes
michaelwillson415 Feb 18, 2026
32ef32e
updated to just one beambreak
michaelwillson415 Feb 18, 2026
db422e1
implemented candoder
michaelwillson415 Feb 21, 2026
4c4901e
implemented PID
michaelwillson415 Feb 21, 2026
b39149d
fixed pid updating
michaelwillson415 Feb 21, 2026
b17c61a
added cancoder feedback
michaelwillson415 Feb 21, 2026
b2c5e81
updated constants and configs
michaelwillson415 Feb 21, 2026
e9340d9
updated configs and cancoder
michaelwillson415 Feb 21, 2026
3909a28
coderabbit fixes
michaelwillson415 Feb 21, 2026
cc7aaf5
fixed units
michaelwillson415 Feb 21, 2026
6e497b9
updated inputs
michaelwillson415 Feb 21, 2026
ba91e8f
Merge branch 'main' of https://github.com/Team5924/GoldenGateRobotics…
michaelwillson415 Feb 21, 2026
7f9416c
nitpick fixes
michaelwillson415 Feb 22, 2026
99958f9
nitpick fixes
michaelwillson415 Feb 22, 2026
d1f3275
nitpick fixes again
michaelwillson415 Feb 22, 2026
6eb6fd6
added todos
michaelwillson415 Feb 27, 2026
e0dc065
Merge https://github.com/Team5924/GoldenGateRobotics2026 into 18-basi…
michaelwillson415 Feb 27, 2026
3e39ec9
merge conflicts
michaelwillson415 Feb 27, 2026
6e3eed0
fixed stuff and configs and handle curent state
michaelwillson415 Feb 28, 2026
a5dc6b4
Merge branch 'main' of https://github.com/Team5924/GoldenGateRobotics…
michaelwillson415 Feb 28, 2026
2b31654
implemented motion magic and fixed inputs
michaelwillson415 Feb 28, 2026
4cb8d0d
implemented distance to radian conversion
michaelwillson415 Feb 28, 2026
6ef2020
fixes to distance
michaelwillson415 Feb 28, 2026
bf7e3ea
nitpick fixes
michaelwillson415 Mar 1, 2026
3a2406b
fixed off mode
michaelwillson415 Mar 1, 2026
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
68 changes: 64 additions & 4 deletions src/main/java/org/team5924/frc2026/Constants.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*

/*
* Constants.java
*/
*/

/*
* Copyright (C) 2025-2026 Team 5924 - Golden Gate Robotics and/or its affiliates.
Expand Down Expand Up @@ -529,8 +530,7 @@ public final class TurretRight {
new MotorOutputConfigs()
.withInverted(InvertedValue.Clockwise_Positive)
.withNeutralMode(NeutralModeValue.Brake));

public static final OpenLoopRampsConfigs OPEN_LOOP_RAMPS_CONFIGS =
public static final OpenLoopRampsConfigs OPEN_LOOP_RAMPS_CONFIGS =
new OpenLoopRampsConfigs()
.withDutyCycleOpenLoopRampPeriod(0.02)
.withTorqueOpenLoopRampPeriod(0.02)
Expand Down Expand Up @@ -566,4 +566,64 @@ public final class TurretRight {
.withSensorDirection(SensorDirectionValue.Clockwise_Positive);
}

public final class Climb { // TODO: update these values
Comment thread
michaelwillson415 marked this conversation as resolved.
public static final int CAN_ID = 60;
public static final String BUS = "rio";
public static final double MOTOR_TO_CANCODER = (7.0 / 1.0); // TODO: Update Reductions and add hook to reduction
public static final double CANCODER_TO_MECHANISM = (7.0 / 1.0);
public static final double MOTOR_TO_MECHANISM = MOTOR_TO_CANCODER * CANCODER_TO_MECHANISM;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll have to add more constants here for converting btw. distance/rads of the boat hook roll
these will include the starting radius of the roll, boat hook diameter (thickness), maybe more...

public static final double SIM_MOI = 0.001;

public static final double MIN_POSITION_MULTI = 0.8; // rotations
public static final double MAX_POSITION_MULTI = 0.8; // rotations

public static final double MIN_POSITION_RADS = -Math.PI * MIN_POSITION_MULTI;
public static final double MAX_POSITION_RADS = Math.PI * MAX_POSITION_MULTI;
Comment thread
michaelwillson415 marked this conversation as resolved.
Outdated


public static final double EPSILON_RADS = Units.degreesToRadians(2.0);
public static final double JOYSTICK_DEADZONE = 0.05;

public static final double STATE_TIMEOUT = 5.0;

public static final int CANCODER_ID = 0; // TODO: update id
public static final double CANCODER_ABSOLUTE_OFFSET = 0.0;

public static final TalonFXConfiguration CONFIG =
new TalonFXConfiguration()
.withCurrentLimits(
new CurrentLimitsConfigs()
.withSupplyCurrentLimit(60)
.withStatorCurrentLimit(60))
.withMotorOutput(
new MotorOutputConfigs()
.withInverted(InvertedValue.CounterClockwise_Positive)
.withNeutralMode(NeutralModeValue.Brake));
Comment thread
michaelwillson415 marked this conversation as resolved.

public static final OpenLoopRampsConfigs OPEN_LOOP_RAMPS_CONFIGS =
new OpenLoopRampsConfigs()
.withDutyCycleOpenLoopRampPeriod(0.02)
.withTorqueOpenLoopRampPeriod(0.02)
.withVoltageOpenLoopRampPeriod(0.02);

public static final ClosedLoopRampsConfigs CLOSED_LOOP_RAMPS_CONFIGS =
new ClosedLoopRampsConfigs()
.withDutyCycleClosedLoopRampPeriod(0.02)
.withTorqueClosedLoopRampPeriod(0.02)
.withVoltageClosedLoopRampPeriod(0.02);

Comment thread
arcadeArchitect marked this conversation as resolved.
public static final FeedbackConfigs FEEDBACK_CONFIGS =
new FeedbackConfigs()
.withFeedbackRemoteSensorID(CANCODER_ID)
.withFeedbackRotorOffset(CANCODER_ABSOLUTE_OFFSET)
.withSensorToMechanismRatio(CANCODER_TO_MECHANISM)
.withRotorToSensorRatio(MOTOR_TO_CANCODER)
.withFeedbackSensorSource(FeedbackSensorSourceValue.FusedCANcoder);

Comment thread
michaelwillson415 marked this conversation as resolved.
public static final MagnetSensorConfigs CANCODER_CONFIG =
new MagnetSensorConfigs()
.withMagnetOffset(1.0 * CANCODER_ABSOLUTE_OFFSET)
.withAbsoluteSensorDiscontinuityPoint(0.5)
Comment thread
michaelwillson415 marked this conversation as resolved.
Outdated
.withSensorDirection(SensorDirectionValue.Clockwise_Positive);
Comment thread
michaelwillson415 marked this conversation as resolved.
}
}
3 changes: 3 additions & 0 deletions src/main/java/org/team5924/frc2026/RobotState.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.littletonrobotics.junction.AutoLogOutput;
import org.littletonrobotics.junction.Logger;
import org.team5924.frc2026.subsystems.SuperShooter.ShooterState;
import org.team5924.frc2026.subsystems.climb.Climb.ClimbState;
import org.team5924.frc2026.subsystems.pivots.shooterHood.ShooterHood.ShooterHoodState;
import org.team5924.frc2026.subsystems.rollers.hopper.Hopper.HopperState;
import org.team5924.frc2026.subsystems.rollers.indexer.Indexer.IndexerState;
Expand Down Expand Up @@ -66,6 +67,8 @@ public void resetPose(Pose2d pose) {

/* ### Intake ### */
@Getter @Setter private IntakeState intakeState = IntakeState.OFF;
/* ### Climb ### */
@Getter @Setter private ClimbState climbState = ClimbState.STOW;

/* ### Hopper ### */
@Getter @Setter private HopperState hopperState = HopperState.OFF;
Expand Down
157 changes: 157 additions & 0 deletions src/main/java/org/team5924/frc2026/subsystems/climb/Climb.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Climb.java
*/

/*
* Copyright (C) 2025-2026 Team 5924 - Golden Gate Robotics and/or its affiliates.
*
* This file, and the associated project, are offered under the GNU General
* Public License v3.0. A copy of this license can be found in LICENSE.md
* at the root of this project.
*
* If this file has been separated from the original project, you should have
* received a copy of the GNU General Public License along with it.
* If you did not, see <https://www.gnu.org/licenses>.
*/

package org.team5924.frc2026.subsystems.climb;

import edu.wpi.first.wpilibj.Alert;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import java.util.function.DoubleSupplier;
import lombok.Getter;
import lombok.Setter;

import org.littletonrobotics.junction.Logger;
import org.team5924.frc2026.Constants;
import org.team5924.frc2026.RobotState;
import org.team5924.frc2026.subsystems.sensors.BeamBreakIO;
import org.team5924.frc2026.subsystems.sensors.BeamBreakIOInputsAutoLogged;
import org.team5924.frc2026.subsystems.turret.Turret.TurretState;
import org.team5924.frc2026.util.Elastic;
import org.team5924.frc2026.util.Elastic.Notification;
import org.team5924.frc2026.util.Elastic.Notification.NotificationLevel;
import org.team5924.frc2026.util.EqualsUtil;
import org.team5924.frc2026.util.LoggedTunableNumber;

public class Climb extends SubsystemBase {

private final ClimbIO io;
private final ClimbIOInputsAutoLogged inputs = new ClimbIOInputsAutoLogged();

@Setter private double input;

public enum ClimbState { // TODO: Update climb level values - distance not rads!!!
STOW(new LoggedTunableNumber("Climb/Stow", 0)),
OFF(() -> 0.0),
LEVEL_ONE(new LoggedTunableNumber("Climb/LevelOne", 0)),
LEVEL_TWO(new LoggedTunableNumber("Climb/LevelTwo", 0)),
LEVEL_THREE(new LoggedTunableNumber("Climb/LevelThree", 0)),
CLIMB_DOWN(new LoggedTunableNumber("Climb/ClimbDown", 0)),
DEPLOY(new LoggedTunableNumber("Climb/Deploy", 0)),
DROP(new LoggedTunableNumber("Climb/Drop", 0)),
Comment thread
michaelwillson415 marked this conversation as resolved.
MOVING(() -> 0.0),
// voltage at which the climb subsystem motor moves when controlled by the operator
MANUAL(new LoggedTunableNumber("Climb/OperatorVoltage", 4.5));

// TODO: add distance to rads method

@Getter private final DoubleSupplier rads;

ClimbState(DoubleSupplier rads) {
this.rads = rads;
}
}

@Getter private ClimbState goalState;

private final Alert climbMotorDisconnected;
private final Notification climbMotorDisconnectedNotification;
private boolean wasClimbMotorConnected = true;

private double lastStateChange = 0.0;

// Climb Beam Break
private final BeamBreakIO beamBreakIO;
private final BeamBreakIOInputsAutoLogged beamBreakInputs = new BeamBreakIOInputsAutoLogged();

public Climb(ClimbIO io, BeamBreakIO beamBreakIO) {
this.io = io;
this.goalState = ClimbState.STOW;
this.climbMotorDisconnected =
new Alert("Climb System Motor Disconnected!", Alert.AlertType.kWarning);
this.climbMotorDisconnectedNotification =
new Notification(NotificationLevel.WARNING, "Climb System Motor Disconnected", "");
this.beamBreakIO = beamBreakIO;
}

@Override
public void periodic() {
io.periodicUpdates();
io.updateInputs(inputs);
beamBreakIO.updateInputs(beamBreakInputs);
Logger.processInputs("Climb", inputs);
Logger.processInputs("Climb/BeamBreak", beamBreakInputs);

Logger.recordOutput("Climb/GoalState", goalState.toString());
Logger.recordOutput("Climb/CurrentState", RobotState.getInstance().getClimbState().toString());
Logger.recordOutput("Climb/TargetRads", goalState.rads.getAsDouble());

climbMotorDisconnected.set(!inputs.climbMotorConnected);

handleCurrentState();

if (!inputs.climbMotorConnected && wasClimbMotorConnected) {
Elastic.sendNotification(climbMotorDisconnectedNotification);
}

wasClimbMotorConnected = inputs.climbMotorConnected;
}

public boolean isAtSetpoint() {
return RobotState.getTime() - lastStateChange < Constants.Climb.STATE_TIMEOUT
|| EqualsUtil.epsilonEquals(
inputs.setpointRads, inputs.climbPositionRads, Constants.Climb.EPSILON_RADS);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

private void handleCurrentState() {
switch (RobotState.getInstance().getClimbState()) {
case MOVING -> {
if (isAtSetpoint()) RobotState.getInstance().setClimbState(goalState);
}
case MANUAL -> handleManualState();
case OFF -> io.stop();
default -> io.setPosition(goalState.rads.getAsDouble());
}
Comment thread
michaelwillson415 marked this conversation as resolved.
}

private void handleManualState() {
if (!goalState.equals(TurretState.MANUAL)) return;

Comment thread
michaelwillson415 marked this conversation as resolved.
if (Math.abs(input) <= Constants.Climb.JOYSTICK_DEADZONE) {
io.runVolts(0);
return;
}

io.runVolts(ClimbState.MANUAL.getRads().getAsDouble() * input);
}

public void setGoalState(ClimbState goalState) {
this.goalState = goalState;
switch (goalState) {
case MANUAL:
RobotState.getInstance().setClimbState(ClimbState.MANUAL);
break;
case MOVING:
DriverStation.reportError(
"Climb: MOVING is an invalid goal state; it is a transition state!!", null);
break;
default:
RobotState.getInstance().setClimbState(goalState);
break;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
michaelwillson415 marked this conversation as resolved.
}

lastStateChange = RobotState.getTime();
Comment thread
michaelwillson415 marked this conversation as resolved.
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
64 changes: 64 additions & 0 deletions src/main/java/org/team5924/frc2026/subsystems/climb/ClimbIO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* ClimbIO.java
*/

/*
* Copyright (C) 2025-2026 Team 5924 - Golden Gate Robotics and/or its affiliates.
*
* This file, and the associated project, are offered under the GNU General
* Public License v3.0. A copy of this license can be found in LICENSE.md
* at the root of this project.
*
* If this file has been separated from the original project, you should have
* received a copy of the GNU General Public License along with it.
* If you did not, see <https://www.gnu.org/licenses>.
*/

package org.team5924.frc2026.subsystems.climb;

import org.littletonrobotics.junction.AutoLog;

public interface ClimbIO {
@AutoLog
public static class ClimbIOInputs {
public boolean climbMotorConnected = true;
public double climbPositionRads = 0.0;
public double climbPositionCancoder = 0.0;
public double climbVelocityRadsPerSec = 0.0;
public double climbAppliedVoltage = 0.0;
public double climbSupplyCurrentAmps = 0.0;
public double climbTorqueCurrentAmps = 0.0;
public double climbTempCelsius = 0.0;

public double setpointRads = 0.0;
public double acceleration = 0.0;

public boolean cancoderConnected = true;
public double cancoderAbsolutePosition = 0.0;
public double cancoderVelocity = 0.0;
public double cancoderSupplyVoltage = 0.0;
public double cancoderPositionRotations = 0.0;
}

/**
* Updates the inputs object with the latest data from hardware
*
* @param inputs Inputs to update
*/
public default void updateInputs(ClimbIOInputs inputs) {}

/** Updates that are be called in climb periodic */
public default void periodicUpdates() {}

/**
* Sets the subsystem motor to the specified voltage
*
* @param volts number of volts
*/
public default void runVolts(double volts) {}

public default void setPosition(double rads) {}

/** stops the motor */
default void stop() {}
}
Loading