Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 29 additions & 2 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.InstantCommand;
import edu.wpi.first.wpilibj2.command.RunCommand;
import edu.wpi.first.wpilibj2.command.button.CommandJoystick;
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
import edu.wpi.first.wpilibj2.command.button.Trigger;
Expand All @@ -18,6 +19,7 @@
import frc.robot.commands.drive.FakeVision;
import frc.robot.commands.intake.SpinIntake;
import frc.robot.commands.angler.AimAngler;
import frc.robot.commands.angler.RunAnglerToReverseLimit;
import frc.robot.commands.shooter.SetShootingState;
import frc.robot.constants.Constants;
import frc.robot.subsystems.AnglerSubsystem;
Expand Down Expand Up @@ -189,22 +191,47 @@ public void putShuffleboardCommands() {

SmartDashboard.putNumber("angler/TargetRotations", Constants.ANGLER_HOME_ROTATIONS);

SmartDashboard.putNumber("angler/TargetAngle", 0);

SmartDashboard.putData(
"angler/Set Position",
new InstantCommand(() -> anglerSubsystem.setPosition(
SmartDashboard.getNumber("angler/TargetRotations", 0.0))));

SmartDashboard.putData(
"angler/Set Angle",
new InstantCommand(() -> anglerSubsystem.setAngle(
SmartDashboard.getNumber("angler/TargetAngle", 0.0))));

SmartDashboard.putData(
"angler/Go Home",
new InstantCommand(() -> anglerSubsystem.setPosition(Constants.ANGLER_HOME_ROTATIONS)));

SmartDashboard.putData(
"angler/Go Low",
new InstantCommand(() -> anglerSubsystem.setPosition(Constants.ANGLER_LOW_ROTATIONS)));
new InstantCommand(() -> anglerSubsystem.setPosition(Constants.ANGLER_ENCODER_LOW)));

SmartDashboard.putData(
"angler/Go High",
new InstantCommand(() -> anglerSubsystem.setPosition(Constants.ANGLER_HIGH_ROTATIONS)));
new InstantCommand(() -> anglerSubsystem.setPosition(Constants.ANGLER_ENCODER_HIGH)));

SmartDashboard.putData(
"angler/Run To Fwd Limit",
new RunCommand(anglerSubsystem::runToForwardLimit, anglerSubsystem)
.until(anglerSubsystem::isAtForwardLimit));

SmartDashboard.putData(
"angler/Run To Rev Limit",
new RunCommand(anglerSubsystem::runToReverseLimit, anglerSubsystem)
.until(anglerSubsystem::isAtReverseLimit));

SmartDashboard.putData(
"angler/Reset Encoder",
new InstantCommand(anglerSubsystem::resetEncoderToZero));

SmartDashboard.putData(
"angler/Home Rev (Reset)",
new RunAnglerToReverseLimit(anglerSubsystem));

SmartDashboard.putData(
"Spin Intake",
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/frc/robot/commands/angler/AimAngler.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ public class AimAngler extends LoggableCommand {
HUB_TARGET_POSE,
0.00,
6,
Constants.ANGLER_LOW_ROTATIONS,
Constants.ANGLER_HIGH_ROTATIONS);
Constants.ANGLER_ENCODER_LOW,
Constants.ANGLER_ENCODER_HIGH);

private static final AimConfig SHUTTLE_CONFIG = new AimConfig(
SHUTTLE_TARGET_POSE,
0,
6,
Constants.ANGLER_LOW_ROTATIONS,
Constants.ANGLER_HIGH_ROTATIONS);
Constants.ANGLER_ENCODER_LOW,
Constants.ANGLER_ENCODER_HIGH);

