Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback swerve cancoders #85

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@

public final class SwerveConfig {

public double wheelDiameterMeters, driveGearing, mu, autoCentripetalAccel, driveModifier;
public double wheelDiameterMeters, driveGearing, turnGearing, mu, autoCentripetalAccel, driveModifier;
public double[] kForwardVolts, kForwardVels, kForwardAccels, kBackwardVolts, kBackwardVels, kBackwardAccels,
drivekP, drivekI, drivekD, turnkP, turnkI, turnkD, turnkS, turnkV, turnkA, turnZeroDeg;
public boolean[] driveInversion, turnInversion, reversed;

public SwerveConfig(double wheelDiameterMeters, double driveGearing, double mu,
public SwerveConfig(double wheelDiameterMeters, double driveGearing, double turnGearing, double mu,
double autoCentripetalAccel, double[] kForwardVolts, double[] kForwardVels, double[] kForwardAccels,
double[] kBackwardVolts, double[] kBackwardVels, double[] kBackwardAccels, double[] drivekP,
double[] drivekI, double[] drivekD, double[] turnkP, double[] turnkI, double[] turnkD, double[] turnkS,
double[] turnkV, double[] turnkA, double[] turnZeroDeg, boolean[] driveInversion, boolean[] reversed, double driveModifier, boolean[] turnInversion) {
this.wheelDiameterMeters = wheelDiameterMeters;
this.driveGearing = driveGearing;
this.mu = mu;//coefficient of friction between the wheel and the surface
this.turnGearing = turnGearing;
this.mu = mu; //coefficient of friction between the wheel and the surface
this.autoCentripetalAccel = autoCentripetalAccel;
this.kForwardVolts = kForwardVolts;
this.kForwardVels = kForwardVels;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
* such as moving, getting encoder values, or configuring PID.
*/
public class SwerveModule implements Sendable {

/**
* If a CANCoder has not sent a packet in this amount of time, it is considered disconnected.
*/
public static final double CANCODER_TIMEOUT_MS = 200;

public enum ModuleType {FL, FR, BL, BR};

private SwerveConfig config;
Expand All @@ -53,7 +59,7 @@ public enum ModuleType {FL, FR, BL, BR};
private Timer timer;
private SimpleMotorFeedforward forwardSimpleMotorFF, backwardSimpleMotorFF, turnSimpleMotorFeedforward;
private double maxControllableAccerlationRps2;
private double desiredSpeed, lastAngle, maxAchievableTurnVelocityRps, maxAchievableTurnAccelerationRps2, drivetoleranceMPerS, turnToleranceRot, angleDiffRot;
private double desiredSpeed, lastAngle, maxAchievableTurnVelocityRps, maxAchievableTurnAccelerationRps2, drivetoleranceMPerS, turnToleranceRot, angleDiffRot, relativePositionCorrection;

private double turnSpeedCorrectionVolts, turnFFVolts, turnVolts;
private double maxTurnVelocityWithoutTippingRps;
Expand All @@ -73,7 +79,12 @@ public SwerveModule(SwerveConfig config, ModuleType type, CANSparkMax drive, CAN
drive.setInverted(config.driveInversion[arrIndex]);
drive.getEncoder().setPositionConversionFactor(positionConstant);
drive.getEncoder().setVelocityConversionFactor(positionConstant / 60);

positionConstant = 360 / config.turnGearing; // Convert rotations to degrees
turn.setInverted(config.turnInversion[arrIndex]);
turn.getEncoder().setPositionConversionFactor(positionConstant);
turn.getEncoder().setVelocityConversionFactor(positionConstant / 60);

maxControllableAccerlationRps2 = 0;
final double normalForceNewtons = 83.2 /* lbf */ * 4.4482 /* N/lbf */ / 4 /* numModules */;
double wheelTorqueLimitNewtonMeters = normalForceNewtons * config.mu * config.wheelDiameterMeters / 2;
Expand All @@ -95,7 +106,6 @@ public SwerveModule(SwerveConfig config, ModuleType type, CANSparkMax drive, CAN
drivePIDController = new PIDController(config.drivekP[arrIndex],
config.drivekI[arrIndex],
config.drivekD[arrIndex]);

/* offset for 1 CANcoder count */
drivetoleranceMPerS = (1.0 / (double)(drive.getEncoder().getCountsPerRevolution()) * positionConstant) / Units.millisecondsToSeconds(drive.getEncoder().getMeasurementPeriod() * drive.getEncoder().getAverageDepth());
drivePIDController.setTolerance(drivetoleranceMPerS);
Expand Down Expand Up @@ -196,6 +206,15 @@ public void drivePeriodic() {
}

public void turnPeriodic() {
// Use a member variable instead of setPosition to reduce CAN bus traffic
// If we call the CANCoder value c, the SparkMax value s, and the correction x,
// When we're using the CANCoder, we want the correction to work out so s - x = c
// The formula here gives x = s - c => s - x = s - (s - c) = c + s - s = c as desired
// When we're using the SparkMax, we want the correction to work out so there is no chage
// The formula here gives x = s - (s - x) = x + s - s = x as desired
double newRelativePositionCorrection = turn.getEncoder().getPosition() - getRawEncoderOrFallbackAngle();
if(!Double.isNaN(newRelativePositionCorrection)) relativePositionCorrection = newRelativePositionCorrection;

String moduleString = type.toString();
// Turn Control
{
Expand Down Expand Up @@ -303,7 +322,14 @@ private void setAngle(double angle) {
* @return module angle in degrees
*/
public double getModuleAngle() {
return MathUtil.inputModulus(Units.rotationsToDegrees(turnEncoder.getAbsolutePosition().getValue()) - turnZeroDeg, -180, 180);
return MathUtil.inputModulus(getRawEncoderOrFallbackAngle()-turnZeroDeg, -180, 180);
}

/**
* @return The current angle measured by the CANCoder (not zeroed) or, if the CANCoder is disconnected, an approximated angle from the turn motor encoder.
*/
public double getRawEncoderOrFallbackAngle() {
return cancoderConnected() ? Units.rotationsToDegrees(turnEncoder.getAbsolutePosition().getValue()) : turn.getEncoder().getPosition() - relativePositionCorrection;
}

/**
Expand Down Expand Up @@ -354,8 +380,12 @@ public void updateSmartDashboard() {
SmartDashboard.putNumber(moduleString + " Turn Goal Vel (dps)", turnPIDController.getGoal().velocity);
//SmartDashboard.putNumber("Gyro Pitch", pitchDegSupplier.get());
//SmartDashboard.putNumber("Gyro Roll", rollDegSupplier.get());
SmartDashboard.putNumber(moduleString + "Antigravitational Acceleration", calculateAntiGravitationalA(pitchDegSupplier.get(), rollDegSupplier.get()));
SmartDashboard.putNumber(moduleString + " Antigravitational Acceleration", calculateAntiGravitationalA(pitchDegSupplier.get(), rollDegSupplier.get()));
SmartDashboard.putBoolean(moduleString + " Turn is at Goal", turnPIDController.atGoal());
SmartDashboard.putBoolean(moduleString + " CANCoder Connected", cancoderConnected());
SmartDashboard.putNumber(moduleString + " Raw Encoder or Fallback Angle", getRawEncoderOrFallbackAngle());
SmartDashboard.putNumber(moduleString + " CANCoder Last Packet", (System.nanoTime() / 1e6d) - (turnEncoder.getLastTimestamp() * 1000));
SmartDashboard.putNumber(moduleString + " CANCoder Last Timestamp", turnEncoder.getLastTimestamp());

SmartDashboard.putNumber(moduleString + "Turn PID Output (Volts)", turnSpeedCorrectionVolts);
SmartDashboard.putNumber(moduleString + "Turn FF Output (Volts)", turnFFVolts);
Expand Down Expand Up @@ -429,6 +459,17 @@ public void setMaxTurnVelocity(double maxVel) {
turnPIDController.setConstraints(turnConstraints);
}

public boolean cancoderConnected() {
// The right thing to do here would be to have WPILib tell us this time, but that functionality
// is not exposed in the 2023 API.
// From what I can tell, WPILib bases CAN packet timestamps off of the system's monotonic clock
// On linux (and maybe other OSs), this is exposed through System.nanoTime()
// In WPILib 2024, this should be replaced with CAN.getCANPacketBaseTime() (see wpilibsuite/allwpilib#5357)
// That function should also return millis rather than nanos, eliminating the need
// for the below conversion.
return (System.nanoTime() / 1e6d) - (turnEncoder.getLastTimestamp() * 1000) < CANCODER_TIMEOUT_MS;
}

@Override
public void initSendable(SendableBuilder builder) {
builder.setActuator(true);
Expand All @@ -449,6 +490,7 @@ public void initSendable(SendableBuilder builder) {
builder.addDoubleProperty("Error (deg)", turnPIDController::getPositionError, null);
builder.addDoubleProperty("Desired Speed (mps)", drivePIDController::getSetpoint, null);
builder.addDoubleProperty("Angle Diff (deg)", () -> angleDiffRot, null);
builder.addBooleanProperty("CANCoder Connected", this::cancoderConnected, null);

builder.addDoubleProperty("Turn PID Output", () -> turnSpeedCorrectionVolts, null);
builder.addDoubleProperty("Turn FF Output", () -> turnFFVolts, null);
Expand Down
Loading