Skip to content

Commit

Permalink
Merge pull request #1 from FRC-4509-MechBulls/✨drivetrain✨
Browse files Browse the repository at this point in the history
basic drive and vision
  • Loading branch information
IsaacThoman authored Oct 4, 2023
2 parents f5fd1aa + 61d2c96 commit f4f5201
Show file tree
Hide file tree
Showing 5 changed files with 486 additions and 12 deletions.
87 changes: 87 additions & 0 deletions src/main/java/frc/robot/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package frc.robot;

import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.kinematics.SwerveDriveKinematics;
import edu.wpi.first.math.util.Units;

/**
* The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean
* constants. This class should not be used for any other purpose. All constants should be declared
Expand All @@ -15,5 +19,88 @@
public final class Constants {
public static class OperatorConstants {
public static final int kDriverControllerPort = 0;

public static final double driveExponent = 1.8;
public static final double driveMaxSpeed = 0.5; //5
public static final double turnExponent = 1.8;
public static final double turnMaxSpeed = 1; //11


public static final double radFeedClamp = 0.5; //max heading adjustment speed
}

public static final class DriveConstants{

/*Physical Characteristics*/
public static final double TRACK_WIDTH = Units.inchesToMeters(23.625); //need to find
// Distance between right and left wheels
public static final double WHEEL_BASE = Units.inchesToMeters(23.625); //need to find


// Distance between front and back wheels
public static final SwerveDriveKinematics kinematics = new SwerveDriveKinematics(
new Translation2d(WHEEL_BASE / 2, TRACK_WIDTH / 2),
new Translation2d(WHEEL_BASE / 2, -TRACK_WIDTH / 2),
new Translation2d(-WHEEL_BASE / 2, TRACK_WIDTH / 2),
new Translation2d(-WHEEL_BASE / 2, -TRACK_WIDTH / 2)
);


public static final double wheelDiameterMeters = Units.inchesToMeters(3.8);
public static final double wheelCircumferenceMeters = wheelDiameterMeters * Math.PI;
public static final double driveMotorGearRatio = 6.75;
public static final double turningGearRatio = 21.4286;
public static final double falconTicks = 2048;

public static final double radToFalcon = falconTicks / (2*Math.PI);

public static final double radPerSecondDeadband = 0.01;




/*Motor IDs and offsets */
public static final int frontLeftDriveID = 1;
public static final int frontLeftTurningID = 4;
public static final double frontLeftOffsetRad = 0.945;

public static final int frontRightDriveID = 6;
public static final int frontRightTurningID = 5;
public static final double frontRightOffsetRad = -5.1929;

public static final int rearRightDriveID = 3;
public static final int rearRightTurningID = 7;
public static final double rearRightOffsetRad = 2.361;

public static final int rearLeftDriveID = 8;
public static final int rearLeftTurningID = 2;
public static final double rearLeftOffsetRad = -2.296;





/*Drive Motor Constants */
public static final double driveMotorkP = 0.1;
public static final double driveMotorkI = 0.0;
public static final double driveMotorkD = 0.0;
public static final double driveMotorkF = 0.045;

public static final double driveNeutralDeadband = 0.01;



/*Turning Motor Constants */

public static final double turningMotorkP = 0.2;
public static final double turningMotorkI = 0.0;
public static final double turningMotorkD = 0.0;
public static final double turningMotorkF = 0.0;





}

}
27 changes: 15 additions & 12 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@

package frc.robot;

import edu.wpi.first.wpilibj.XboxController;
import edu.wpi.first.wpilibj2.command.RunCommand;
import frc.robot.Constants.OperatorConstants;
import frc.robot.commands.Autos;
import frc.robot.commands.ExampleCommand;
import frc.robot.subsystems.ExampleSubsystem;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
import edu.wpi.first.wpilibj2.command.button.Trigger;
import frc.robot.subsystems.drive.SwerveSubsystem;
import frc.robot.subsystems.drive.VisionSubsystem;

