Skip to content
This repository has been archived by the owner on Jan 6, 2024. It is now read-only.

Commit

Permalink
Add initial lights subsystem implementation (#18)
Browse files Browse the repository at this point in the history
* Start lights subsystem

* Format with Spotless
  • Loading branch information
ryanknj5 authored Aug 29, 2023
1 parent f0dff8d commit 8f22ab4
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 172 deletions.
19 changes: 12 additions & 7 deletions src/main/java/frc/robot/intake/IntakeSubsystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package frc.robot.intake;

import com.revrobotics.*;

import edu.wpi.first.math.filter.LinearFilter;
import frc.robot.util.scheduling.LifecycleSubsystem;
import frc.robot.util.scheduling.SubsystemPriority;
Expand All @@ -15,12 +14,12 @@
public class IntakeSubsystem extends LifecycleSubsystem {
private final LinearFilter voltageFilter = LinearFilter.movingAverage(7);
private final LinearFilter velocityFilter = LinearFilter.movingAverage(7);
//7 is a placeholder not tuned
// 7 is a placeholder not tuned
private final CANSparkMax motor;
private final RelativeEncoder encoder;
private IntakeState goalState;
private HeldGamePiece gamePiece = HeldGamePiece.NOTHING;

public IntakeSubsystem(CANSparkMax motor) {
super(SubsystemPriority.INTAKE);
this.motor = motor;
Expand All @@ -36,7 +35,8 @@ public void setGoalState(IntakeState intakeState) {

goalState = intakeState;
}
@Override

@Override
public void robotPeriodic() {
Logger.getInstance().recordOutput("Intake/State", goalState.toString());
Logger.getInstance().recordOutput("Intake/HeldGamePiece", gamePiece.toString());
Expand Down Expand Up @@ -66,17 +66,22 @@ public void enabledPeriodic() {
// Game piece detection
double motorVelocity = velocityFilter.calculate(encoder.getVelocity());
double intakeVoltage = voltageFilter.calculate(motor.getAppliedOutput()) * 12.0;
double theoreticalSpeed = intakeVoltage * (5700.0/12.0); //Neo Max is 5700
double threshold = theoreticalSpeed * 0.5;
double theoreticalSpeed = intakeVoltage * (5700.0 / 12.0); // Neo Max is 5700
double threshold = theoreticalSpeed * 0.5;
if (motorVelocity < threshold && goalState == IntakeState.INTAKE_CONE) {
gamePiece = HeldGamePiece.CONE;
} else if (motorVelocity < threshold && goalState == IntakeState.INTAKE_CUBE) {
gamePiece = HeldGamePiece.CUBE;
} else if (motorVelocity > threshold && (goalState == IntakeState.OUTTAKE_CONE || goalState == IntakeState.OUTTAKE_CUBE)) {
} else if (motorVelocity > threshold
&& (goalState == IntakeState.OUTTAKE_CONE || goalState == IntakeState.OUTTAKE_CUBE)) {
gamePiece = HeldGamePiece.NOTHING;
}
}

public IntakeState getIntakeState() {
return goalState;
}

public boolean atGoal(IntakeState state) {
if (goalState != state) {
return false;
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/frc/robot/lights/BlinkPattern.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package frc.robot.lights;

public enum BlinkPattern {
SOLID,
BLINK_SLOW,
BLINK_FAST;
}
106 changes: 106 additions & 0 deletions src/main/java/frc/robot/lights/LightsSubsystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package frc.robot.lights;

import com.ctre.phoenix.led.CANdle;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.util.Color;
import edu.wpi.first.wpilibj.util.Color8Bit;
import frc.robot.fms.FmsSubsystem;
import frc.robot.intake.HeldGamePiece;
import frc.robot.intake.IntakeState;
import frc.robot.intake.IntakeSubsystem;
import frc.robot.managers.superstructure.SuperstructureManager;
import frc.robot.util.scheduling.LifecycleSubsystem;
import frc.robot.util.scheduling.SubsystemPriority;

public class LightsSubsystem extends LifecycleSubsystem {

private static final double FAST_BLINK_DURATION = 0.08;
private static final double SLOW_BLINK_DURATION = 0.25;

private final CANdle candle;
private final IntakeSubsystem intake;
private final SuperstructureManager superstructure;

private final Timer blinkTimer = new Timer();
private Color color = Color.kWhite;
// TODO: Copy paste blink pattern enum from other repo
private BlinkPattern blinkPattern = BlinkPattern.SOLID;

public LightsSubsystem(
CANdle candle, IntakeSubsystem intake, SuperstructureManager superstructure) {
super(SubsystemPriority.LIGHTS);
this.candle = candle;
this.intake = intake;
this.superstructure = superstructure;
}

public void enabledPeriodic() {
HeldGamePiece gamePiece = intake.getGamePiece();
IntakeState intakeMode = intake.getIntakeState();
HeldGamePiece superstructureMode = superstructure.getMode();

if (DriverStation.isDisabled()) {
if (FmsSubsystem.isRedAlliance()) {
color = Color.kRed;
blinkPattern = BlinkPattern.SOLID;
} else {
color = Color.kBlue;
blinkPattern = BlinkPattern.SOLID;
}
} else if (gamePiece == HeldGamePiece.CUBE) {
if (intakeMode == IntakeState.INTAKE_CUBE) {
color = Color.kPurple;
blinkPattern = BlinkPattern.BLINK_FAST;
} else {
color = Color.kPurple;
blinkPattern = BlinkPattern.SOLID;
}
} else if (gamePiece == HeldGamePiece.CONE) {
if (intakeMode == IntakeState.INTAKE_CONE) {
color = Color.kYellow;
blinkPattern = BlinkPattern.BLINK_FAST;
} else {
color = Color.kYellow;
blinkPattern = BlinkPattern.SOLID;
}
} else if (superstructureMode == HeldGamePiece.CUBE) {
color = Color.kPurple;
blinkPattern = BlinkPattern.BLINK_SLOW;
} else if (superstructureMode == HeldGamePiece.CONE) {
color = Color.kYellow;
blinkPattern = BlinkPattern.BLINK_SLOW;
} else {
color = Color.kWhite;
blinkPattern = BlinkPattern.SOLID;
}

Color8Bit color8Bit = new Color8Bit(color);
if (blinkPattern == BlinkPattern.SOLID) {
candle.setLEDs(color8Bit.red, color8Bit.green, color8Bit.blue);
} else {
double time = blinkTimer.get();
double onDuration = 0;
double offDuration = 0;

if (blinkPattern == BlinkPattern.BLINK_FAST) {
onDuration = FAST_BLINK_DURATION;
offDuration = FAST_BLINK_DURATION * 2;
} else if (blinkPattern == BlinkPattern.BLINK_SLOW) {
onDuration = SLOW_BLINK_DURATION;
offDuration = SLOW_BLINK_DURATION * 2;
}

if (time >= offDuration) {
blinkTimer.reset();
candle.setLEDs(0, 0, 0);
} else if (time >= onDuration) {
candle.setLEDs(color8Bit.red, color8Bit.green, color8Bit.blue);
}
}
}
}
44 changes: 28 additions & 16 deletions src/main/java/frc/robot/managers/superstructure/Positions.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,34 @@
import edu.wpi.first.math.geometry.Rotation2d;

public class Positions {
public static final SuperstructurePosition STOWED = new SuperstructurePosition(Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(0));

public static final SuperstructurePosition INTAKING_CUBE_FLOOR = new SuperstructurePosition(Rotation2d.fromDegrees(20), Rotation2d.fromDegrees(135));
public static final SuperstructurePosition INTAKING_CUBE_SHELF = new SuperstructurePosition(Rotation2d.fromDegrees(90), Rotation2d.fromDegrees(180));

public static final SuperstructurePosition CUBE_NODE_LOW = new SuperstructurePosition(Rotation2d.fromDegrees(-20), Rotation2d.fromDegrees(-135));
public static final SuperstructurePosition CUBE_NODE_MID = new SuperstructurePosition(Rotation2d.fromDegrees(-75), Rotation2d.fromDegrees(-190));
public static final SuperstructurePosition CUBE_NODE_HIGH = new SuperstructurePosition(Rotation2d.fromDegrees(-100), Rotation2d.fromDegrees(-190));

public static final SuperstructurePosition INTAKING_CONE_FLOOR = new SuperstructurePosition(Rotation2d.fromDegrees(20), Rotation2d.fromDegrees(135));
public static final SuperstructurePosition INTAKING_CONE_SHELF = new SuperstructurePosition(Rotation2d.fromDegrees(90), Rotation2d.fromDegrees(180));
public static final SuperstructurePosition INTAKING_CONE_SINGLE_SUBSTATION = new SuperstructurePosition(Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(30));

public static final SuperstructurePosition CONE_NODE_LOW = new SuperstructurePosition(Rotation2d.fromDegrees(-20), Rotation2d.fromDegrees(-135));
public static final SuperstructurePosition CONE_NODE_MID = new SuperstructurePosition(Rotation2d.fromDegrees(-75), Rotation2d.fromDegrees(-190));
public static final SuperstructurePosition CONE_NODE_HIGH = new SuperstructurePosition(Rotation2d.fromDegrees(-100), Rotation2d.fromDegrees(-190));
public static final SuperstructurePosition STOWED =
new SuperstructurePosition(Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(0));

public static final SuperstructurePosition INTAKING_CUBE_FLOOR =
new SuperstructurePosition(Rotation2d.fromDegrees(20), Rotation2d.fromDegrees(135));
public static final SuperstructurePosition INTAKING_CUBE_SHELF =
new SuperstructurePosition(Rotation2d.fromDegrees(90), Rotation2d.fromDegrees(180));

public static final SuperstructurePosition CUBE_NODE_LOW =
new SuperstructurePosition(Rotation2d.fromDegrees(-20), Rotation2d.fromDegrees(-135));
public static final SuperstructurePosition CUBE_NODE_MID =
new SuperstructurePosition(Rotation2d.fromDegrees(-75), Rotation2d.fromDegrees(-190));
public static final SuperstructurePosition CUBE_NODE_HIGH =
new SuperstructurePosition(Rotation2d.fromDegrees(-100), Rotation2d.fromDegrees(-190));

public static final SuperstructurePosition INTAKING_CONE_FLOOR =
new SuperstructurePosition(Rotation2d.fromDegrees(20), Rotation2d.fromDegrees(135));
public static final SuperstructurePosition INTAKING_CONE_SHELF =
new SuperstructurePosition(Rotation2d.fromDegrees(90), Rotation2d.fromDegrees(180));
public static final SuperstructurePosition INTAKING_CONE_SINGLE_SUBSTATION =
new SuperstructurePosition(Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(30));

public static final SuperstructurePosition CONE_NODE_LOW =
new SuperstructurePosition(Rotation2d.fromDegrees(-20), Rotation2d.fromDegrees(-135));
public static final SuperstructurePosition CONE_NODE_MID =
new SuperstructurePosition(Rotation2d.fromDegrees(-75), Rotation2d.fromDegrees(-190));
public static final SuperstructurePosition CONE_NODE_HIGH =
new SuperstructurePosition(Rotation2d.fromDegrees(-100), Rotation2d.fromDegrees(-190));

private Positions() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.Commands;
import frc.robot.intake.HeldGamePiece;
import frc.robot.intake.IntakeSubsystem;
import frc.robot.util.scheduling.LifecycleSubsystem;
import frc.robot.util.scheduling.SubsystemPriority;
Expand All @@ -17,6 +18,7 @@ public class SuperstructureManager extends LifecycleSubsystem {
private WristSubsystem wrist;
private IntakeSubsystem intake;
private SuperstructureState goalState;
private HeldGamePiece mode = HeldGamePiece.CUBE;

public SuperstructureManager(SuperstructureMotionManager motionManager, IntakeSubsystem intake) {
super(SubsystemPriority.SUPERSTRUCTURE_MANAGER);
Expand Down Expand Up @@ -48,4 +50,12 @@ public Command setStateCommand(SuperstructureState newGoalState) {
return Commands.runOnce(() -> setGoal(newGoalState))
.andThen(Commands.waitUntil(() -> atGoal(newGoalState)));
}

public void setMode(HeldGamePiece mode) {
this.mode = mode;
}

public HeldGamePiece getMode() {
return mode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public SuperstructureMotionManager(WristSubsystem shoulder, WristSubsystem wrist
}

public boolean atPosition(SuperstructurePosition position) {
return shoulder.atAngle(position.shoulderAngle)
&& wrist.atAngle(position.wristAngle);
return shoulder.atAngle(position.shoulderAngle) && wrist.atAngle(position.wristAngle);
}

public void set(SuperstructurePosition newGoalPosition) {
Expand Down
41 changes: 22 additions & 19 deletions src/main/java/frc/robot/shoulder/ShoulderSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package frc.robot.shoulder;
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

import org.littletonrobotics.junction.Logger;
package frc.robot.shoulder;

import com.revrobotics.CANSparkMax;
import com.revrobotics.CANSparkMax.ControlType;
import com.revrobotics.RelativeEncoder;
import com.revrobotics.SparkMaxPIDController;

import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.wpilibj2.command.Command;
import frc.robot.util.scheduling.LifecycleSubsystem;
import frc.robot.util.scheduling.SubsystemPriority;
import org.littletonrobotics.junction.Logger;

public class ShoulderSubsystem extends LifecycleSubsystem {
private final CANSparkMax motor;
Expand Down Expand Up @@ -43,22 +45,24 @@ public void enabledPeriodic() {
pid.setReference(goalAngle.getRotations(), ControlType.kSmartMotion);
}

@Override
public void robotPeriodic(){
Logger.getInstance().recordOutput("Shoulder/MainMotor/Velocity", encoder.getVelocity());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/Velocity", encoder.getVelocity());
Logger.getInstance().recordOutput("Shoulder/MainMotor/Angle", getWristAngle().getDegrees());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/Angle", getWristAngle().getDegrees());
Logger.getInstance().recordOutput("Shoulder/MainMotor/GoalAngle", goalAngle.getDegrees());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/GoalAngle", goalAngle.getDegrees());
Logger.getInstance().recordOutput("Shoulder/MainMotor/DutyCycleOutput", motor.getAppliedOutput());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/DutyCycleOutput", motor.getAppliedOutput());
Logger.getInstance().recordOutput("Shoulder/MainMotor/StatorCurrent", motor.getOutputCurrent());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/StatorCurrent", motor.getOutputCurrent());

}
@Override
public void robotPeriodic() {
Logger.getInstance().recordOutput("Shoulder/MainMotor/Velocity", encoder.getVelocity());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/Velocity", encoder.getVelocity());
Logger.getInstance().recordOutput("Shoulder/MainMotor/Angle", getWristAngle().getDegrees());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/Angle", getWristAngle().getDegrees());
Logger.getInstance().recordOutput("Shoulder/MainMotor/GoalAngle", goalAngle.getDegrees());
Logger.getInstance().recordOutput("Shoulder/FollowerMotor/GoalAngle", goalAngle.getDegrees());
Logger.getInstance()
.recordOutput("Shoulder/MainMotor/DutyCycleOutput", motor.getAppliedOutput());
Logger.getInstance()
.recordOutput("Shoulder/FollowerMotor/DutyCycleOutput", motor.getAppliedOutput());
Logger.getInstance().recordOutput("Shoulder/MainMotor/StatorCurrent", motor.getOutputCurrent());
Logger.getInstance()
.recordOutput("Shoulder/FollowerMotor/StatorCurrent", motor.getOutputCurrent());
}

public void set(Rotation2d angle) {
public void set(Rotation2d angle) {
goalAngle = angle;
}

Expand All @@ -78,4 +82,3 @@ private Rotation2d getWristAngle() {
return Rotation2d.fromRotations(encoder.getPosition());
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum SubsystemPriority {
LOCALIZATION(9),

FMS(0),
LIGHTS(0),
RUMBLE_CONTROLLER(0);

final int value;
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/frc/robot/wrist/WristSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package frc.robot.wrist;
import org.littletonrobotics.junction.Logger;

import com.revrobotics.CANSparkMax;
import com.revrobotics.CANSparkMax.ControlType;
import com.revrobotics.RelativeEncoder;
import com.revrobotics.SparkMaxPIDController;

import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.wpilibj2.command.Command;
import frc.robot.util.scheduling.LifecycleSubsystem;
import frc.robot.util.scheduling.SubsystemPriority;
import org.littletonrobotics.junction.Logger;

public class WristSubsystem extends LifecycleSubsystem {
private final CANSparkMax motor;
Expand Down
Loading

0 comments on commit 8f22ab4

Please sign in to comment.