Skip to content

Commit

Permalink
Merge pull request #233 from team467/stolen-joystick
Browse files Browse the repository at this point in the history
Stolen joystick
  • Loading branch information
EQMoore authored Apr 2, 2024
2 parents a28b624 + d91a686 commit 1758e2a
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 22 deletions.
33 changes: 21 additions & 12 deletions src/main/java/frc/robot/Orchestrator.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,24 @@ public Command stopFlywheel() {
* @return The command to move the arm to the correct setPoint for shooting from its current
* location.
*/
public Command alignArmSpeaker(
Supplier<Double> distance) { // TODO: Not working. Abishek, Fix this
public Command alignArmSpeaker(Supplier<Pose2d> robotPose) {
return Commands.defer(
() ->
arm.toSetpoint(
Rotation2d.fromDegrees(
(-3.1419 * (distance.get() * distance.get()))
+ (23.725 * distance.get())
- 30.103)),
() -> {
Supplier<Double> distance =
() ->
robotPose
.get()
.getTranslation()
.getDistance(
AllianceFlipUtil.apply(
FieldConstants.Speaker.centerSpeakerOpening.toTranslation2d()));
return arm.toSetpoint(
() ->
Rotation2d.fromDegrees(
(-3.1419 * (distance.get() * distance.get()))
+ (23.725 * distance.get())
- 30.103));
},
Set.of(arm));
// return Commands.defer(
// () ->
Expand All @@ -255,8 +264,8 @@ public Command alignArmSpeaker(
*
* @return The command to move the robot and the arm in preparation to shoot.
*/
public Command fullAlignSpeaker(Supplier<Double> distance) {
return Commands.sequence(turnToSpeaker(), alignArmSpeaker(distance));
public Command fullAlignSpeaker(Supplier<Pose2d> robotPose) {
return Commands.sequence(turnToSpeaker(), alignArmSpeaker(robotPose));
}

/**
Expand All @@ -265,8 +274,8 @@ public Command fullAlignSpeaker(Supplier<Double> distance) {
*
* @return The command to align both the robot and the arm, and then shoots at full power.
*/
public Command fullAlignShootSpeaker(Supplier<Double> distance) {
return Commands.sequence(fullAlignSpeaker(distance), shootBasic());
public Command fullAlignShootSpeaker(Supplier<Pose2d> robotPose) {
return Commands.sequence(fullAlignSpeaker(robotPose), shootBasic());
}

/**
Expand Down
22 changes: 12 additions & 10 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import frc.robot.commands.auto.Autos;
import frc.robot.commands.drive.DriveWithDpad;
import frc.robot.commands.drive.DriveWithJoysticks;
import frc.robot.commands.drive.StolenJoystick;
import frc.robot.subsystems.arm.Arm;
import frc.robot.subsystems.arm.ArmConstants;
import frc.robot.subsystems.arm.ArmIO;
Expand Down Expand Up @@ -265,7 +266,6 @@ private void configureButtonBindings() {
driverController
.pov(-1)
.whileFalse(new DriveWithDpad(drive, () -> driverController.getHID().getPOV()));

// stop when doing nothing
intake.setDefaultCommand(intake.stop());
indexer.setDefaultCommand(indexer.setPercent(0));
Expand Down Expand Up @@ -317,18 +317,20 @@ private void configureButtonBindings() {
// arm.toSetpoint(ArmConstants.STOW.minus(Rotation2d.fromDegrees(5))),
// Commands.waitUntil(arm::limitSwitchPressed))
// .withTimeout(2));
driverController.rightBumper().onTrue(orchestrator.turnToSpeaker());
// driverController
// .rightBumper()
// .whileTrue(
driverController
.rightBumper()
.whileTrue(
orchestrator.alignArmSpeaker(
() ->
drive
.getPose()
.getTranslation()
.getDistance(
AllianceFlipUtil.apply(
FieldConstants.Speaker.centerSpeakerOpening.toTranslation2d()))));
new StolenJoystick(
drive,
() -> -driverController.getLeftY(),
() -> -driverController.getLeftX(),
() -> drive.getPose(),
FieldConstants.Speaker.centerSpeakerOpening.toTranslation2d(),
() -> true)
.alongWith(orchestrator.alignArmSpeaker(() -> drive.getPose())));
// Click Left Bumper: Move arm to amp position
driverController.leftBumper().onTrue(orchestrator.alignArmAmp());
// Click left Trigger: Intake (until clicked again or has a note)
Expand Down
137 changes: 137 additions & 0 deletions src/main/java/frc/robot/commands/drive/StolenJoystick.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package frc.robot.commands.drive;

import edu.wpi.first.math.MathUtil;
import edu.wpi.first.math.controller.PIDController;
import edu.wpi.first.math.filter.SlewRateLimiter;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.kinematics.ChassisSpeeds;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.wpilibj2.command.Command;
import frc.lib.utils.AllianceFlipUtil;
import frc.lib.utils.GeomUtils;
import frc.lib.utils.RobotOdometry;
import frc.lib.utils.TunableNumber;
import frc.robot.Constants;
import frc.robot.subsystems.drive.Drive;
import frc.robot.subsystems.drive.DriveConstants;
import java.util.Arrays;
import java.util.function.Supplier;
import org.littletonrobotics.junction.Logger;

public class StolenJoystick extends Command {
private final Drive drive;
private final Supplier<Double> leftXSupplier;
private final Supplier<Double> leftYSupplier;
private final Supplier<Pose2d> robotOrientation;
private final Translation2d targetPosition;
private final Supplier<Boolean> robotRelativeOverride;

private static final double TIME_TO_FULL_SPEED = 0.15;
private final SlewRateLimiter leftXFilter = new SlewRateLimiter(1 / TIME_TO_FULL_SPEED);
private final SlewRateLimiter leftYFilter = new SlewRateLimiter(1 / TIME_TO_FULL_SPEED);

private TunableNumber rotationKP = new TunableNumber("StolenJoystick/KP", 2.5);
private TunableNumber rotationKD = new TunableNumber("StolenJoystick/KD", 0.0);
private final PIDController rotationPid;
private final double MAX_ANGULAR_SPEED;

public StolenJoystick(
Drive drive,
Supplier<Double> leftXSupplier,
Supplier<Double> leftYSupplier,
Supplier<Pose2d> robotOrientation,
Translation2d targetPosition,
Supplier<Boolean> robotRelativeOverride) {
this.drive = drive;
this.leftXSupplier = leftXSupplier;
this.leftYSupplier = leftYSupplier;
this.robotOrientation = robotOrientation;
this.targetPosition = targetPosition;
this.robotRelativeOverride = robotRelativeOverride;

MAX_ANGULAR_SPEED =
DriveConstants.MAX_LINEAR_SPEED
/ Arrays.stream(drive.getModuleTranslations())
.map(Translation2d::getNorm)
.max(Double::compare)
.get();

rotationPid = new PIDController(rotationKP.get(), 0.0, rotationKD.get());
rotationPid.enableContinuousInput(-Math.PI, Math.PI);
rotationPid.setTolerance(Units.degreesToRadians(4));

addRequirements(drive);
}

@Override
public void execute() {
// Update controllers if tunable numbers have changed
if (Constants.tuningMode) {
if (rotationKP.hasChanged(hashCode()) || rotationKD.hasChanged(hashCode())) {
rotationPid.setPID(rotationKP.get(), 0, rotationKD.get());
}
}

// Get values from double suppliers
double leftX = leftXFilter.calculate(leftXSupplier.get());
double leftY = leftYFilter.calculate(leftYSupplier.get());

// Get direction and magnitude of linear axes
double linearMagnitude = Math.hypot(leftX, leftY);
Rotation2d linearDirection = new Rotation2d(leftX, leftY);

// Apply deadband
linearMagnitude = MathUtil.applyDeadband(linearMagnitude, 0.1);

// Apply squaring
linearMagnitude = Math.copySign(linearMagnitude * linearMagnitude, linearMagnitude);

// Apply speed limits //TODO: Custom limits
linearMagnitude *= 1.0;

// Calcaulate new linear components
Translation2d linearVelocity =
new Pose2d(new Translation2d(), linearDirection)
.transformBy(GeomUtils.transformFromTranslation(linearMagnitude, 0))
.getTranslation();

// Calculate the target angle based on the current position of the robot and the speaker
Rotation2d targetAngle =
new Pose2d(
robotOrientation.get().getTranslation(),
AllianceFlipUtil.apply(targetPosition)
.minus(robotOrientation.get().getTranslation())
.getAngle()
.minus(Rotation2d.fromDegrees(180)))
.getRotation();
Logger.recordOutput("Drive/TargetAngle", targetAngle);
double angularVelocity =
rotationPid.calculate(
robotOrientation.get().getRotation().getRadians(), targetAngle.getRadians());
// Convert to meters per second
ChassisSpeeds speeds;
Logger.recordOutput("StolenJoystick/AngularVelocity", angularVelocity);

if (AllianceFlipUtil.shouldFlip()) {
Logger.recordOutput("Drive/FlipAlliance", true);
linearVelocity = linearVelocity.rotateBy(Rotation2d.fromRadians(Math.PI));
} else {
Logger.recordOutput("Drive/FlipAlliance", false);
}
speeds =
ChassisSpeeds.fromFieldRelativeSpeeds(
linearVelocity.getX() * DriveConstants.MAX_LINEAR_SPEED,
linearVelocity.getY() * DriveConstants.MAX_LINEAR_SPEED,
angularVelocity,
RobotOdometry.getInstance().getPoseEstimator().getEstimatedPosition().getRotation());

drive.runVelocity(speeds);
}

@Override
public void end(boolean interrupted) {
drive.stop();
}
}
10 changes: 10 additions & 0 deletions src/main/java/frc/robot/subsystems/arm/Arm.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import edu.wpi.first.wpilibj2.command.Commands;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.Constants;
import java.util.function.Supplier;
import org.littletonrobotics.junction.AutoLogOutput;
import org.littletonrobotics.junction.Logger;

Expand Down Expand Up @@ -111,6 +112,15 @@ public Command toSetpoint(Rotation2d setpointAngle) {
this);
}

public Command toSetpoint(Supplier<Rotation2d> setpointAngle) {
return Commands.run(
() -> {
feedback.setGoal(setpointAngle.get().getRadians());
feedbackMode = true;
},
this);
}

/**
* Runs the command with a specified percentage of voltage.
*
Expand Down

0 comments on commit 1758e2a

Please sign in to comment.