2025-01-04 16:09:10 -07:00
// 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 frc4388.robot.subsystems ;
2025-01-08 18:32:02 -07:00
import java.util.Optional ;
import com.ctre.phoenix6.Utils ;
2025-01-06 21:34:40 -07:00
import com.ctre.phoenix6.hardware.CANcoder ;
import com.ctre.phoenix6.hardware.TalonFX ;
import com.ctre.phoenix6.swerve.SwerveDrivetrain ;
import com.ctre.phoenix6.swerve.SwerveRequest ;
2025-01-08 18:32:02 -07:00
import edu.wpi.first.math.geometry.Pose2d ;
2025-01-04 16:09:10 -07:00
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.kinematics.SwerveModuleState ;
2025-01-05 11:25:37 -07:00
import edu.wpi.first.networktables.GenericEntry ;
import edu.wpi.first.wpilibj.shuffleboard.BuiltInLayouts ;
import edu.wpi.first.wpilibj.shuffleboard.BuiltInWidgets ;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard ;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardLayout ;
2025-01-08 18:32:02 -07:00
import edu.wpi.first.wpilibj.smartdashboard.Field2d ;
2025-01-04 16:09:10 -07:00
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard ;
// import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import frc4388.robot.Constants.SwerveDriveConstants ;
import frc4388.robot.Constants.SwerveDriveConstants.Conversions ;
2025-01-07 13:45:41 -07:00
2025-01-04 16:09:10 -07:00
import frc4388.utility.Status ;
import frc4388.utility.Subsystem ;
import frc4388.utility.Status.ReportLevel ;
public class SwerveDrive extends Subsystem {
2025-01-06 21:34:40 -07:00
private SwerveDrivetrain < TalonFX , TalonFX , CANcoder > swerveDriveTrain ;
2025-01-04 16:09:10 -07:00
2025-01-07 13:45:41 -07:00
private int gear_index = SwerveDriveConstants . STARTING_GEAR ;
2025-01-04 16:09:10 -07:00
private boolean stopped = false ;
2025-01-07 13:45:41 -07:00
public double speedAdjust = SwerveDriveConstants . MAX_SPEED_MEETERS_PER_SEC * SwerveDriveConstants . GEARS [ gear_index ] ;
2025-01-04 16:09:10 -07:00
public double rotSpeedAdjust = SwerveDriveConstants . MAX_ROT_SPEED ;
2025-01-07 13:45:41 -07:00
public double autoSpeedAdjust = SwerveDriveConstants . MAX_SPEED_MEETERS_PER_SEC * 0 . 25 ; // cap auto performance to 25%
2025-01-04 16:09:10 -07:00
public double rotTarget = 0 . 0 ;
public Rotation2d orientRotTarget = new Rotation2d ( ) ;
public ChassisSpeeds chassisSpeeds = new ChassisSpeeds ( ) ;
2025-01-08 18:32:02 -07:00
private Field2d field = new Field2d ( ) ;
2025-01-04 16:09:10 -07:00
/** Creates a new SwerveDrive. */
2025-01-06 21:34:40 -07:00
public SwerveDrive ( SwerveDrivetrain < TalonFX , TalonFX , CANcoder > swerveDriveTrain ) {
2025-01-04 16:09:10 -07:00
super ( ) ;
2025-01-08 18:32:02 -07:00
SmartDashboard . putData ( field ) ;
2025-01-06 21:34:40 -07:00
this . swerveDriveTrain = swerveDriveTrain ;
2025-01-04 16:09:10 -07:00
}
2025-01-07 13:45:41 -07:00
// public void oneModuleTest(SwerveModule module, Translation2d leftStick, Translation2d rightStick){
// // double ang = Math.atan2(rightStick.getY(), rightStick.getX());
// // rightStick.getAngle()
// double speed = Math.sqrt(Math.pow(leftStick.getX(), 2) + Math.pow(leftStick.getY(), 2));
// // System.out.println(ang);
// // module.go(ang);
// // Rotation2d rot = Rotation2d.fromRadians(ang);
// Rotation2d rot = new Rotation2d(rightStick.getX(), rightStick.getY());
// SwerveModuleState state = new SwerveModuleState(speed, rot);
// module.setDesiredState(state);
// }
2025-01-04 16:09:10 -07:00
public void driveWithInput ( Translation2d leftStick , Translation2d rightStick , boolean fieldRelative ) {
2025-01-07 08:38:21 -07:00
if ( rightStick . getNorm ( ) < 0 . 05 & & leftStick . getNorm ( ) < 0 . 05 & & stopped = = false ) // if no imput and the swerve drive is still going:
2025-01-07 13:45:41 -07:00
stopModules ( ) ; // stop the swerve
2025-01-07 08:38:21 -07:00
if ( rightStick . getNorm ( ) < 0 . 05 & & leftStick . getNorm ( ) < 0 . 05 ) //if no imput
return ; // don't bother doing swerve drive math and return early.
2025-01-08 18:32:02 -07:00
leftStick = leftStick . rotateBy ( Rotation2d . fromDegrees ( SwerveDriveConstants . FORWARD_OFFSET ) ) ;
2025-01-07 08:38:21 -07:00
2025-01-04 16:09:10 -07:00
if ( fieldRelative ) {
2025-01-06 21:34:40 -07:00
swerveDriveTrain . setControl ( new SwerveRequest . FieldCentric ( )
2025-01-08 18:32:02 -07:00
. withVelocityX ( leftStick . getX ( ) * - speedAdjust )
2025-01-06 21:34:40 -07:00
. withVelocityY ( leftStick . getY ( ) * speedAdjust )
2025-01-08 18:32:02 -07:00
. withRotationalRate ( rightStick . getX ( ) * rotSpeedAdjust )
2025-01-06 21:34:40 -07:00
) ;
// double rot = 0;
2025-01-04 16:09:10 -07:00
// ! drift correction
2025-01-06 21:34:40 -07:00
// dependant on if the new odomitry system acounts for rotational drift, this may not be needed.
// if (rightStick.getNorm() > 0.05) {
// rotTarget = swerveDriveTrain.getRotation3d().toRotation2d().getDegrees();
// swerveDriveTrain.setControl(new SwerveRequest.FieldCentric()
// .withVelocityX(leftStick.getX()*speedAdjust)
// .withVelocityY(leftStick.getY()*speedAdjust)
// .withRotationalRate(rightStick.getY()*rotSpeedAdjust)
// );
// // SmartDashboard.putBoolean("drift correction", false);
// stopped = false;
// } else if(leftStick.getNorm() > 0.05) {
// if (!stopped) {
// stopModules();
// stopped = true;
// }
// // SmartDashboard.putBoolean("drift correction", true);
2025-01-04 16:09:10 -07:00
2025-01-06 21:34:40 -07:00
// // rot = ((rotTarget - gyro.getAngle()) / 360) * SwerveDriveConstants.ROT_CORRECTION_SPEED;
2025-01-04 16:09:10 -07:00
2025-01-06 21:34:40 -07:00
// }
2025-01-04 16:09:10 -07:00
2025-01-06 21:34:40 -07:00
// // Use the left joystick to set speed. Apply a cubic curve and the set max speed.
// Translation2d speed = leftStick.times(leftStick.getNorm() * speedAdjust);
// // Translation2d cubedSpeed = new Translation2d(Math.pow(speed.getX(), 3.00), Math.pow(speed.getY(), 3.00));
2025-01-04 16:09:10 -07:00
2025-01-06 21:34:40 -07:00
// // Convert field-relative speeds to robot-relative speeds.
// // chassisSpeeds = chassisSpeeds.
// chassisSpeeds = ChassisSpeeds.fromFieldRelativeSpeeds(-1 * speed.getX(), -1 * speed.getY(), (-1 * rightStick.getX() * rotSpeedAdjust) - rot_correction, gyro.getRotation2d().times(-1));
2025-01-04 16:09:10 -07:00
} else { // Create robot-relative speeds.
2025-01-07 13:45:41 -07:00
swerveDriveTrain . setControl ( new SwerveRequest . RobotCentric ( )
2025-01-08 18:32:02 -07:00
. withVelocityX ( leftStick . getX ( ) * - speedAdjust )
2025-01-07 13:45:41 -07:00
. withVelocityY ( leftStick . getY ( ) * speedAdjust )
2025-01-08 18:32:02 -07:00
. withRotationalRate ( rightStick . getX ( ) * rotSpeedAdjust )
2025-01-07 13:45:41 -07:00
) ;
2025-01-04 16:09:10 -07:00
}
}
2025-01-07 13:45:41 -07:00
public void driveWithInputOrientation ( Translation2d leftStick , Translation2d rightStick ) { // there is no practical reason to have a robot relitive version of this, and no pre provided version
if ( rightStick . getNorm ( ) < 0 . 05 & & leftStick . getNorm ( ) < 0 . 05 & & stopped = = false ) // if no imput and the swerve drive is still going:
stopModules ( ) ; // stop the swerve
if ( rightStick . getNorm ( ) < 0 . 05 & & leftStick . getNorm ( ) < 0 . 05 ) //if no imput
return ; // don't bother doing swerve drive math and return early.
2025-01-04 16:09:10 -07:00
2025-01-07 13:45:41 -07:00
leftStick . rotateBy ( Rotation2d . fromDegrees ( SwerveDriveConstants . FORWARD_OFFSET ) ) ;
2025-01-04 16:09:10 -07:00
2025-01-07 13:45:41 -07:00
swerveDriveTrain . setControl ( new SwerveRequest . FieldCentricFacingAngle ( )
. withVelocityX ( leftStick . getX ( ) * speedAdjust )
. withVelocityY ( leftStick . getY ( ) * speedAdjust )
. withTargetDirection ( rightStick . getAngle ( ) )
) ;
2025-01-04 16:09:10 -07:00
}
public boolean rotateToTarget ( double angle ) {
2025-01-07 13:45:41 -07:00
swerveDriveTrain . setControl ( new SwerveRequest . FieldCentricFacingAngle ( )
. withVelocityX ( 0 )
. withVelocityY ( 0 )
. withTargetDirection ( Rotation2d . fromDegrees ( angle ) )
) ;
2025-01-04 16:09:10 -07:00
if ( Math . abs ( angle - getGyroAngle ( ) ) < 5 . 0 ) {
return true ;
}
return false ;
}
public double getGyroAngle ( ) {
2025-01-07 13:45:41 -07:00
return swerveDriveTrain . getRotation3d ( ) . getAngle ( ) ;
2025-01-04 16:09:10 -07:00
}
public void resetGyro ( ) {
2025-01-07 13:45:41 -07:00
swerveDriveTrain . tareEverything ( ) ;
2025-01-04 16:09:10 -07:00
}
public void stopModules ( ) {
2025-01-07 13:45:41 -07:00
swerveDriveTrain . setControl ( new SwerveRequest . SwerveDriveBrake ( ) ) ;
2025-01-04 16:09:10 -07:00
}
@Override
public void periodic ( ) {
// This method will be called once per scheduler run\
SmartDashboard . putNumber ( " Gyro " , getGyroAngle ( ) ) ;
SmartDashboard . putNumber ( " RotTartget " , rotTarget ) ;
2025-01-08 18:32:02 -07:00
Optional < Pose2d > e = swerveDriveTrain . samplePoseAt ( Utils . getCurrentTimeSeconds ( ) ) ;
if ( e . isPresent ( ) )
field . setRobotPose ( e . get ( ) ) ;
2025-01-04 16:09:10 -07:00
}
private void reset_index ( ) {
2025-01-07 13:45:41 -07:00
gear_index = SwerveDriveConstants . STARTING_GEAR ; // however we wish to initialize the gear (What gear does the robot start in?)
2025-01-04 16:09:10 -07:00
}
public void shiftDown ( ) {
if ( gear_index = = - 1 | | gear_index > = SwerveDriveConstants . GEARS . length ) reset_index ( ) ; // If outof bounds: reset index
int i = gear_index - 1 ;
if ( i = = - 1 ) i = 0 ;
setPercentOutput ( SwerveDriveConstants . GEARS [ i ] ) ;
gear_index = i ;
}
public void shiftUp ( ) {
if ( gear_index = = - 1 | | gear_index > = SwerveDriveConstants . GEARS . length ) reset_index ( ) ; // If outof bounds: reset index
int i = gear_index + 1 ;
if ( i = = SwerveDriveConstants . GEARS . length ) i = SwerveDriveConstants . GEARS . length - 1 ;
setPercentOutput ( SwerveDriveConstants . GEARS [ i ] ) ;
gear_index = i ;
}
public void setPercentOutput ( double speed ) {
speedAdjust = Conversions . JOYSTICK_TO_METERS_PER_SECOND_FAST * speed ;
gear_index = - 1 ;
}
public void setToSlow ( ) {
2025-01-07 13:45:41 -07:00
setPercentOutput ( SwerveDriveConstants . SLOW_SPEED ) ;
gear_index = 0 ;
2025-01-04 16:09:10 -07:00
}
public void setToFast ( ) {
2025-01-07 13:45:41 -07:00
setPercentOutput ( SwerveDriveConstants . FAST_SPEED ) ;
gear_index = 1 ;
2025-01-04 16:09:10 -07:00
}
public void setToTurbo ( ) {
2025-01-07 13:45:41 -07:00
setPercentOutput ( SwerveDriveConstants . TURBO_SPEED ) ;
gear_index = 2 ;
2025-01-04 16:09:10 -07:00
}
public void shiftUpRot ( ) {
rotSpeedAdjust = SwerveDriveConstants . ROTATION_SPEED ;
}
public void shiftDownRot ( ) {
rotSpeedAdjust = SwerveDriveConstants . MIN_ROT_SPEED ;
}
@Override
public String getSubsystemName ( ) {
return " Swerve Drive Controller " ;
}
2025-01-05 11:25:37 -07:00
ShuffleboardLayout subsystemLayout = Shuffleboard . getTab ( " Subsystems " )
. getLayout ( getSubsystemName ( ) , BuiltInLayouts . kList )
. withSize ( 2 , 2 ) ;
GenericEntry sbGyro = subsystemLayout
. add ( " Gyro angle " , 0 )
. withWidget ( BuiltInWidgets . kGyro )
. getEntry ( ) ;
2025-01-04 16:09:10 -07:00
2025-01-05 11:25:37 -07:00
GenericEntry sbShiftState = subsystemLayout
. add ( " Shift State " , 0 )
. withWidget ( BuiltInWidgets . kNumberBar )
. getEntry ( ) ;
2025-01-04 16:09:10 -07:00
2025-01-05 11:25:37 -07:00
@Override
public void queryStatus ( ) {
2025-01-07 13:45:41 -07:00
sbGyro . setDouble ( getGyroAngle ( ) ) ;
2025-01-05 11:25:37 -07:00
sbShiftState . setDouble ( this . speedAdjust ) ;
2025-01-04 16:09:10 -07:00
//TODO: Add more status things
}
@Override
public Status diagnosticStatus ( ) {
Status status = new Status ( ) ;
2025-01-07 13:45:41 -07:00
status . addReport ( ReportLevel . ERROR , " Don't know how to diganose new CTRE swerve systems. please check under the CAN(t) section for more detailed information about the swerves there. " ) ;
2025-01-04 16:09:10 -07:00
return status ;
}
}