/**
* This class is where the bulk of the robot should be declared. Since Command-based is a
Expand All @@ -20,14 +24,19 @@
*/
public class RobotContainer {
// The robot's subsystems and commands are defined here...
private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem();

// Replace with CommandPS4Controller or CommandJoystick if needed
private final CommandXboxController m_driverController =
new CommandXboxController(OperatorConstants.kDriverControllerPort);
XboxController driver = new XboxController(0);

VisionSubsystem visionSub = new VisionSubsystem();
SwerveSubsystem swerveSubsystem = new SwerveSubsystem(visionSub);
RunCommand drive = new RunCommand(()->swerveSubsystem.joystickDrive(driver.getLeftX(),driver.getLeftY(),driver.getRightX()),swerveSubsystem);


/** The container for the robot. Contains subsystems, OI devices, and commands. */
public RobotContainer() {

swerveSubsystem.setDefaultCommand(drive);

// Configure the trigger bindings
configureBindings();
}
Expand All @@ -42,13 +51,7 @@ public RobotContainer() {
* joysticks}.
*/
private void configureBindings() {
// Schedule `ExampleCommand` when `exampleCondition` changes to `true`
new Trigger(m_exampleSubsystem::exampleCondition)
.onTrue(new ExampleCommand(m_exampleSubsystem));

// Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed,
// cancelling on release.
m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand());
// m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand());
}

/**
Expand All @@ -58,6 +61,6 @@ private void configureBindings() {
*/
public Command getAutonomousCommand() {
// An example command will be run in autonomous
return Autos.exampleAuto(m_exampleSubsystem);
return null;
}
}
171 changes: 171 additions & 0 deletions src/main/java/frc/robot/subsystems/drive/SwerveModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package frc.robot.subsystems.drive;

import com.ctre.phoenix.motorcontrol.*;
import com.ctre.phoenix.motorcontrol.can.WPI_TalonFX;
import com.ctre.phoenix.sensors.SensorInitializationStrategy;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.kinematics.SwerveModulePosition;
import edu.wpi.first.math.kinematics.SwerveModuleState;
import edu.wpi.first.wpilibj.DutyCycleEncoder;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.Constants;

import static frc.robot.Constants.DriveConstants.*;