public AimAngler(AnglerSubsystem angler, Supplier<Pose2d> poseSupplier, ShootingState shootingState) {
this.angler = angler;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package frc.robot.commands.angler;

import frc.robot.subsystems.AnglerSubsystem;
import frc.robot.utils.logging.commands.LoggableCommand;

/**
* Runs the angler to the reverse limit switch and resets the encoder to zero.
*/
public class RunAnglerToReverseLimit extends LoggableCommand {
private final AnglerSubsystem angler;
private boolean finished = false;

public RunAnglerToReverseLimit(AnglerSubsystem angler) {
this.angler = angler;
addRequirements(angler);
}

@Override
public void initialize() {
finished = false;
}

@Override
public void execute() {
angler.runToReverseLimit();
if (angler.isAtReverseLimit()) {
angler.resetEncoderToZero();
finished = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably have a timeout of 5 seconds(?) to prevent this from hanging forever if the switch is broken

}
}

@Override
public void end(boolean interrupted) {
angler.stopMotors();
}

@Override
public boolean isFinished() {
return finished;
}
}
16 changes: 10 additions & 6 deletions src/main/java/frc/robot/constants/GameConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,18 @@ public enum Mode {
public static final int NEO_CURRENT_LIMIT = 20;

// angler (turret) PID
public static final double ANGLER_P = 0.05;
public static final double ANGLER_I = 0.0;
public static final double ANGLER_P = 0.1;
public static final double ANGLER_I = 0.000001;
public static final double ANGLER_D = 0.0;
public static final double ANGLER_FF = 0.0;
public static final double ANGLER_HOME_ROTATIONS = 0.0; //Where Angler usually is
public static final double ANGLER_LOW_ROTATIONS = -50; //Lowest position of Angler
public static final double ANGLER_HIGH_ROTATIONS = 50; //Highest position of Angler
public static final double ANGLER_FIXED_ROTATIONS = 0.1; //Fixed position of Angler in Fixed ShootState
public static final double ANGLER_HOME_ROTATIONS = 0.0;
Copy link
Contributor

Choose a reason for hiding this comment

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

These comments should not have been removed.

public static final double ANGLER_ENCODER_LOW = 0;
public static final double ANGLER_ENCODER_HIGH = 100;
public static final double ANGLER_ANGLE_LOW = 0;
public static final double ANGLER_ANGLE_HIGH = 45;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should have comments about these constants as well

public static final double ANGLER_FIXED_ROTATIONS = 0.1;
public static final double ANGLER_LIMIT_SPEED = 0.2;


//swerve config
public static final TelemetryVerbosity TELEMENTRY_VERBOSITY = TelemetryVerbosity.HIGH;
Expand Down
67 changes: 66 additions & 1 deletion src/main/java/frc/robot/subsystems/AnglerSubsystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.revrobotics.spark.config.SparkBaseConfig;
import com.revrobotics.spark.config.SparkMaxConfig;

import edu.wpi.first.math.MathUtil;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.constants.Constants;
import frc.robot.utils.logging.input.MotorLoggableInputs;
Expand Down Expand Up @@ -41,16 +42,80 @@ public void periodic() {

/**
* Gets the desired Encoder Position and uses a PID controller to get the motor there
* Planning to add a setPosition based on an angle position soon
*/
public void setPosition(double targetEncoderPosition) {
io.setPidPosition(targetEncoderPosition);
}

/**
* Gets the desired Angle Position and uses a PID controller to get the motor there
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Add comment about the units the angle is expected to be (@param...)

public void setAngle(double targetAngle) {
double targetRotations = calculateRotationsForAngle(
targetAngle,
Constants.ANGLER_ENCODER_HIGH,
Constants.ANGLER_ENCODER_LOW,
Constants.ANGLER_ANGLE_HIGH,
Constants.ANGLER_ANGLE_LOW);
setPosition(targetRotations);
}

//Range translate code with a clamp
public static double calculateRotationsForAngle(
double targetAngle,
double encoderHigh,
double encoderLow,
double angleHigh,
double angleLow) {

double multipler = (encoderHigh - encoderLow) / (angleHigh - angleLow);
double targetRotations = targetAngle * multipler - (multipler * angleHigh - encoderHigh);
return MathUtil.clamp(targetRotations, encoderLow, encoderHigh);
}

public void stopMotors() {
io.stopMotor();
}

/**
* Drive toward the forward limit switch and stop once it is pressed.
* Call this repeatedly from a command while homing.
*/
public void runToForwardLimit() {
Copy link
Contributor

Choose a reason for hiding this comment

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

The way this method is written, it is expecting to be called in a loop until the switch is hit - if it only called once, the motor will run forever (well, it will run until the limit switch is hit and the hardware stops the motor).
In this case, I think it is better to just use a "run forward" method, since you rely on the command to repeatedly check the switch and end when it is hit. Sorry if I caused you to do extra work here.
Same for the other method below.

if (io.isFwdSwitchPressed()) {
io.stopMotor();
return;
}
io.set(Math.abs(Constants.ANGLER_LIMIT_SPEED));
}

/**
* Drive toward the reverse limit switch and stop once it is pressed.
* Call this repeatedly from a command while homing.
*/
public void runToReverseLimit() {
if (io.isRevSwitchPressed()) {
io.stopMotor();
return;
}
io.set(-Math.abs(Constants.ANGLER_LIMIT_SPEED));
}

/**
* Reset the encoder position to zero.
*/
public void resetEncoderToZero() {
io.resetEncoderPosition(0.0);
}

public boolean isAtForwardLimit() {
return io.isFwdSwitchPressed();
}

public boolean isAtReverseLimit() {
return io.isRevSwitchPressed();
}

public static SparkMaxPidMotorIo createMockIo() {
return new MockSparkMaxPidMotorIo(LOGGING_NAME, MotorLoggableInputs.allMetrics());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ public void setPid(double pidP, double pidI, double pidD) {
@Override
public void setPid(double pidP, double pidI, double pidD, double iZone, double pidFF) {
}

@Override
public void resetEncoderPosition(double positionRotations) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ public void setPid(double pidP, double pidI, double pidD) {
public void setPid(double pidP, double pidI, double pidD, double iZone, double pidFF) {
pidMotor.setPid(pidP, pidI, pidD, iZone, pidFF);
}

@Override
public void resetEncoderPosition(double positionRotations) {
pidMotor.getEncoder().setPosition(positionRotations);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ public interface SparkMaxPidMotorIo extends SparkMaxIo {
*/
void setPidVelocity(double velocity);

/**
* Reset the relative encoder position.
*
* @param positionRotations the position (in rotations) to set the encoder to
*/
void resetEncoderPosition(double positionRotations);

/**
* Set new PID values for the PidMotor.
* This will replace the existing PID values with the nerw ones
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

import frc.robot.constants.Constants;
import frc.robot.subsystems.AnglerSubsystem;

public class AnglerCalculationsTest {

static final double DELTA = 0.1;

double[] angles = {0, 45, 20, -20, 60, 30};
double[] expectedRotations = {
0.0,
100.0,
44.46,
0.0,
100.0,
66.67
};

private int index;

private double calculate(double angle) {
return AnglerSubsystem.calculateRotationsForAngle(
angle,
Constants.ANGLER_ENCODER_HIGH,
Copy link
Contributor

Choose a reason for hiding this comment

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

This would break when the constants change, so you should hardcode test values that will not change with the constants to separate the test code from the real ones.

Constants.ANGLER_ENCODER_LOW,
Constants.ANGLER_ANGLE_HIGH,
Constants.ANGLER_ANGLE_LOW);
}

@Test
void angle0Test() {
index = 0;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}

@Test
void angle45Test() {
index = 1;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}

@Test
void angle20Test() {
index = 2;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}

@Test
void angleNeg20Test() {
index = 3;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}

@Test
void angle60Test() {
index = 4;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}

@Test
void angle30Test() {
index = 5;
assertEquals(expectedRotations[index], calculate(angles[index]), DELTA);
}
}