Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
217cf9f
Basically blank commit
SCool62 Jan 15, 2026
d6625a7
Untrack the changed files
SCool62 Jan 15, 2026
c4abb0b
Re-track them
SCool62 Jan 15, 2026
e8d2790
Merge main
SCool62 Jan 15, 2026
bfeb2a7
Cherry pick the merge
SCool62 Jan 15, 2026
2f90f5b
run spotless
SCool62 Jan 15, 2026
301b004
Merge branch 'main' into feature/alpha-state-machine
SCool62 Jan 17, 2026
f2b8d19
Delete placeholder subsystems
SCool62 Jan 17, 2026
a1328e6
Initial integration
SCool62 Jan 17, 2026
966d6ae
More fleshed out feeding
SCool62 Jan 17, 2026
af07565
Make stuff somewhat simmable
SCool62 Jan 17, 2026
3cf7bc0
Sim launches now
SCool62 Jan 17, 2026
e331e90
State transitions work in sim
SCool62 Jan 17, 2026
b6a23de
Talked to Cassie about button bindings
SCool62 Jan 17, 2026
56d8006
Add more transitions for flow state at cassies request
SCool62 Jan 17, 2026
c0ec15f
Merge branch 'subsystem/shooter-flywheel' into feature/alpha-state-ma…
SCool62 Jan 17, 2026
0d9371b
Implement commands for shooter subsystem
SCool62 Jan 17, 2026
3afa805
Sim constants from CAD
SCool62 Jan 17, 2026
e7e0ed5
Spotless
SCool62 Jan 17, 2026
7e78f43
Tune flywheel velocity pid in sim
SCool62 Jan 17, 2026
9d214c9
Tune hood pid in sim
SCool62 Jan 17, 2026
7811295
Rename hood to shooter in robot.java
SCool62 Jan 17, 2026
8f035b8
CAN ids per [#19](https://github.com/HighlanderRobotics/Rebuilt/pull/19)
SCool62 Jan 17, 2026
1bf669a
Merge branch 'main' into feature/alpha-state-machine
SCool62 Jan 19, 2026
9a58a76
Cleanup
SCool62 Jan 19, 2026
9eccde9
Integrate kicker motor
SCool62 Jan 19, 2026
5135ed5
Requested small changes
SCool62 Jan 19, 2026
d6834eb
Remove IDLE -> FLOW transitions
SCool62 Jan 19, 2026
7c2bf0c
Add spin up state
SCool62 Jan 19, 2026
0f7002e
Spotless
SCool62 Jan 19, 2026
9ee8413
Bind commands
SCool62 Jan 19, 2026
453cae1
Spotless
SCool62 Jan 19, 2026
e5d91be
More requested changes
SCool62 Jan 19, 2026
3625d67
Update state machine flowchart
SCool62 Jan 19, 2026
b70a6ef
Spotless
SCool62 Jan 19, 2026
d10a376
Make SPIN_UP -> shoot not require a button (automatic switch to avoid…
SCool62 Jan 19, 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
8 changes: 6 additions & 2 deletions notes/superstructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ IDLE <--> |intakeReq + intakeEmpty| INTAKE

READY <--> |intakeReq + empty| INTAKE

READY --> |feedReq| FEED
READY --> |feedReq| SPIN_UP_FEED

READY --> |scoreReq| SCORE
READY --> |scoreReq| SPIN_UP_SCORE

SPIN_UP_FEED --> |atVelocity| FEED

SPIN_UP_SCORE --> |atVelocity| SCORE


FEED --> |flowReq| FEED_FLOW
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/frc/robot/Autos.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public class Autos {
// mehhhhhhh
private static boolean autoPreScore;
private static boolean autoScore;
private static boolean autoIntakeCoral;
private static boolean autoIntake;
private static boolean autoFeed;

// private static boolean autoIntakeAlgae;

Expand All @@ -37,9 +38,12 @@ public class Autos {
public static Trigger autoScoreReq =
new Trigger(() -> autoScore).and(DriverStation::isAutonomous);

@AutoLogOutput(key = "Superstructure/Auto Coral Intake Request")
public static Trigger autoIntakeCoralReq =
new Trigger(() -> autoIntakeCoral).and(DriverStation::isAutonomous);
@AutoLogOutput(key = "Superstructure/Auto Intake Request")
public static Trigger autoIntakeReq =
new Trigger(() -> autoIntake).and(DriverStation::isAutonomous);

@AutoLogOutput(key = "Superstructure/Auto Feed Request")
public static Trigger autoFeedReq = new Trigger(() -> autoFeed).and(DriverStation::isAutonomous);

public enum PathEndType {
PLACEHOLDER;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/frc/robot/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ public enum RobotType {
@AutoLogOutput(key = "Robot/Zeroing Request")
private Trigger zeroingReq = driver.b();

private final Superstructure superstructure = new Superstructure(swerve, driver, operator);
private final Superstructure superstructure =
new Superstructure(swerve, indexer, intake, shooter, driver, operator);

private final Autos autos;
private Optional<Alliance> lastAlliance = Optional.empty();
Expand Down
201 changes: 188 additions & 13 deletions src/main/java/frc/robot/Superstructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,29 @@
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.Commands;
import edu.wpi.first.wpilibj2.command.button.Trigger;
import frc.robot.subsystems.indexer.IndexerSubsystem;
import frc.robot.subsystems.intake.IntakeSubsystem;
import frc.robot.subsystems.shooter.ShooterSubsystem;
import frc.robot.subsystems.swerve.SwerveSubsystem;
import frc.robot.utils.CommandXboxControllerSubsystem;
import frc.robot.utils.FieldUtils.FeedTargets;
import org.littletonrobotics.junction.AutoLogOutput;
import org.littletonrobotics.junction.Logger;

public class Superstructure {

/**
* We should have a state for every single "pose" the robot will hit. See this document for
* screenshots of the robot in each state. There are also named positions in cad for each state.
*/
/** We should have a state for every single action the robot will perform. */
public enum SuperState {
IDLE();
IDLE,
INTAKE,
READY,
SPIN_UP_FEED,
FEED,
FEED_FLOW,
SPIN_UP_SCORE,
SCORE,
SCORE_FLOW,
SPIT;
public final Trigger trigger;

private SuperState() {
Expand All @@ -41,38 +51,195 @@ public Trigger getTrigger() {
private Timer stateTimer = new Timer();

private final SwerveSubsystem swerve;
private final IndexerSubsystem indexer;
private final IntakeSubsystem intake;
private final ShooterSubsystem shooter;
private final CommandXboxControllerSubsystem driver;
private final CommandXboxControllerSubsystem operator;

// Declare triggers
@AutoLogOutput(key = "Superstructure/Pre Score Request")
public Trigger preScoreReq;

@AutoLogOutput(key = "Superstructure/Score Request")
public Trigger scoreReq;
private Trigger scoreReq;

@AutoLogOutput(key = "Superstructure/Intake Request")
private Trigger intakeReq;

@AutoLogOutput(key = "Superstructure/Feed Request")
private Trigger feedReq;

@AutoLogOutput(key = "Superstructure/Flowstate Request")
private Trigger flowReq;
Copy link
Member

Choose a reason for hiding this comment

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

vivi is working on the flow stuff btw which i'll merge after this


@AutoLogOutput(key = "Superstructure/Anti Jam Req")
private Trigger antiJamReq;

@AutoLogOutput(key = "Superstructure/Is Full")
private Trigger isFull;

@AutoLogOutput(key = "Superstructure/Is Empty")
private Trigger isEmpty;

private boolean shouldFeed = false;

// @AutoLogOutput(key = "Superstructure/At Extension?")
// public Trigger atExtensionTrigger = new Trigger(this::atExtension).or(Robot::isSimulation);

/** Creates a new Superstructure. */
public Superstructure(
SwerveSubsystem swerve,
IndexerSubsystem indexer,
IntakeSubsystem intake,
ShooterSubsystem shooter,
CommandXboxControllerSubsystem driver,
CommandXboxControllerSubsystem operator) {
this.swerve = swerve;
this.indexer = indexer;
this.intake = intake;
this.shooter = shooter;
this.driver = driver;
this.operator = operator;

addTriggers();
addTransitions();
addCommands();

stateTimer.start();
}

private void addTriggers() {
preScoreReq = driver.rightTrigger().or(Autos.autoPreScoreReq);
// Toggles for feeding
operator.leftBumper().onTrue(Commands.runOnce(() -> shouldFeed = true));
operator.rightBumper().onTrue(Commands.runOnce(() -> shouldFeed = false));

scoreReq =
driver
.rightTrigger()
.and(DriverStation::isTeleop)
.and(() -> shouldFeed == false)
.or(Autos.autoScoreReq); // Maybe should include if its our turn?

intakeReq = driver.leftTrigger().and(DriverStation::isTeleop).or(Autos.autoIntakeReq);

feedReq =
driver
.rightBumper()
.and(DriverStation::isTeleop)
.and(() -> shouldFeed == true)
.or(Autos.autoFeedReq);

flowReq = driver.leftTrigger().and(driver.rightTrigger());

antiJamReq = driver.a().or(operator.a());

isFull = new Trigger(indexer::isFull);

isEmpty = new Trigger(indexer::isEmpty);
}

private void addTransitions() {
bindTransition(SuperState.IDLE, SuperState.INTAKE, intakeReq);

bindTransition(SuperState.INTAKE, SuperState.IDLE, intakeReq.negate().and(isEmpty));

bindTransition(
SuperState.INTAKE, SuperState.READY, (intakeReq.negate().and(isEmpty.negate())).or(isFull));

bindTransition(SuperState.INTAKE, SuperState.SPIN_UP_FEED, feedReq);

bindTransition(SuperState.READY, SuperState.INTAKE, intakeReq.and(isFull.negate()));

bindTransition(SuperState.READY, SuperState.SPIN_UP_SCORE, scoreReq);

bindTransition(
SuperState.SPIN_UP_SCORE,
SuperState.SCORE,
new Trigger(shooter::atFlywheelVelocitySetpoint));

bindTransition(
SuperState.SPIN_UP_FEED, SuperState.FEED, new Trigger(shooter::atFlywheelVelocitySetpoint));

bindTransition(SuperState.FEED, SuperState.IDLE, isEmpty);

bindTransition(SuperState.SCORE, SuperState.IDLE, isEmpty);

scoreReq = driver.rightTrigger().negate().and(DriverStation::isTeleop).or(Autos.autoScoreReq);
// FEED_FLOW transitions
{
bindTransition(SuperState.FEED, SuperState.FEED_FLOW, flowReq);

bindTransition(SuperState.FEED_FLOW, SuperState.FEED, flowReq.negate().and(feedReq));

bindTransition(
SuperState.FEED_FLOW, SuperState.READY, flowReq.negate().and(isEmpty.negate()));

// No so sure about the end condition here.
bindTransition(SuperState.FEED_FLOW, SuperState.IDLE, flowReq.negate().and(isEmpty));
}

// SCORE_FLOW transitions
{
bindTransition(SuperState.SCORE, SuperState.SCORE_FLOW, flowReq);

bindTransition(SuperState.SCORE_FLOW, SuperState.SCORE, flowReq.negate().and(scoreReq));

bindTransition(
SuperState.SCORE_FLOW, SuperState.READY, flowReq.negate().and(isEmpty.negate()));

// No so sure about the end condition here.
bindTransition(SuperState.SCORE_FLOW, SuperState.IDLE, flowReq.negate().and(isEmpty));
}

// Transition from any state to SPIT for anti jamming
antiJamReq.onTrue(changeStateTo(SuperState.SPIT));

bindTransition(SuperState.SPIT, SuperState.IDLE, antiJamReq.negate());
}

private void addCommands() {
bindCommands(
SuperState.IDLE,
intake.rest(),
indexer.rest(),
shooter.rest()); // Maybe the indexer should be indexing?

bindCommands(SuperState.INTAKE, intake.intake(), indexer.index(), shooter.rest());

bindCommands(
SuperState.READY,
intake.rest(),
indexer.index(),
shooter.rest()); // Maybe index at slower speed?

bindCommands(
SuperState.SPIN_UP_SCORE, intake.rest(), indexer.rest(), shooter.shoot(swerve::getPose));

bindCommands(
SuperState.SPIN_UP_FEED,
intake.rest(),
indexer.rest(),
shooter.feed(
swerve::getPose, () -> FeedTargets.BLUE_BACK_RIGHT.getPose())); // TODO: SELECTION LOGIC

bindCommands(
SuperState.SCORE, intake.rest(), indexer.indexToShoot(), shooter.shoot(swerve::getPose));

bindCommands(
SuperState.SCORE_FLOW, intake.intake(), indexer.index(), shooter.shoot(swerve::getPose));

bindCommands(
SuperState.FEED,
intake.rest(),
indexer.index(),
shooter.feed(
swerve::getPose,
() -> FeedTargets.BLUE_BACK_RIGHT.getPose())); // TODO: ADD SOME SELECTION LOGIC

bindCommands(
SuperState.FEED_FLOW,
intake.intake(),
indexer.index(),
shooter.feed(swerve::getPose, () -> FeedTargets.BLUE_BACK_RIGHT.getPose()));

bindCommands(SuperState.SPIT, intake.outake(), indexer.outtake(), shooter.spit());
}

public void periodic() {
Expand Down Expand Up @@ -105,6 +272,16 @@ private void bindTransition(SuperState start, SuperState end, Trigger trigger, C
trigger.and(start.getTrigger()).onTrue(Commands.parallel(changeStateTo(end), cmd));
}

/**
* Runs the passed in command(s) in parallel when the superstructure is in the passed in state
*
* @param state
* @param commands
*/
private void bindCommands(SuperState state, Command... commands) {
state.getTrigger().whileTrue(Commands.parallel(commands));
}

// public boolean atExtension(SuperState state) {
// }

Expand All @@ -130,8 +307,6 @@ private void setSubstates() {}
// public Command transitionAfterZeroing() {
// }

private void addTransitions() {}

/**
* <b>Only for setting initial state at the beginning of auto</b>
*
Expand Down
22 changes: 12 additions & 10 deletions src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,6 @@ public Command stopKicker() {
public Command shoot() {
return this.run(() -> kickerIO.setRollerVoltage(0));
}
;

public boolean isFull(boolean firstBeamBreak, boolean secondBeamBreak) {
if (firstBeamBreak && secondBeamBreak) {
return true;
} else {
return false;
}
}

public boolean isEmpty() {
return !firstCANRangeInputs.isDetected && !secondCANRangeInputs.isDetected;
Expand All @@ -87,20 +78,31 @@ public Command index() {
return this.run(
() -> {
indexRollerIO.setRollerVoltage(5);
kickerIO.setRollerVoltage(-5);
});
}

public Command score() {
public Command indexToShoot() {
return this.run(
() -> {
indexRollerIO.setRollerVoltage(10);
kickerIO.setRollerVoltage(5);
});
}

public Command outtake() {
return this.run(
() -> {
indexRollerIO.setRollerVoltage(-5);
kickerIO.setRollerVoltage(-5);
});
}

public Command rest() {
return this.run(
() -> {
indexRollerIO.setRollerVoltage(0.0);
kickerIO.setRollerVoltage(0.0);
});
}

Expand Down
Loading