public class SwerveModule extends SubsystemBase {

private WPI_TalonFX driveMotor;
private WPI_TalonFX turningMotor;
private DutyCycleEncoder absoluteEncoder;
private boolean absoluteEncoderReversed;
double absoluteEncoderOffset;


public SwerveModule(int driveMotorID, int turningMotorID, boolean driveMotorReversed, boolean turningMotorReversed, int absoluteEncoderID, double absoluteEncoderOffset){

/*Motor Creation */
driveMotor = new WPI_TalonFX(driveMotorID);
turningMotor = new WPI_TalonFX(turningMotorID);
absoluteEncoder = new DutyCycleEncoder(absoluteEncoderID);

driveMotor.configFactoryDefault();
turningMotor.configFactoryDefault();

/*Encoder Configs */
absoluteEncoder.setDistancePerRotation(1.0);
this.absoluteEncoderOffset = absoluteEncoderOffset;



/*Drive Motor Configs */
driveMotor.config_kP(0,driveMotorkP);
driveMotor.config_kI(0,driveMotorkI);
driveMotor.config_kD(0,driveMotorkD);
driveMotor.config_kF(0,driveMotorkF);

driveMotor.configVoltageCompSaturation(12.0);
driveMotor.enableVoltageCompensation(true);

driveMotor.configSelectedFeedbackSensor(FeedbackDevice.IntegratedSensor);
driveMotor.configIntegratedSensorInitializationStrategy(SensorInitializationStrategy.BootToZero);

StatorCurrentLimitConfiguration driveStatorConfig = new StatorCurrentLimitConfiguration(false,40,40,0);
SupplyCurrentLimitConfiguration driveSupplyConfig = new SupplyCurrentLimitConfiguration(true,45,55,50);

driveMotor.configStatorCurrentLimit(driveStatorConfig);
driveMotor.configSupplyCurrentLimit(driveSupplyConfig);

driveMotor.configNeutralDeadband(driveNeutralDeadband);

driveMotor.setNeutralMode(NeutralMode.Coast);
driveMotor.setInverted(driveMotorReversed);

/*Turning Motor Configs */
turningMotor.config_kP(0,turningMotorkP);
turningMotor.config_kI(0,turningMotorkI);
turningMotor.config_kD(0,turningMotorkD);
turningMotor.config_kF(0,turningMotorkF);

turningMotor.configVoltageCompSaturation(12.0);
turningMotor.enableVoltageCompensation(true);

turningMotor.configSelectedFeedbackSensor(FeedbackDevice.IntegratedSensor);
turningMotor.configIntegratedSensorInitializationStrategy(SensorInitializationStrategy.BootToZero);
turningMotor.setInverted(true);

StatorCurrentLimitConfiguration turningStatorConfig = new StatorCurrentLimitConfiguration(false,40,40,0);
SupplyCurrentLimitConfiguration turningSupplyConfig = new SupplyCurrentLimitConfiguration(true,20,30,50);

turningMotor.configStatorCurrentLimit(turningStatorConfig);
turningMotor.configSupplyCurrentLimit(turningSupplyConfig);

turningMotor.setNeutralMode(NeutralMode.Coast);
turningMotor.setInverted(turningMotorReversed);

new Thread(()->{
try{
// for(int i = 0; i<10; i++){
Thread.sleep(1000);
driveMotor.setSelectedSensorPosition(0);
turningMotor.setSelectedSensorPosition(radToTurning(getAbsoluteEncoderRad()));
//z }
} catch (InterruptedException e) {}
}).start();
}
double getAbsoluteEncoderRad(){
return absoluteEncoder.getAbsolutePosition()*2*Math.PI + absoluteEncoderOffset;
}

static double turningToRad(double turning){
turning/=falconTicks;
turning/=turningGearRatio;
turning*=2*Math.PI;
return turning;
}

static double radToTurning(double rad){
rad *= falconTicks;
rad *= turningGearRatio;
rad /= 2*Math.PI;
return rad;
}

public double getAngle(){
return turningToRad(turningMotor.getSelectedSensorPosition());
}

public void setState(SwerveModuleState state){

if(state.speedMetersPerSecond<0.01){
driveMotor.set(ControlMode.Velocity,0);
return;
}
state = SwerveModuleState.optimize(state,Rotation2d.fromRadians(getAngle())); //minimize change in heading

double delta = state.angle.getRadians() - getAngle(); //error
double deltaConverted = delta % Math.PI; //error converted to representative of the actual gap; error > pi indicates we aren't taking the shortest route to setpoint, but rather doing one or more 180* rotations.this is caused by the discontinuity of numbers(pi is the same location as -pi, yet -pi is less than pi)
double setAngle = Math.abs(deltaConverted) < (Math.PI / 2) ? getAngle() + deltaConverted : getAngle() - ((deltaConverted/Math.abs(deltaConverted)) * (Math.PI-Math.abs(deltaConverted))); //makes set angle +/- 1/2pi of our current position(capable of pointing all directions)


turningMotor.set(ControlMode.Position,radToTurning(setAngle));
driveMotor.set(ControlMode.Velocity, driveMetersPerSecondToFalcon(state.speedMetersPerSecond));
}

public double driveMetersPerSecondToFalcon(double metersPerSecond){ //untested
metersPerSecond *= 10; //convert from 1000ms to 100ms
metersPerSecond = driveMetersToFalcon(metersPerSecond);
return metersPerSecond;
}

public double driveMetersToFalcon(double meters){
meters /= wheelCircumferenceMeters; //meters to rotations
meters *= falconTicks; //rotations to sensor units
meters /= driveMotorGearRatio; //wheel rotations to motor rotations
return meters;
}

public double falconToDriveMeters(double falconTicksIn){
falconTicksIn *= wheelCircumferenceMeters;
falconTicksIn /= Constants.DriveConstants.falconTicks;
falconTicksIn /= driveMotorGearRatio;
return falconTicksIn;
}

public SwerveModulePosition getModulePosition(){
return new SwerveModulePosition(falconToDriveMeters(driveMotor.getSelectedSensorPosition()),new Rotation2d(getAngle()));
}

public SwerveModulePosition getPosition(){
// SmartDashboard.putNumber("sensorPosDrive",falconToDriveMeters(driveMotor.getSelectedSensorPosition()));
return new SwerveModulePosition(falconToDriveMeters(driveMotor.getSelectedSensorPosition()),new Rotation2d(getAngle()));
}



public void periodic(){


}

}
Loading

0 comments on commit f4f5201

Please sign in to comment.